问题
I am trying to build a Makefile that can build both release and debug targets by specifying a target rather than a variable (such as make debug=1, not great) I have a condensed simplified example here that emulates what I am trying to achieve:
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
This example would have me use make debug=1 but I don't really like it and feel this implementation could be better. One way is to use target specific variables , but I am not entirely sure how to use them when the dependencies also need to change their names when a debug target is built. Something like:
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 > $@
Here the target will work alright as the bin/$(BINARY).bin target wont need to be built when debug is being built.But I am not sure how to handle the dependencies module_1/$(MODULE_1_BIN).bin and module_2/$(MODULE_2_BIN).bin in the recipe when building debug
回答1:
A previous version of this answer tried to use target-specific variables, but they are of limited use, because they are used in recipes, but are ignored when it comes to specifying targets and prerequisites.
Implicit rules make use of patterns, but capturing both my_binary and my_binary_debug with the implicit target my_binary% doesn’t work, because patterns don’t match the empty string.
In this case however, implicit rules work, because all your targets and dependencies have the common ending .bin, which is nonempty. The string that matches % is avalaible in the automatic variable $*.
So this is my solution:
.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
If the recipe to build bin/my_binary.bin can be rewritten with all modules one after another and $(FLAG) at the beginning, some more semplifications are possible:
.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
回答2:
As I said before, you cannot use target-specific variables in prerequisites for that target, only in recipes for that target and recursive prerequisites. I think the best you can do, according to what you want, is this:
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))))
来源:https://stackoverflow.com/questions/49346580/makefile-for-release-and-debug-targets