从foreach中包含的目标配方中的文件中读取变量

时间:2018-03-29 03:56:51

标签: makefile gnu-make

我有一个可以创建多个目标的顶级Makefile,我有一个for循环。在这个文件中,我试图读取一个文本文件,其版本号仅在子makefile运行时创建。我有它工作,但它看起来非常难看,所以我认为可能有更好的方法来做到这一点。这是顶级Makefile:

T1=_release
T2=_debug
T3=_test


all: bin/mybin_release.bin
debug: bin/mybin_debug.bin
debug: export DBG:=1
test: bin/mybin_test.bin
test: export TST:=1

define build_foo

bin/mybin$$($(1)).bin: bin/abc$$($(1)).bin bin/xyz$$($(1)).bin
    cat $$^ > $$@
    VER=$$$$(cat bin/rev.txt) && mv bin/mybin$$($(1)).bin bin/mybin$$($(1))_$$$${VER}.bin

bin/abc$$($(1)).bin:
    $(MAKE) -C mod1    # <--- rev.txt is produced here

bin/xyz$$($(1)).bin:
    $(MAKE) -C mod2

endef

$(foreach suffix, T1 T2 T3, $(eval $(call build_foo,$(suffix))))

clean:
    rm bin/*.bin bin/*.txt

请注意尝试在VER中抓取文件内容。有没有更好/正确的方法来做到这一点?我不能使用eval,因为它在开始时运行,rev.txt只在子make运行时才会创建。 另外,这是构建多个目标(使用foreach)的一种不错的方法吗?我使用导出的变量来修改子makefile构建的目标。

1 个答案:

答案 0 :(得分:1)

据我所知,运行bin/rev.txt时会生成此bin/abcXXX.bin文件和所有$(MAKE) -C mod1。所以,对所有人来说都是一样的。怎么样:

include version.mk

version.mk: bin/rev.txt
    { printf 'VER = '; cat $<; } > $@

bin/rev.txt:
    $(MAKE) -C mod1

演示:

$ ls
Makefile
$ cat Makefile
include version.mk

all:
    touch $(VER).txt

version.mk: rev.txt
    { printf 'VER = '; cat $<; } > $@

rev.txt:
    echo "1.2.3" > $@
$ make --quiet
Makefile:1: version.mk: No such file or directory
$ ls
1.2.3.txt  Makefile  rev.txt  version.mk

说明:

version.mk是make将寻找的第二个makefile。根据{{​​3}}:

  

为此,在阅读完所有makefile后,make会考虑每个   作为目标目标并尝试更新它。如果makefile有规则   它说如何更新它(发现在那个非常makefile中或者在   另一个)或者隐含规则适用于它(请参阅使用隐式   规则),必要时会更新。毕竟makefile已经   检查,如果有任何实际更改,请从干净开始   平板并再次读取所有makefile。 (它也会尝试   再次更新它们,但通常这不会改变它们   再次,因为他们已经是最新的。)

注意:在编写makefile时,$(MAKE) -C mod1将运行多次,这是一种浪费。您可以使用GNU make pattern规则的特异性:当它们有多个目标时,make会认为所有目标都是通过一次调用配方生成的。例如:

$ cat Makefile
all: a.bin b.bin c.bin

a.%in b.%in c.%in:
    @echo 'building a.bin b.bin c.bin'
$ make all
building a.bin b.bin c.bin

请参阅?配方仅执行一次以构建3个目标。唯一的问题是%通配符必须至少匹配一个字符。因此,在您的情况下,您可以执行类似的操作(%匹配的字符是b的{​​{1}}):

bin/

这将告诉make T1 := _release T2 := _debug T3 := _test suffixes := T1 T2 T3 pattern := $(foreach suffix,$(suffixes),%in/abc$($(suffix))) %in/rev.txt $(pattern): $(MAKE) -C mod1 一次构建所有$(MAKE) -C mod1bin/abcXXX.bin。与bin/rev.txt相同。

总而言之,通过将所有这些功能粘合在一起,您可能完全摆脱了$(MAKE) -C mod2通用规则。类似的东西:

build_foo