制作通用制作具有动态依赖关系的目标

时间:2018-04-04 13:02:56

标签: makefile build gnu-make

我需要生成一些具有不同加载地址的目标文件。我还有一个调用objdump的make目标来向我展示相应的反汇编。

code0:
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) $@.S -o $@.o
    objcopy -O binary $@.o --only-section=.text $@.bin

code1:
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE1_RELOC) $@.S -o $@.o
    objcopy -O binary $@.o --only-section=.text $@.bin

dump: dump_code0 dump_code1
dump_code0: code0.bin
    objdump $< -D > $<.decomp

dump_code1: code1.bin
    objdump $< -D > $<.decomp

这会失败,因为code.bin没有目标,但目标dump_code取决于code.bin存在。为了防止它混淆(即使用依赖code0,然后生成code0.bin)我认为创建一个%.bin目标会更容易创建与之关联的相应二进制文件每个目标文件(因为在所有code*目标中也存在此代码的重复。此目标将成为每个code*目标的依赖项。但是,这需要(或至少我认为确实如此)需要动态分配依赖关系。我尝试过这样的东西不起作用:

%.bin: $(basename $@)
    objcopy -O binary $(basename $@).o --only-section=.text $@.bin

code0: code0.bin
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) $@.S -o $@.o

逻辑是,code0.bin等依赖项会导致此目标以code0的单一有效依赖关系执行,以首先构建目标文件。

我可能误解了%字符如何用于通配符制作目标。 basename的第一次使用是评估为空(第二次使用),因此目标没有依赖关系。在调用时对依赖关系树进行一次评估确实有意义,但我希望能够提供更具动态性的功能。

这可以在Make中完成吗?

1 个答案:

答案 0 :(得分:1)

您正在寻找的可能是Static Pattern Rules,您可以使用它来重做您的第一次尝试:

code0:
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) $@.S -o $@.o
    objcopy -O binary $@.o --only-section=.text $@.bin

为:

code0.o code1.o: code%.o: code%.S
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE$*_RELOC) $< -o $@

code0.bin code1.bin: %.bin: %.o
    objcopy -O binary $< --only-section=.text $@

看原理?第一个规则的配方中的$*被静态模式规则的匹配词干(在我们的例子中为数字)所取代。这可行,但特定于模式的变量可能更容易理解和维护:

# Default code reloc option
CODE_RELOC := default_code_reloc_option

# code1-specific code reloc option, if different from default
code1.o: CODE_RELOC := code1_code_reloc_option

code0.o code1.o: %.o: %.S
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE_RELOC) $< -o $@

第一个makefile的最后一部分也可以使用静态模式规则和虚假目标。类似的东西:

.PHONY: dump dump_code0 dump_code1

dump: dump_code0 dump_code1

dump_code0 dump_code1: dump_%: %.bin.decomp

code0.bin.decomp code1.bin.decomp: %.bin.decomp: %.bin
    objdump $< -D > $@

最后,我们可以使用更多制作技巧(发现源文件,模式替换)来进一步自动化:

CODES   := $(wildcard *.S)
OBJS    := $(patsubst %.S,%.o,$(CODES))
BINS    := $(patsubst %.S,%.bin,$(CODES))
DECS    := $(patsubst %.S,%.bin.decomp,$(CODES))
DUMPS   := $(patsubst %.S,dump_%,$(CODES))

# Default code reloc option
CODE_RELOC := default_code_reloc_option

# code1-specific code reloc option, if different from default
code1.o: CODE_RELOC := code1_code_reloc_option

.PHONY: dump $(DUMPS)

dump: $(DUMPS)

$(DUMPS): dump_%: %.bin.decomp

$(DECS): %.bin.decomp: %.bin
    objdump $< -D > $@

$(BINS): %.bin: %.o
    objcopy -O binary $< --only-section=.text $@

$(OBJS): %.o: %.S
    gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE_RELOC) $< -o $@

.PHONY: clean

clean:
    rm -f $(OBJS) $(BINS) $(DECS)

clean目标是奖励礼物。

所有这一切都优于您尝试使用非真实文件的目标。在这里,文件依赖于其他文件,除了虚假目标,它们只是真实目标文件的一种简写。这100%符合make的理念:表达文件间依赖性,以便比较文件时间戳并决定什么是最新的以及必须重建的内容。当很多目标已经是最新的时,可以节省大量资金。

第二个优点是表达所有文件间依赖性是并行安全的。如果您使用以下命令在此makefile上运行make:

make -j 8

(假设您的计算机上有大约8个核心),您可以期望加速因子为8.如果您只有两个源文件,那就不多了,但如果您有数百个源文件则非常有趣......