【问题标题】:Makefile for release and debug targets用于发布和调试目标的 Makefile
【发布时间】:2018-03-18 09:57:42
【问题描述】:

我正在尝试构建一个 Makefile,它可以通过指定一个目标而不是一个变量来构建发布和调试目标(例如 make debug=1,不是很好)我在这里有一个浓缩的简化示例来模拟我正在尝试的内容实现:

ifdef debug
    BINARY=my_binary_debug
    MODULE_1_BIN=abc_debug
    MODULE_2_BIN=xyz_debug
    export DBG=1
else
    BINARY=my_binary
    MODULE_1_BIN=abc
    MODULE_2_BIN=xyz
endif

FLAG=something

.PHONY: all debug clean

all: bin/$(BINARY).bin

bin/$(BINARY).bin: module_1/$(MODULE_1_BIN).bin module_2/$(MODULE_2_BIN).bin
    cat module_1/$(MODULE_1_BIN).bin $(FLAG) module_2/$(MODULE_2_BIN).bin > $@

module_1/$(MODULE_1_BIN).bin:
    $(MAKE) -C module_1

module_2/$(MODULE_2_BIN).bin:
    $(MAKE) -C module_2


clean:
    rm bin/*.bin
    $(MAKE) -C module_1 clean
    $(MAKE) -C module_2 clean

这个例子会让我使用make debug=1,但我不太喜欢它,我觉得这个实现可能会更好。一种方法是使用目标特定变量,但我不完全确定在构建调试目标时依赖项还需要更改其名称时如何使用它们。比如:

debug: export DBG:=1
debug: bin/$(BINARY)_debug.bin
debug: module_1/$(MODULE_1_BIN)_debug.bin
debug: module_2/$(MODULE_2_BIN)_debug.bin

bin/$(BINARY).bin bin/$(BINARY)_debug.bin: module_1/$(MODULE_1_BIN).bin module_2/$(MODULE_2_BIN).bin
        cat module_1/$(MODULE_1_BIN).bin module_2/$(MODULE_2_BIN).bin > $@

这里的目标可以正常工作,因为在构建debug 时不需要构建bin/$(BINARY).bin 目标。但我不确定如何在构建时处理配方中的依赖关系module_1/$(MODULE_1_BIN).binmodule_2/$(MODULE_2_BIN).bin debug

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    此答案的先前版本尝试使用特定于目标的变量,但它们的用途有限,因为它们用于配方中,但在指定目标和先决条件时被忽略。

    隐式规则使用模式,但是使用隐式目标my_binary% 捕获my_binarymy_binary_debug 不起作用,因为模式与空字符串不匹配。

    但是,在这种情况下,隐式规则起作用,因为您的所有目标和依赖项都有共同的结尾 .bin,它是非空的。匹配% 的字符串在自动变量$* 中可用。 所以这是我的解决方案:

    .PHONY: all debug clean
    
    FLAG=something 
    
    # Maybe still needed by subdirectory makefiles
    debug: export DBG:=1
    
    all: bin/my_binary.bin
    debug: bin/my_binary_debug.bin
    
    # % will match both ".bin" and "_debug.bin"
    # It won’t match the empty string.
    bin/my_binary%: module_1/abc% module_2/xyz%
        cat module_1/abc$* $(FLAG) module_2/xyz$* > $@
    
    # Maybe, by specifying the target in the sub-make commandline,
    # you can get rid of the DBG variable altogether.
    module_1/abc%:
        $(MAKE) -C module_1 $@
    
    module_2/xyz%:
        $(MAKE) -C module_2 $@
    
    clean:
        rm bin/*.bin
        $(MAKE) -C module_1 clean
        $(MAKE) -C module_2 clean
    

    如果构建bin/my_binary.bin的配方可以一个接一个地重写所有模块并在开始时使用$(FLAG),则可以进行更多的简化:

    .PHONY: all debug clean
    
    MODULES = module_1/abc module_2/xyz
    FLAG    = something 
    
    # Maybe still needed by subdirectory makefiles
    debug: export DBG:=1
    
    all: bin/my_binary.bin
    debug: bin/my_binary_debug.bin
    
    bin/my_binary%: $(addsuffix %,$(MODULES))
        cat $(FLAG) $^ > $@
    
    module_1/abc%:
        $(MAKE) -C module_1 $@
    
    module_2/xyz%:
        $(MAKE) -C module_2 $@
    
    clean:
        rm bin/*.bin
        for m in $(MODULES); do $(MAKE) -C $$(dirname $$m) clean; done
    

    【讨论】:

    • 看起来很干净!但是当我运行make debug 时,BINARY 似乎没有采用 my_binary_debug 的值。我在各自的 Makefile 中使用简单的ifdef 来更改基于 DBG 的子二进制文件的值,因此这两个人更改了它们的值。我在all debug 目标下添加了一个简单的回声,例如@echo Building $@ : $<,当我运行make debug 时我看到Building debug : bin/my_binary.bin
    • 天哪,你是对的。 特定于目标的变量仅在目标配方的上下文中可用,而在目标和先决条件中不可用...我将制定另一个解决方案...
    • 达里奥:这是我之前发布的马克所指的问题的翻转。 @Mark:今后会做出更好的努力。谢谢!
    • @Dario:感谢您抽出宝贵时间来帮助我
    • @Dario 对不起...我应该作为评论发布问题
    【解决方案2】:

    正如我之前所说,您不能在该目标的先决条件中使用特定于目标的变量,只能在该目标的配方和递归先决条件中使用。我认为你能做的最好的,根据你想要的,是这样的:

    RELEASE_SUFFIX:=#
    DEBUG_SUFFIX:=_debug
    
    BINARY:=my_binary
    MODULE_1_BIN:=abc
    MODULE_2_BIN:=xyz
    
    FLAG=-u
    
    .PHONY: all debug
    
    all: bin/$(BINARY).bin
    
    debug: export DBG:=1
    debug: BINARY+=$(DEBUG_SUFFIX)
    debug: bin/$(BINARY).bin
    
    
    define rules
    
    bin/$(BINARY)$($(1)): module_1/$(MODULE_1_BIN)$($(1)).bin module_2/$(MODULE_2_BIN)$($(1)).bin
        cat $(FLAG) $$^ > $$@
    
    module_1/$(MODULE_1_BIN)$($(1)).bin:
        $(MAKE) -C $$(@D)
    
    module_2/$(MODULE_2_BIN)$($(1)).bin:
        $(MAKE) -C $$(@D)
    
    endef
    
    
    $(foreach suffix, RELEASE_SUFFIX DEBUG_SUFFIX, $(eval $(call rules,$(suffix))))
    

    【讨论】:

    • @rookie 或者,正如 Dario 所发布的,使用隐式规则 - 这比我使用 eval 的方法更容易理解。
    • # 只是一个评论。我喜欢把 cmets 放在有意义的空白之后,或者没有空白。这只是我的习惯。好的,在FOO:=bar # 之类的内容中更明显,现在FOO 末尾有空白空间,如果没有评论,很难看到。
    • 好的,我明白了。还是不错的把戏。我明白您使用注释分隔符来确保变量为空的观点。
    • @Dario 否则,理论上,该值可能是一些空格,您不会看到差异。实际上,我必须添加一个间接级别的全部原因是因为他想要空后缀,并且没有办法用 foreach 迭代空值 - 如果其中一个你必须深入到变量名它们有一个空值。
    • @Mark 感谢您的回答,这是一个有趣的方法!
    猜你喜欢
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多