使用GNU Make为复杂的构建命令编写模式规则

时间:2017-11-09 19:13:45

标签: makefile gnu-make

我使用mcs作为构建命令使用makefile系统。简而言之,mcs用:

调用
  • 源文件:直接传递;
  • 资源:-resource:;
  • 目标:-target:,可以是exewinexelibrarymodule

并生成*.exe*.dll*.netmodule-target:参数在前两种情况下是确定的,但可以使用*.exeexe构建winexe

目前,每个目录的makefile都包含以下内容:

RESOLVED_SOURCES   := $(addprefix $(srcdir)/,$(SOURCES))
RESOLVED_RESOURCES := $(addprefix $(srcdir)/,$(RESOURCES))

S_PARAM := $(RESOLVED_SOURCES)
R_PARAM := $(addprefix -resource:,$(RESOLVED_RESOURCES))

all: $(OUTPUT)

$(OUTPUT): $(RESOLVED_SOURCES) $(RESOLVED_RESOURCES)
    $(MCS) $(MCSARGS) $(S_PARAM) $(R_PARAM) -target:$(TARGET) -out:$(OUTPUT)

在每个项目目录中,变量OUTPUTTARGETSOURCESRESOURCES在包含之前定义。

即使我遗漏了所有内容,但它仍然相当复杂,并且只能构建包含它的单个具体目标,而不会重复构建规则。

为了避免重复并增加灵活性,我想为这个复杂的构建命令定义一些模式规则,但这很困难:

  • 每个编译单元通常都有很多输入;
  • 无法逐步添加每个输入;
  • 某些输入需要不同的处理。

e.g。对于mcs,这些模式似乎是可能的:

%.exe: %.cs
    $(MCS) $(MCSARGS) -target:$(target) -out:$@ $< 

%.dll: %.cs
    $(MCS) $(MCSARGS) -target:library -out:$@ $< 

%.netmodule: %.cs
    $(MCS) $(MCSARGS) -target:module -out:$@ $< 

作为模式规则,它们并不是太糟糕,但它们对mcs的大多数应用程序都没有用,因为只有一个源文件被传递。

如果用户为目标添加了源文件先决条件,那么上面的$<可以交换为$^以传递它们,但不会对资源文件起作用。仅订单列表可用于传递资源文件先决条件,但在仅更新资源文件时会阻止重建。

是否存在将这种复杂命令的调用转换为模式规则或规则集的一般技术?

1 个答案:

答案 0 :(得分:0)

有很多问题:

  1. 构建命令区分多个先决条件类型;
  2. 他们必须立即通过;
  3. 对其中任何一个的更新都必须导致重建,它们都是regular prerequisites
  4. 思路:

    • 将您想要分开的输入委托给输入文件,然后将它们重新读入,这样就可以让一个简单的目标调用构建;
    • 使用secondary expansion您可以根据“模式变量”的内容定义这些输入文件;
    • general search应该有用。

    例如:

    multi_A := foo
    multi_B := bar
    
    all: multi.foo
    
    %.foo: .a.% .b.%
        @echo $*: $(foreach _,$^,$(file < $_))
        @touch $@
    
    .SECONDEXPANSION:
    
    .a.%: $$($$*_A)
        $(file > $@,$^)
    
    .b.%: $$($$*_B)
        $(file > $@,$(addprefix -b:,$^))
    

    开始使用二次扩展似乎很可疑。除此之外,最直接的问题是用户必须知道将读取任何常规先决条件并将其传递给构建命令。

    另一方面,知道这一点,用户可以通过依赖于将目标写入另一个输入文件的目标来为目标补充额外的输入参数。