如何实现记住上一个构建目标的Makefile?

如何实现记住上一个构建目标的Makefile?,makefile,target,gnu-make,Makefile,Target,Gnu Make,假设您有一个带有两个伪目标的Makefile,“all”和“debug”。“debug”目标旨在构建与“all”相同的项目,除了使用一些不同的编译开关(例如-ggdb)之外。由于目标使用不同的编译开关,如果在两者之间切换,显然需要重新生成整个项目。但GNUmake并不自然地认识到这一点 因此,如果您键入makeall,您将得到 Building ... ... 然后,如果您键入makedebug,您将得到 make: Nothing to be done for `debug'. 因此,我的

假设您有一个带有两个伪目标的Makefile,“all”和“debug”。“debug”目标旨在构建与“all”相同的项目,除了使用一些不同的编译开关(例如-ggdb)之外。由于目标使用不同的编译开关,如果在两者之间切换,显然需要重新生成整个项目。但GNUmake并不自然地认识到这一点

因此,如果您键入
makeall
,您将得到

Building ...
...
然后,如果您键入
makedebug
,您将得到

make: Nothing to be done for `debug'.

因此,我的问题是:如何在Makefile中实现一个干净的解决方案,以注意到上一次构建使用的伪目标或编译开关与当前所需的不同?如果它们不同,Makefile将重建所有内容。

将构建产品放入不同的目录树中(当然要保留源代码的一个副本)。这样,无论是调试版本还是发布版本(甚至其他版本),您都只需从最新版本中进行一次短编译。也不可能出现混淆

编辑

上面的草图

src := 1.c 2.c 3.c
bare-objs := ${src:%.c=%.o}
release-objs := ${bare-objs:%=Release/%}
debug-objs := ${bare-objs:%=Debug/%}

Release/prog: ${release-objs}
Debug/prog: ${debug-objs}

${release-objs}: Release/%.o: %.c # You gotta lurve static pattern rules
    gcc -c $< -o $@

${debug-objs}: Debug/%.o: %.c
    gcc -c $< -o $@

Release/prog Debug/prog:
    gcc $^ -o $@

.PHONY: all
all: Release/prog ; echo $@ Success

.PHONY: debug
debug: Debug/prog ; echo $@ Success
src:=1.c2.c3.c
裸对象:=${src:%.c=%.o}
release objs:=${bare objs:%=release/%}
debug objs:=${bare objs:%=debug/%}
Release/prog:${Release objs}
Debug/prog:${Debug objs}
${release objs}:release/%.o:%.c#您必须使用静态模式规则
gcc-c$<-o$@
${debug objs}:debug/%.o:%.c
gcc-c$<-o$@
发布/程序调试/程序:
gcc$^-o$@
冒牌货:全部
全部:发布/prog;echo$@Success
.假的:调试
调试:调试/prog;echo$@Success
(免责声明:未经测试,甚至未运行过make。)


好了。它甚至是
-j
安全的,所以你可以
让-j5全部调试
。有很多明显的锅炉板需要清理。

唯一干净的解决方案是将差异合并到目标名称中。
例如,您可以定义一个变量
$(DEBUG)
,并在依赖于编译步骤的所有目标中一致地使用它。

保留对象文件的变量集(如bobbogo的解决方案)可能是最好的方法,但如果出于某种原因您不想这样做,可以使用空文件作为标记,以指示上次构建可执行文件的方式:

%-marker:
        @rm -f $(OBJECTS) *-marker
        @touch $@

debug: GCCFLAGS += -ggdb

debug: SOMEOTHERFLAG = WHATEVER

all debug: % : %-marker
        @echo making $@
        @$(MAKE) -S GCCFLAGS='$(GCCFLAGS)' SOMEOTHERFLAG='$(SOMEOTHERFLAG)' main

这个想法还有其他变体;您可以有一个包含标志设置的小文件,makefile将构建并包含标志设置。。这会很聪明,但不会比这更干净。

非常简单。我可以想象这在大多数情况下都有效。如果可能的话,我仍然希望只构建一个目标。@Elliot:在这种情况下,在构建
debug
目标时,首先删除
all
目标。与树中有两个目标中的一个相比,更不容易出错。你确定自己足够好,可以随时知道树中当前包含的目标吗?我发现最简单的方法是使用递归make调用。例如
debug:@$(MAKE)all TARGET_DIR=“$(DEBUG_DIR)”FLAGS=“-ggdb”
@Elliot:出于各种原因,我不喜欢递归MAKE。总有其他机制(特定于目标的变量
DEBUG:TARGET_DIR:=debugdir/
;或间接
目标调试:=debugdir/
,然后在配方中使用
${TARGET-$}
@bobbogo:我很难实现这两个选项中的任何一个。我的调试目标只是
debug:$(OUT_文件)
因为它依赖于一个依赖于一堆对象文件的可执行文件。为
调试设置特定于目标的变量似乎不起作用,而且我不知道如何在一堆不同的目标上进行间接寻址。哇……太棒了,太聪明了。我必须研究一下Makefile语法!