编写可重用代码的最佳实践

ДМИ*_*КОВ 6 makefile

Makefiles中编写可重用代码的最佳实践是什么?

假设我有一个Makefile:

.PHONY: all task01-all task01-clean task01-run task02-all task02-clean task02-run

all: task01-all task02-all

###############################################################################
task01-all: task01-clean task01 task01-run

task01-clean:
     rm task01 task01.{exi,o} -f

task01:
    compiler task01.ext -O2 --make

task01-run:
    ./task01

###############################################################################
task02-all: task02-clean task02 task02-run

task02-clean:
    rm task02 task02.{exi,o} -f

task02:
    compiler task02.ext -O2 --make

task02-run:
    ./task02
Run Code Online (Sandbox Code Playgroud)

现在,我想补充的任务(task03)新的家庭,我需要copypaste整段,使得s/02/03/它并将其添加到.PHONY节-这是嘈杂,恶心,只是不正确的.

我怎么能避免这种情况?我可以用模板重新定义所有任务,以便在一行中添加新任务组的好机制吗?

lai*_*dir 9

由于问题是关于在Makefile中编写可重用代码,我将举例说明如何在GNU Make中使用模式规则(看起来这就是你提到.PHONY目标时所使用的内容).但是,如果您没有使用任何Make的依赖项检查,那么使用shell脚本执行此操作可能更简单 - 例如:

#!/bin/sh
TASKS="task01 task02 task03"

for i in $TASKS; do
    rm $i $i.ext $i.o -f;
    compiler $i.ext -O2 --make;
    ./$i;
done
Run Code Online (Sandbox Code Playgroud)

但是,为了将原则扩展到Make,我们还有另一个需要解决的问题.形式的行:

task01-all: task01-clean task01 task01-run
Run Code Online (Sandbox Code Playgroud)

不要告诉Make以什么顺序构建先决条件 - 只需要在task01-all构建之前完成所有这些操作.相反,每个要运行的步骤都应该取决于之前的步骤.像这样的东西:

TASKS=task01-run task02-run task03-run

.PHONY: all $(TASKS) $(TASKS:run=clean)

all: $(TASKS)

$(TASKS:run=clean): %-clean:
    rm $* $*.ext $*.o -f

%: %.ext | %-clean
    compiler $< -O2 --make

$(TASKS): %-run: %
    ./$<
Run Code Online (Sandbox Code Playgroud)

规则%被称为"模式规则",它们是避免为不同目标多次重写相同规则的好工具.需要注意的是,Make通常不会检查.PHONY目标的模式规则; 我们通过在目标列表和第二个冒号(例如$(TASKS):)之前添加前缀来告诉Make明确地这样做.

由于task01-run需要task01为了工作,我们制定%-run目标依赖%.此外,您的Makefile显示您希望每次都运行干净,因此我们%依赖于%-clean.由于%-clean实际上并没有产生任何输出,我们将其设为"仅订单"依赖项 - Make不会查找时间戳或任何内容,它只会在需要运行%-clean规则时首先运行%规则."仅订购"依赖项放在|:

%: %.ext | %-clean
Run Code Online (Sandbox Code Playgroud)

值得一提的是,Make的最大优势之一是它可以通过不重复不需要重复的工作来节省时间 - 即,如果依赖关系比目标更新,它只会运行规则.所以,你可以离开过的依赖%-clean,这将导致做出只运行compiler $< -O2 --make,如果%.ext是比新%:

%: %.ext
    compiler $< -O2 --make
Run Code Online (Sandbox Code Playgroud)

然后,您可以添加规则以运行所有%-clean目标:

.PHONY: all $(TASKS) $(TASKS:run=clean) clean

clean: $(TASKS:run=clean)
Run Code Online (Sandbox Code Playgroud)

最后一件事:我在食谱中使用了一些特殊的变量.$@代表正在建造的目标.$<代表第一个依赖.$*代表模式规则的"主干"(即,与之匹配的部分%).