如何强制makefile重建目标


182

我有一个生成的生成文件,然后调用另一个生成文件。由于此makefile调用了更多的makefile来完成工作,因此它实际上并没有改变。因此,它一直认为该项目已建成并且是最新的。

dnetdev11 ~ # make
make: `release' is up to date.

如何强制Makefile重建目标?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

注意:删除名称以保护无辜者

编辑:最终固定版本:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib

Lodle,由于这是一个经常访问的问题,您是否想将其编辑为更现代的问题?(看来这.PHONY不是您的唯一问题,并且您真的不应该将解决方案编辑到问题中,或者至少不再是。)
Keith M

Answers:


22

您可以将一个或多个目标声明为虚假

虚假目标实际上不是文件名。相反,它只是您明确请求时要执行的配方的名称。使用伪造目标的原因有两个:避免与同名文件冲突,并提高性能。

...

虚假目标不应成为真实目标文件的前提;如果是这样,则每次make更新该文件时都会运行其配方。只要伪造目标永远不是真实目标的先决条件,那么只有当伪造目标是指定目标时,才会执行伪造目标配方


68
这个答案虽然被“接受”并且被高度“赞成”,但实际上是不合时宜的。首先,它说“声明目标是假的”,然后说“假目标不是文件的名称”。好吧,如果您的目标是文件,那么答案就是矛盾的。其次,它说“假冒的目标不应该成为真实的先决条件”-好吧,如果有的话?原始问题未指定是不是。正确的答案是,申报你的目标是假的,而是宣告一个额外的假目标,然后,取决于你想要重建的目标,这一点。
Mark Galeck 2014年

2
@MarkGaleck。当答案指出“伪造的目标不是真正的文件名”时,它直接引用了gcc make手册。这是完全正确的。
drlolly

“目标”是一个Make术语,指的是冒号左侧的文本 :,而不仅仅是您要创建的最终结果(例如,二进制文件)。在的问题,releasedebugclean,和install是制作的目标,而不是xxx_utilxxxcore.so或其他任何东西。
Keith M

727

-B要进行的切换(其长格式为--always-make)告诉make您忽略时间戳并确定指定的目标。这可能会破坏使用make的目的,但可能正是您所需要的。


4
@MarkKCowan我完全同意!这个选项正是我在寻找的东西,而不是Dave建议的解决方法。
Maarten Bamelis,2015年

8
这种方法的警告是,它只会构建很多东西。特别是使用自动工具,我看到它正在重新运行configure ..我希望可以构建基于LD_PRELOAD的解决方案!
vrdhn

是的,它甚至可以重写您不想要的文件!例如出现在依赖项中并被重建和覆盖的全局系统库...
Julio Guerra

18

Sun手册中曾经记录的一个技巧make是使用(不存在)目标'.FORCE'。您可以通过创建一个文件force.mk来完成此任务,该文件包含:

.FORCE:
$(FORCE_DEPS): .FORCE

然后,假设您现有的makefile名为makefile,则可以运行:

make FORCE_DEPS=release -f force.mk -f makefile release

由于.FORCE不存在,因此任何依赖它的东西都会过时并重建。

所有这些都适用于任何版本的make; 在Linux上,您拥有GNU Make,因此可以使用.PHONY目标进行讨论。

还值得考虑为什么要make考虑发布是最新的。这可能是因为您touch release在执行的命令中有一个命令。可能是因为存在一个名为“ release”的文件或目录,并且没有依赖性,因此是最新的。那是真正的原因...


14

有人建议.PHONY绝对正确。.PHONY应该用于输入和输出之间的日期比较无效的任何规则。由于您没有表单的任何目标output: input应对都使用.PHONY!

综上所述,您可能应该在makefile的顶部为各种文件名定义一些变量,并定义同时具有输入和输出部分的真实make规则,以便您可以使用make的好处,即只能实际编译康普米尔必要的东西!

编辑:添加示例。未经测试,但这是您的工作方式。

.PHONY: clean    
clean:
    $(clean)

1
好吧,如果您能给我看一个例子,那就太好了。Atm im只是破解它,试图使大坝工作正常:P
Lodle

1
.PHONY目标的位置无关紧要。它可以在中的任何位置Makefile
阿德里安W

5

如果我没记错的话,“ make”使用时间戳(文件修改时间)来确定目标是否最新。强制重建的一种常见方法是使用“ touch”命令更新该时间戳。您可以尝试在生成文件中调用“触摸”以更新目标之一(也许是这些子生成文件之一)的时间戳,这可能会强制Make执行该命令。


5

这种简单的技术将使makefile在不需要强制时可以正常运行。在makefile的末尾创建一个名为force的新目标。该部队的目标将涉及一个程序文件的默认目标取决于。在下面的示例中,我添加了touch myprogram.cpp。我还添加了一个递归调用make。每次您键入make force时,都会导致默认目标被建立。

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make

3

我尝试了这个,对我有用

将这些行添加到Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

保存并立即致电

make new 

它将再次重新编译所有内容

发生了什么?

1)“新”电话干净。'clean'执行'rm',删除所有扩展名为'.o'的目标文件。

2)“新”称为“制造”。'make'看到没有'.o'文件,因此它再次创建了所有'.o'文件。然后链接程序将所有.o文件链接为一个可执行输出

祝好运


1
在食谱中要比new$(MAKE)make
-Basile Starynkevitch

1

根据米勒的递归使有害,您应该避免致电$(MAKE)!在您所展示的情况下,它是无害的,因为这实际上不是makefile,只是包装脚本,也可能是用Shell编写的。但是您说您会在更深层次的递归级别上继续这样做,因此您可能遇到了令人大开眼界的文章中显示的问题。

当然,使用GNU可以避免这种麻烦。即使他们意识到了这个问题,这也是他们记录在案的做事方式。

OTOH,makepp是为解决此问题而创建的。您可以在每个目录级别上编写您的makefile,但它们都被汇总到项目的完整视图中。

但是,遗留的makefile是递归编写的。因此,有一种解决方法,$(MAKE)除了将子请求引导回主makepp流程外,什么也没有做。仅当您在子make之间进行多余的或更糟糕的是矛盾的操作时,才必须请求--traditional-recursive-make(这当然会破坏makepp的这种优势)。我不知道您的其他makefile,但是如果它们是干净编写的,则使用makepp可以自动进行必要的重建,而无需其他人提出的任何建议。


没有回答问题:与要点相切,应该是评论而不是答案。
flungo

也许我还不够清楚。使用makepp时,不需要整个包装器makefile。通过了解确切的依赖关系(所有依赖关系,而不仅仅是后面列出的内容:),它将始终在必要时进行重建。
丹尼尔(Daniel)


0

它实际上取决于目标是什么。如果它是假目标(即目标与文件无关),则应将其声明为.PHONY。

但是,如果目标不是伪造目标,但由于某种原因您只想重建它(例如,当您使用__TIME__预处理宏时),则应使用此处答案中所述的FORCE方案。



0

已经提到过,但是我想我可以添加到 touch

如果您touch要编译所有源文件,该touch命令会将文件的时间戳更改touch为执行该命令的系统时间。

源文件timstamp是什么 make用于“知道”文件已更改,需要重新编译

例如:如果该项目是c ++项目,则执行do touch *.cpp,然后make再次运行,并且make应该重新编译整个项目。



0

正如abernier所指出的,GNU make手册中有一个推荐的解决方案,它使用“伪造”目标来强制重建目标:

clean: FORCE
        rm $(objects)
FORCE: ; 

不管其他依赖项如何,它都将运行干净。

我将分号从手册中添加到解决方案中,否则需要空行。


-1

在我的Linux系统(Centos 6.2)上,当规则确实创建与目标匹配的文件时,声明目标.PHONY与在FORCE上创建伪造的依赖项之间存在显着差异。当必须每次重新生成文件时,它都需要文件上的伪依赖项FORCE和伪造依赖项都要求.PHONY。

错误:

date > $@

对:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.