发布和调试目标的Makefile

3

我想创建一个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目标。但是我不确定如何在构建debug时处理配方中的依赖项module_1/$(MODULE_1_BIN).binmodule_2/$(MODULE_2_BIN).bin

2个回答

1
这个答案的早期版本试图使用目标特定变量,但它们的用途有限,因为它们在配方中使用时很有用,但在指定目标和前提条件时被忽略。
隐式规则使用模式,但是使用隐式目标my_binary%无法捕获my_binary和my_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,如@echo Building $@ : $<,当我运行make debug时,我看到Building debug : bin/my_binary.bin - rookie
哦,你说得对。_目标特定变量仅在目标的配方上下文中有效_,而不在目标和先决条件中...我将想出另一个解决方案... - Dario
达里奥:那是我之前发布的一个问题的转载,马克在提到它。@马克:今后会更加努力的。谢谢! - rookie
@Dario:感谢您抽出时间来帮助我解决这个问题。 - rookie
@Dario 抱歉...我应该把这个发表为一个评论来回答问题。 - Mark Galeck

1
正如我之前所说,你不能在该目标的先决条件中使用特定于目标的变量,只能在该目标的配方和递归先决条件中使用。根据你的需求,我认为你能做到最好的是这样:
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))))

1
@rookie 或者,就像Dario发布的那样,使用隐式规则 - 这比我使用eval的方法更容易理解。 - Mark Galeck
# 只是一个注释。我喜欢在有意义的空格或缺少空格之后添加注释。这只是我的习惯。好吧,像 FOO:=bar # 这样的东西更明显了,现在 FOO 末尾有空格,如果没有注释,很难看到。 - Mark Galeck
好的,我明白了。无论如何都是个不错的技巧。我理解你使用注释分隔符来确保变量为空的观点。 - Dario
@Dario 否则,理论上来说,该值可能是一些空格,而您不会看到差异。实际上,我之所以不得不添加一个间接级别,是因为他想要一个空后缀,并且没有办法使用foreach遍历空值 - 如果其中一个变量具有空值,则必须转到变量名称。 - Mark Galeck
@Mark,感谢你的回答,这是一个有趣的方法! - rookie
@新手 对此没有什么有趣的东西...这是标准的,我不太喜欢隐式规则,它们很简单没问题,但在许多情况下,我更喜欢使用eval - Mark Galeck

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