我有一小组C的源代码文件。我正在尝试拼凑一个Makefile,它们可以从同一组源代码中构建几个不同的输出。每个输出都使用特定于目标的变量进行自定义。
(现实世界的例子是在几个不同的电路板版本上运行的固件,但它是使用相同的源代码构建的,并使用条件编译进行自定义。)
这是一个示例Makefile,说明了我遇到的问题:
CINPUTFILES = Testfile.c
all: v12target v13target
# the same source code is built several different ways depending on a
# list of preset configurations
v12target: lots_of_common_variables = hello
v12target: more_variables = v12_specific
v12target: Rev12Output.mycommontargets
v13target: lots_of_common_variables = hello
v13target: more_variables = v13_specific
v13target: Rev13Output.mycommontargets
# (more vXXtarget targets omitted)
# TODO: why is @echo required?
%.mycommontargets: %.hex %.elf
@echo
# TODO: why are these output files deleted?
%.elf: $(CINPUTFILES)
cp $< $@
%.hex: %.elf
cp $< $@
# TODO: correct way of adding the dummy mycommontargets to PHONY?
.PHONY : all clean
这个想法是all
目标构建了几个不同的目标 - 每个硬件版本都有一个目标。因为除了配置变量列表之外,每个构建过程都是相同的,所以它会调用许多设置变量的vXXtarget
目标,然后调用一个公共目标:%.mycommontargets
。然后,该目标设置生成实际输出文件。
注意TODO标记......
%.mycommontargets
:出于某种原因,如果我删除@echo
,我会收到错误消息:
make: *** No rule to make target `Rev12Output.mycommontargets', needed by `v12target'. Stop.
为什么会发生这种情况,我需要做些什么才能摆脱它?
如果我保留@echo
,则构建成功完成。但是然后决定继续并删除输出!
$ make
cp Testfile.c Rev12Output.elf
cp Rev12Output.elf Rev12Output.hex
cp Testfile.c Rev13Output.elf
cp Rev13Output.elf Rev13Output.hex
rm Rev12Output.hex Rev12Output.elf Rev13Output.hex Rev13Output.elf
为什么make会这样做?决定什么时候会这样做,什么时候不呢?我从来没有意识到make甚至有能力删除这样的文件;它与增量构建的整个想法背道而驰,我认为这应该是有帮助的。我宁愿保留所有中间和输出文件...
mycommontargets
模式添加到.PHONY
?我想我可以保留@echo
,然后将每个目标添加到.PRECIOUS
。但即使我没有很多make的经验,我也有强烈的感觉,如果我必须使用像@echo
之类的黑客并且使用更加模糊的特殊目标,例如{{{ 1}}。只是感觉不对。
(对于1个问题似乎在空间中提出3个问题的道歉,但我感觉他们有很强的相关性......)
答案 0 :(得分:1)
输出文件是中间文件,即Makefile中未明确提及,但模式规则需要。默认情况下,make删除所有中间文件。这里禁用自动删除的最简单方法是在没有先决条件的情况下提及.SECONDARY
目标,即在某处添加一行只是说:
.SECONDARY:
如果你真的需要这里的.PHONY,你必须没有模式规则。这在你的布局中是非常不受欢迎的,所以最好让它成为现实。
总的来说,我建议在这里采用更正统的布局。通常,您将交叉编译问题从Makefile中删除,并将主机板(autotools用语:主板是软件将运行的板)作为configure
的参数。让configure从中央源代码树为每个主机板生成一个构建树,并构建在这些构建树中。