我试图在Makefile中为每个目标添加一些行为,而不修改目标。
我目前的尝试是:
%: $*
@echo 'Logging $* target'
.PHONY: test
test:
@echo 'Inside explicit test target'
当我运行make test
时,我想匹配%
模式规则,该规则会执行test
作为先决条件($*
扩展到模式主干) ,然后记录已运行的目标。
$ make test
Inside explicit test target
Logging test target
相反,会发生的事情是make test
与显式test
目标匹配(可能是因为它更接近匹配):
$ make test
Inside explicit test target
如何在不更改显式测试目标的情况下使其工作?
编辑: 另一种尝试......
.SECONDEXPANSION:
%: $$*
@echo 'Logging $* target'
结果
$ make test
make: Circular Makefile <- Makefile dependency dropped.
inside actual test target
答案 0 :(得分:1)
我出现在你自己的答案中,这打败了我
您只关心触发目标的初步操作
在命令行上提到 - $(MAKECMDGOALS)
。从我发布的帖子
你希望对#34; Makefile&#34;中的每个目标都进行这样的操作
将包括命令行目标的先决条件的所有目标,或者
如果没有命令行目标,则为默认目标。
无论如何,您可能仍然对解决更普遍的问题感兴趣。
您希望在每个目标的配方之前执行初步操作。 您的问题是:如何在显式规则之前匹配模式规则?
这是一种解决问题的XY方式,因为make
会参考模式
规则只有在您不明确指出时才能找到制作目标的方法
食谱。例如,您知道make
具有预定义的模式规则
从.o
文件创建.c
文件。即便如此,如果我的makefile是:
test.o:
@echo $@
然后make
打印test.o
,而不试图找到test.c
并编译它。
如果我的make文件是:
test.o: test.c
@echo $@
test.c:
@echo $@
然后make
打印:
test.c
test.o
不需要诉诸模式规则。但是如果我的makefile是:
test.o: test.c
然后make
说:
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop
所以你不能按照问题的方式做你想做的事情, 因为你想从模式中挑起初步行动 只有当目标没有没有其他行动时,才能激发规则。
在这种情况下,你的两次尝试失败的原因是相当学术性的, 您可能希望滚动到 The Chase 。
在您的第一次尝试中,使用:
%: $*
@echo 'Logging $* target'
模式规则 - 由make test
失业 - 相当于:
%:
@echo 'Logging $* target'
因为$*
仅假定配方中的值,而不是模式规则中的值。您
可以通过制作任何目标来使这种模式规则
makefile 不提供配方,例如make nonsuch
将打印Logging nonsuch target
;
但那是没用的。
第二次尝试,用:
.SECONDEXPANSION:
%: $$*
@echo 'Logging $* target'
创建您打算创建的规则是正确的。但是 该规则的含义是:
<target>: <target>
@echo 'Logging <target> target'
使应用此规则的每个目标成为其自身的先决条件。
这将不可避免地导致所有此类目标的循环依赖性错误。
如您所见,此循环不会影响您的test
目标,因为
它有一个明确的配方,不使用该规则。但它确实引起了挑战
令人惊讶的错误:
make: Circular Makefile <- Makefile dependency dropped.
这是因为make
自动考虑的第一个目标是
makefile本身。与test
目标不同,您没有配方
makefile;所以模式规则适用于它,使makefile依赖
本身。
追逐
您可以通过不同的方法实现您想要的目标。在一个实际的项目中
很可能在任何makefile中你都可以计算出一个列表
所有可能的目标。从这里你可以生成一个相应的列表
辅助目标,比如,目标 =&gt; target.prelim ,其中
target.prelim 的唯一目的是挑衅,当它应该和不应该
否则,目标所需的初步行动;你可以make
生成order-only rules,目标的列表:| target.prelim ,
对于每个目标,在确定 target 时不会考虑 target.prelim
必须制作,但只要目标需要在目标之前制作。
以下是插图:
SRCS := main.c foo.c
OBJS := $(SRCS:.c=.o)
TARGETS := all prog $(OBJS)
PRELIMS := $(patsubst %,%.prelim,$(TARGETS))
define prelim_rule =
$(1): | $(1).prelim
endef
$(foreach target,$(TARGETS),$(eval $(call prelim_rule,$(target))))
.PHONY: all
all: prog
prog: $(OBJS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(PRELIMS) prog
%.prelim:
@echo "Logging target $(@:%.prelim=%)"
@touch $@
示例会话:
$ make
Logging target all
Logging target main.o
cc -c -o main.o main.c
Logging target foo.o
cc -c -o foo.o foo.c
Logging target prog
cc -o prog main.o foo.o
$ make
make: Nothing to be done for 'all'.
$ make clean
rm -f main.o foo.o all.prelim prog.prelim main.o.prelim foo.o.prelim prog
$ make main.o
Logging target main.o
cc -c -o main.o main.c
$ make main.o
make: 'main.o' is up to date.
$ # A prelim can't out-date its target...
$ touch main.o.prelim
$ make main.o
make: 'main.o' is up to date.
答案 1 :(得分:0)
我意识到这并没有按照要求回答我的问题,但它有我想要的效果 - 尽可能在MoveEntity(id, newPosition)
处理后期执行shell
命令。
Makefile
MYVAR?=foo
.PHONY: test
test:
@echo 'Inside test target'
LOG=$(shell echo 'Logging $(MAKECMDGOALS), myvar=$(MYVAR)' > log)
.SECONDEXPANSION:
force: $$(LOG)
是一个延迟变量,因此在Make评估LOG
目标的先决条件列表之前不会展开。
在单个Makefile中,不需要force
部分,因为在.SECONDEXPANSION:
设置后评估force
目标。
但是,如果我将MYVAR
变量和LOG
变量移动到子制作文件中,force
行之前很容易include subMakefile
- 这不会工作。
通过为MYVAR?=
指定.SECONDEXPANSION
,可以消除对订购的依赖。