如何使一个makefile依赖于构建选项

3
很久以前,我记得使用过一些Solaris make工具,它们有一个巧妙的选项,可以自动检测编译器选项是否已更改,并相应地重新构建所有规则。例如,假设我从以下选项切换:

g++ -O3

g++ -g

那么所有文件都应该重新编译。我正在使用GNU make,并没有发现类似这样的功能,想知道是否有人有办法使其工作。


类似问题:https://dev59.com/M3A75IYBdhLWcg3wi5sr - slowdog
3个回答

4
使用gmake实现这一点的简单方法是将gcc选项写入文件。然后,在Makefile中将这些选项读取到一个变量中,在gcc命令行中使用此变量,再将所有对象文件的依赖关系添加到此选项文件中(可以在模式规则中完成)。

或者更好的方法是使用该文件的内容来设置 CFLAGS 变量(或者对于 C++ 来说是 CXXFLAGS)。 - Bart van Ingen Schenau
设置CFLAGS变量的问题在于你会覆盖同名的shell环境变量。 - Didier Trosset
1
这个解决方案简单而优雅。我不理解CFLAGS的注释。然而,仅仅写出文件是不够的,你需要比较新参数是否不同,只有在改变时才写出文件。否则,文件总是会改变,规则总是会触发。在make中如何比较文件内容和变量,并且如果不同,就写入文件呢?类似于:COMPILE:=g++ $(DEBUG) $(OPT) LASTCOMPILE:=cat <.compile.txt <br>if $(COMPILE) != $(LASTCOMPILE) <br> echo $(COMPILE) >.compile.txt 这样行吗? - Dov
@Didier:我的UNIX有点生疏,但是如果你不导出CFLAGS,它不会改变整个shell的设置,只会影响当前脚本的执行,对吗? - Bruno Brant
1
这里有一个这样解决的例子:https://dev59.com/M3A75IYBdhLWcg3wi5sr#3237349 - slowdog
@Bruno:你说得对。我的意思是,如果你想使用CFLAGS变量将一些选项从命令行设置到Makefile中,那么你不能这样做,因为Makefile会覆盖它。 - Didier Trosset

1
这是一种基本的方法来实现这个(尽管我相信这是一个可怕的想法,见下文):
-include CFLAGS.save

CFLAGS := -O2 -g

all: foo

CFLAGS.save:
    echo 'CFLAGS_SAVE := $(CFLAGS)' > $@
ifeq ($(CFLAGS),$(CFLAGS_SAVE))
%.o: %.c CFLAGS.save
    gcc $(CFLAGS_SAVE) -c -o $@ $<
else
.PHONY: CFLAGS.save
%.o: %.c CFLAGS.save
    $(MAKE) $@
endif

foo: foo.o
    gcc -o $@ $^

这是发生的事情:在进行任何编译之前,当前的CFLAGS被写入CFLAGS.save。如果CFLAGS不等于CFLAGS_SAVE,那么用户必须已经更改了它们。如果是这样,我们声明CFLAGS.save为虚假的,以便make将重新构建它。还要注意,如果CFLAGS已更改,我们将更新它,但仍将在内存中保留旧值。因此,我们必须递归地调用make来处理每个源文件。对于大型项目来说,这并不好。
另一个问题是,如果您忽略在命令行上指定CFLAGS,它将返回并使用默认值重新构建所有内容。您可以通过测试CFLAGS$(origin)来解决此问题,但是,说实话,不行。我的职业道德不允许我容忍这种情况。

make的目的是要简单。发行商已经足够困扰于理解打包工具的滥用(可悲的是,大部分对automake的指责都是因为这个原因)。请拒绝使用克苏鲁式的构建系统。

此外,make clean all CFLAGS='-Whatever -foo'同样有效。


1
谢谢你提出“Cthulhoid build systems”这个词组,我很喜欢它 :-) 这是你解决方案的一个变体,避免了递归调用make:https://dev59.com/questions/M3A75IYBdhLWcg3wi5sr#3237349 - slowdog

0

只需让您的目标依赖于Makefile本身:

all: a.out

a.out: boo.c Makefile
        cc -O3 -g boo.c

这非常粗暴。更改makefile中的任何内容,即使是一个空格,都会重新编译所有内容。这并不是很好。 - Dov
嗯,当你改变你的 makefiles 时,你不重新编译吗?那你为什么要改变它们呢? - Nikolai Fetissov
添加单个源文件应该只会触发该文件的编译和链接到某个库或二进制文件中。它不必重建 所有 的内容才能正确。 - Jack Kelly
1
是的 - 那就是我在答案中给出的link行(不介意它也是编译行 :) - Nikolai Fetissov
问题在于,如果我在规则中使用$^,那么Makefile现在也会被包含在内。 - user663031

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接