我正在使用 Makefile 来编译我的干净的代码。我的 Clean 文件具有以下格式的文件名*.icl
,并编译为具有相同名称但不带.icl
.这是通过以下规则完成的:
$(EXE): % : %.icl | copy
$(CLM) $(CLM_LIBS) $(CLM_INC) $(CLM_OPTS) $@ -o $@
我现在想添加一条允许我运行二进制文件的规则。目前,我经常做
make some_module && ./some_module
我想要一个依赖于上述规则并运行模块的 make 目标。但是,模块的名称本身已经是单独编译的目标,我想保持这种状态。我想要的是一个带有两个单词的目标,我可以用它来调用make run some_module
它,然后取决于上面的规则并./some_module
随后运行。
是否可以创建包含多个单词的目标?
我尝试制定一条规则(现在仍然没有依赖性),如下所示:
run $(EXE):
./$@
运行make run some_module
会导致许多配方被“覆盖”和“忽略”,最终./run
不存在。
Makefile:24: warning: overriding recipe for target 'tut7_2_2'
Makefile:21: warning: ignoring old recipe for target 'tut7_2_2'
Makefile:24: warning: overriding recipe for target 'support_check'
Makefile:21: warning: ignoring old recipe for target 'support_check'
[...]
Makefile:24: warning: overriding recipe for target 'drawingframe'
Makefile:21: warning: ignoring old recipe for target 'drawingframe'
./run
/bin/bash: ./run: No such file or directory
Makefile:24: recipe for target 'run' failed
make: *** [run] Error 127
答案1
你也许可以使用$(MAKECMD目标)强制run
在命令行中指定的其他目标中最后执行。下面的例子使用C,因为我不知道Clean。
EXE = a b c
%: %.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
all: $(EXE)
clean:
rm -f $(EXE)
run: $(filter-out run, $(MAKECMDGOALS))
@for i in $^; do ./$$i; done
.PHONY: all clean run
make run program
可能看起来有点笨拙,因为它总是产生不必要的输出program is up to date
。
$ cat a.c
#include <stdio.h>
int main(int argc, char **argv) { printf("This is %s\n", argv[0]); return 0; }
$ cp a.c b.c
$ cp a.c c.c
$ make run a b
cc -o a a.c
cc -o b b.c
This is ./a
This is ./b
make: 'a' is up to date.
make: 'b' is up to date.
make program run
没有这样的输出,它可能像英语一样更自然。
$ make c run
cc -o c c.c
This is ./c
答案2
你可以检查MAKECMDGOALS
在建立另一个目标的同时检测一个目标的存在。要么让%: %.icl
运行检测目标的存在run
,要么让run
目标检查哪些可执行文件被称为目标。如果您传递多个可执行文件作为目标,第一个方法会导致每个文件在构建后立即运行,而第二个方法会导致所有运行在最后发生。
这种方法的缺点是它不能很好地与其他功能一起扩展。例如,如果您定义一个具有多个可执行文件作为依赖项的目标,则具有run
目标的方法将不起作用。
EXE = foo bar experimental
released: foo bar
run: $(filter $(EXE), $(MAKECMDGOALS))
set -e; for x in $^; do ./$x; done
这里make released run
不会运行任何东西。
对于这种情况,我通常做的是为每个可执行文件定义一个“运行”目标。这使得每个目标都表达为单个单词,这是一个主要优点。它很简单并且不会破坏其他功能。
$(EXE): %.run: %
./$(@:.run=)
all.run: $(EXE:=.run)
make {foo,bar}.run
然后,如果我想构建并测试foo
和bar
,或者make all.run
构建并运行它们,我就运行它们。