【问题标题】:Writing pattern rules for complex build commands with GNU Make使用 GNU Make 为复杂的构建命令编写模式规则
【发布时间】:2017-11-09 19:13:45
【问题描述】:

我正在使用一个使用mcs 作为构建命令的makefile 系统。简而言之,mcs 被调用:

  • 源文件:直接传递;
  • 资源:-resource:;
  • 一个目标:-target:,可以是exe、winexe、library或module。

并产生*.exe、*.dll 或*.netmodule。 -target: 参数在最后两种情况下是确定的,但*.exe 可以使用exe 或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)

在每个项目目录中,变量OUTPUT、TARGET、SOURCES和RESOURCES在包含之前定义。

即使我遗漏了所有内容,它也相当复杂,并且只能构建包含它的单个具体目标,而无需复制构建规则。

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

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

例如对于mcs,这些模式似乎是可能的:

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

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

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

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

如果用户为目标添加源文件先决条件,则上述$&lt; 可以交换为$^ 以传递它们,但这不适用于资源文件。仅订单列表可用于传递资源文件先决条件,但仅在更新资源文件时会阻止重建。

是否有一种通用技术可以将这种复杂命令的调用转换为模式规则或规则集?

【问题讨论】:

  • 对 Make 的这种错综复杂的使用已经产生了一个不好的后果:它使您的问题不清楚。在我尝试找到正确的方法来做这件事之前,我必须弄清你想要做什么以及为什么,这足以让我去寻找更有价值的问题。另外,你的连续句子伤害了我的眼睛。
  • 应该很清楚,在标题里。我正在尝试在 VPATH 工作的同时处理多种先决条件类型。
  • 我们不知道“多种类型的先决条件”是什么意思。什么是“先决条件类型”? Beta 的建议是,不要提供有关您已经解决的问题的信息,或者至少另外,您要提供您正在尝试完成的具体示例。此外,您绝对可以区分普通的仅订单先决条件;查看自动变量列表:gnu.org/software/make/manual/html_node/Automatic-Variables.html
  • 多种先决条件是指我需要调用的构建命令。具体示例实际上是mcs,它接受不同传递的源文件和资源文件。这些都不能仅仅被视为订单。否则,正如您所指出的,使用 $| 是可能的。
  • 对不起,但恕我直言,仍然不清楚您在问什么。从新编辑末尾的项目符号列表中,我认为您正在寻找一种在我想要的前提下运行的算法,以或多或少任意方式将输入列表转换为编译命令.如果没有对您的问题进行适当的结构化,您将无法做到这一点,SO 上的人也不会这样做。原始解决方案的程序员显然也认为这是一项过于复杂的任务,并手工编写了每个实例。

标签: makefile gnu-make


【解决方案1】:

有很多问题:

  1. build 命令区分多个先决条件类型;
  2. 必须一次性全部通过;
  3. 对其中任何一个的更新都必须导致重建,它们都是regular prerequisites。

想法:

  • 将要分离的输入委托给输入文件,然后将它们读回,这样您就可以有一个简单的目标来调用构建;
  • 使用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:,$^))

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

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

【讨论】:

  • 请测试一下,如果$(file &lt; filename.txt) 在您的系统上工作 - 在我的系统上它已损坏(GNU make 4.1)。
猜你喜欢
  • 2022-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多