【问题标题】:How do you implement a Makefile that remembers the last build target?你如何实现一个记住最后一个构建目标的 Makefile?
【发布时间】:2011-03-07 16:13:35
【问题描述】:

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

所以如果你输入 make all 你会得到

Building ...
...

然后如果你输入make debug,你会得到

make: Nothing to be done for `debug'.

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

【问题讨论】:

    标签: makefile target gnu-make


    【解决方案1】:

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

    编辑

    上面的草图。

    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
    

    (免责声明:未经测试,甚至未通过 make 运行。)

    给你。它甚至是-j 安全的,所以你可以做make -j5 all debug。有很多明显的样板都在哭着整理。

    【讨论】:

    • 非常简单。我可以想象这在大多数情况下都有效。如果可能的话,我仍然希望只构建一个目标。
    • @Elliot:在这种情况下,在构建debug 目标时,首先删除all 目标。仍然比在树中具有两个目标之一更不容易出错。你确定你足够优秀,能够始终知道树当前持有的目标吗?
    • 我发现最简单的方法是使用递归调用。例如。 debug: @$(MAKE) all TARGET_DIR="$(DEBUG_DIR)" FLAGS="-ggdb"
    • @Elliot:由于各种原因,我不喜欢递归 make。总是有其他机制(目标特定变量debug: TARGET_DIR := debugdir/;或间接TARGET-debug := debugdir/,然后在配方中使用${TARGET-$@}(我更喜欢后一种公式)。
    • @bobbogo:我在实现这些选项中的任何一个时都遇到了困难。我的调试目标只是debug : $(OUT_FILE),因为它依赖于一个依赖于一堆目标文件的可执行文件。为debug 设置特定于目标的变量似乎不起作用,而且我不确定如何对一大堆不同的目标进行间接处理。
    【解决方案2】:

    保留目标文件的变体集(如 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 将构建它和include。那会很聪明,但没有比这更干净的了。

    【讨论】:

    • 哇...优秀而聪明。我将不得不研究一些 Makefile 语法!
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2012-12-04
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 2016-06-20
      • 1970-01-01
      • 2012-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多