如何将一个独立的Makefile目标设为另一个目标的依赖,并在选项改变时重新构建
我创建了一个有多个目标的makefile,将从另一个脚本调用。一个目标依赖于一个选项文件。选项文件依赖于一个空的FORCE目标,它的配方会检查传入的选项是否发生变化。只有在确实变化时,选项文件才会更新。其意图是在传入的选项发生变化时重新构建所有受影响的文件。
以下是表示主源文本的文件,main.asm:
section code
incbin "help1.txt"
incbin "help2.txt"
incbin "help3.txt"
下面是三个帮助模块,help/help1.asm:
%ifdef OPTION
db "Good",13,10
%else
db "Bad",13,10
%endif
和help/help2.asm:
%ifdef OPTION
db "Good quux",13,10
%else
db "Bad quux",13,10
%endif
以及help/help3.asm:
%ifdef OPTION
db "Good baz",13,10
%else
db "Bad baz",13,10
%endif
这是我的两个独立目标的makefile,helptxt 和 main.bin:
NASM?=nasm
HELPSOURCES = $(wildcard help/*.asm)
HELPTXT = $(patsubst help/%.asm,%.txt,$(HELPSOURCES))
all: main.bin
clean:
rm -f *.bin *.txt *.lst
.SUFFIXES: .bin .asm .txt
option: FORCE
@echo $(OPTIONS) > option.new
@diff -Nq option option.new \
|| cp -a option.new option
FORCE:
helptxt: $(HELPTXT)
%.txt: help/%.asm option
$(NASM) $(OPTIONS) help/$*.asm -o $*.txt -fbin
%.bin: %.asm
$(NASM) $*.asm -l $*.lst -o $*.bin -fbin
以下是从干净状态重新构建的预期用法:
test$ make clean
rm -f *.bin *.txt *.lst
test$ make helptxt OPTIONS=-DOPTION
Files option and option.new differ
nasm -DOPTION help/help1.asm -o help1.txt -fbin
nasm -DOPTION help/help2.asm -o help2.txt -fbin
nasm -DOPTION help/help3.asm -o help3.txt -fbin
test$ make
nasm main.asm -l main.lst -o main.bin -fbin
test$ cat main.bin
Good
Good quux
Good baz
在本示例中,分别构建 helptxt 和 all 目标可以正常工作。然而,如果我们修改其中一个帮助文件,但未检测到 main.bin 需要重新构建,效果就不会按预期进行:
test$ touch help/help1.asm
test$ make helptxt OPTIONS=-DOPTION
nasm -DOPTION help/help1.asm -o help1.txt -fbin
test$ make
make: Nothing to be done for 'all'.
现在 main.bin 已经过时。因此,我们希望将.txt文件添加为 main.bin 的依赖项。看起来很简单,在makefile中加入以下内容:
ifeq ($(EXTERNALHELPTARGET),helptxt)
main.bin: $(HELPTXT)
endif
因此现在我们重新尝试,设定变量使其依赖于.txt文件:
test$ touch help/help1.asm
test$ make helptxt OPTIONS=-DOPTION
nasm -DOPTION help/help1.asm -o help1.txt -fbin
test$ EXTERNALHELPTARGET=helptxt make
Files option and option.new differ
nasm help/help1.asm -o help1.txt -fbin
nasm help/help2.asm -o help2.txt -fbin
nasm help/help3.asm -o help3.txt -fbin
nasm main.asm -l main.lst -o main.bin -fbin
test$ cat main.bin
Bad
Bad quux
Bad baz
发生了什么?第二次make运行重新构建了所有帮助文件,现在得到的是错误的内容。也就是说选项开关没有被正确传递。
这个问题在我把一些脚本转换为 [我的86-DOS调试器项目,lDebug](带一个小写字母L)时出现。新的makefile包含 [helptxt和 helphlz目标],它们等价于本例中的 helptxt。选项文件 [名为optionlz],并接收变量 $(LZEXEDAT_L_SWITCH),该变量在生成lzexedat压缩的帮助文件的配方中使用。需要依赖这些帮助文件的文件是 msg.obj。
解决方案
解决方法是在调用 make 时,总是为 helptxt 目标传递选项开关。如果与 helptxt 相同的文件是 main.bin 的前提条件,那么在第二次 make 运行时也会执行强制选项检查;如果发现选项不同(例如为空字符串),它将导致以错误的选项状态重建所有.txt文件。
将.txt文件选项开关传递给第二次 make 调用即可解决。以下是在该问题最后一次运行之后的立即一次运行:
test$ make helptxt OPTIONS=-DOPTION
Files option and option.new differ
nasm -DOPTION help/help1.asm -o help1.txt -fbin
nasm -DOPTION help/help2.asm -o help2.txt -fbin
nasm -DOPTION help/help3.asm -o help3.txt -fbin
test$ EXTERNALHELPTARGET=helptxt make OPTIONS=-DOPTION
nasm main.asm -l main.lst -o main.bin -fbin
test$ cat main.bin
Good
Good quux
Good baz
test$
为了证明只有 help1.txt 和 main.bin 在修改单个文件 help/help1.asm 时会重新构建,下面给出另一组传入正确选项的运行:
test$ touch help/help1.asm
test$ make helptxt OPTIONS=-DOPTION
nasm -DOPTION help/help1.asm -o help1.txt -fbin
test$ EXTERNALHELPTARGET=helptxt make OPTIONS=-DOPTION
nasm main.asm -l main.lst -o main.bin -fbin
test$ cat main.bin
Good
Good quux
Good baz
test$
实现正确顺序的 make 命令的实际项目修订位于 https://hg.pushbx.org/ecm/ldebug/rev/df5bf9cf492a