如何强制makefile重新构建目标?

我有一个生成文件,然后调用另一个生成文件。因为这个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
252436 次浏览

你可以声明一个或多个目标为假的

一个虚假的目标是一个不是真正的文件名;相反,它 只是一个名称的配方执行时,你做显式 请求。使用假目标有两个原因:避免 与同名文件冲突,提高性能。

...

假目标不应该是一个真正的目标文件的先决条件;如果 是的,它的recipe会在每次make去更新时运行 文件。只要目标是假的,就绝不是真目标的先决条件 目标,虚假的目标配方将只执行时,虚假 Target是一个指定的目标

如果我没记错的话,'make'使用时间戳(文件修改时间)来确定目标是否为最新。强制重新构建的常用方法是使用“touch”命令更新时间戳。您可以尝试在makefile中调用'touch'来更新其中一个目标(可能是那些子makefile中的一个)的时间戳,这可能会迫使Make执行该命令。

还有人建议使用. phony,这是绝对正确的。. phony应该用于任何输入和输出之间的日期比较无效的规则。由于你没有任何output: input形式的目标,你应该对所有目标都使用.PHONY !

尽管如此,您可能应该在makefile的顶部为各种文件名定义一些变量,并定义真正的make规则,这些规则同时具有输入和输出部分,这样您就可以利用make的好处,即您只编译需要复制的东西!

编辑:新增示例。未经测试,但你就是这么做的。假的

.PHONY: clean
clean:
$(clean)

make的-B开关,其长形式为--always-make,告诉make忽略时间戳并使指定的目标。这可能会违背使用make的目的,但它可能正是您所需要的。

曾经在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认为release是最新的。这可能是因为你在执行的命令中有touch release命令;这可能是因为存在一个名为“release”的文件或目录,它没有依赖关系,所以是最新的。还有真正的原因…

这实际上取决于目标是什么。如果它是一个伪目标(即目标与文件无关),你应该将它声明为. phony。

然而,如果目标不是伪目标,而只是出于某种原因想要重新构建它(例如当你使用__TIME__预处理宏时),你应该使用回答中描述的FORCE方案。

根据Miller的递归使被认为有害,你应该避免调用$(MAKE)!在您所展示的情况中,它是无害的,因为这不是一个真正的makefile,只是一个包装器脚本,它也可能是用Shell编写的。但是你说你在更深层次的递归中继续这样做,所以你可能遇到了那篇令人大开眼界的文章中所显示的问题。

当然,使用GNU的make是很麻烦的。尽管他们意识到了这个问题,但这是他们记录在案的做事方式。

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

但是遗留makefile是递归编写的。因此,有一个变通办法,$(MAKE)什么也不做,只是将子请求引导回主makepp进程。只有当你在你的子make之间做了冗余的或者更糟的,矛盾的事情时,你必须请求--traditional-recursive-make(这当然破坏了makepp的这个优势)。我不知道你的其他makefile文件,但如果它们写得很干净,使用makepp进行必要的重建应该会自动发生,而不需要其他人在这里建议的任何hack。

在我的Linux系统(Centos 6.2)上,当规则实际上创建了一个匹配目标的文件时,在声明目标. phony和在FORCE上创建一个虚假依赖项之间有一个显著的区别。当每次都必须重新生成文件时,两者都需要 假依赖文件,和.PHONY假依赖。< / p >

错误的:

date > $@

正确的:

FORCE
date > $@
FORCE:
.PHONY: FORCE

这种简单的技术将允许makefile在不需要强制时正常运行。在你的makefile后面创建一个名为的新目标。目标将触及默认目标所依赖的文件。在下面的例子中,我添加了触摸myprogram.cpp。我还添加了对使的递归调用。这将导致每次键入使力时生成默认目标。

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


force:
touch yourProgram.cpp
make

它已经被提到,但我认为我可以添加到使用touch

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

源文件时间戳是make用来“知道”文件已经更改,并且需要重新编译的

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

我试过了,对我很有效

将这些行添加到Makefile中

clean:
rm *.o output


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

保存,然后调用

make new

它会重新编译所有东西

发生了什么事?

< p > 1)“新”就是干净。 'clean' do 'rm'删除所有扩展名为'.o'的目标文件 < p > 2)'new'调用'make'。 'make'看到没有'。O '文件,因此它创建了所有的'。o '了。然后链接器链接所有的。o文件int一个可执行输出

祝你好运

如果您不需要保存已经成功编译的任何输出

nmake /A

重建所有

make clean删除所有已编译的目标文件。

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

clean: FORCE
rm $(objects)
FORCE: ;

这将干净地运行,而不考虑任何其他依赖项。

我在手册中的解决方案中添加了分号,否则需要空行。