匹配Makefile目标的不同/多个部分
这是一个Makefile,我目前使用它来创建具有不同配置的目标,也就是说,我正在使用同一个目标构建不同的软件包,可以一次生成,也可以单独生成匹配Makefile目标的不同/多个部分,makefile,pattern-matching,target,Makefile,Pattern Matching,Target,这是一个Makefile,我目前使用它来创建具有不同配置的目标,也就是说,我正在使用同一个目标构建不同的软件包,可以一次生成,也可以单独生成 .PHONY: build test %.build %.test build-all test-all %.build %.test: PACKAGE = $* %.build: @echo build $(PACKAGE) %.test: @echo test $(PACKAGE) build-all: a.build b.bui
.PHONY: build test %.build %.test build-all test-all
%.build %.test: PACKAGE = $*
%.build:
@echo build $(PACKAGE)
%.test:
@echo test $(PACKAGE)
build-all: a.build b.build
test-all: a.test b.test
build: $(PACKAGE).build
test: $(PACKAGE).test
我现在可以使用makebuildall
构建所有包,也可以使用makebuildpackage=a
构建单个包。但是,我想切换%.build
和build
等目标的主体,如下所示:
.PHONY: build test %.build %.test build-all test-all
build:
@echo build $(PACKAGE)
test:
@echo test $(PACKAGE)
build-all: a.build b.build
test-all: a.test b.test
%.build %.test: PACKAGE = $*
$(PACKAGE).%: $*
这样,模式匹配逻辑就与应该包含实际构建命令的“主要”目标build
和test
完全分离;使Makefile的重要部分更具可读性。但是,最后一行没有按预期工作,即运行make a.build
,因此make build all
应该触发目标build
,使用PACKAGE=a
。最后一行中的变量赋值有效,而最后一行中的目标匹配无效
问题:有没有一种方法可以表示匹配的目标,如
$(包)。%:$*
或匹配目标的单独部分,如%。%:$2
?首先您可能需要:
$(PACKAGE).% : %
不使用$*
,这是一个自动变量,因此除了配方内部之外,它没有任何值;在必备条件列表中不能这样使用它
第二,在GNU make中不能这样做。没有配方的模式规则不仅仅像显式规则那样创建先决条件关系;相反,它会删除模式规则。由于您没有$(包).%
的模式规则,这基本上是不可行的。而且,特定于目标的变量仅在配方中可用,因此尝试在目标定义中使用$(包)
,并期望它从以前设置的特定于目标的变量中获取值是行不通的
您可以这样做,但它不是完全动态的(您仍然需要包和类型的列表):
正如疯狂科学家所解释的,这个问题在GNU make中不容易解决。为了完整起见,我想补充并解释我的最终和更全面的解决方案:
.PHONY: all build test clean %.build %.test build-all test-all
PACKAGES = a b c e f g
PACKAGE = a
all: clean build-all test-all
%.build %.test: PACKAGE = $*
%.build:
@echo build $(PACKAGE)
%.test:
@echo test $(PACKAGE)
clean:
@echo remove build dir
build-all: $(addsuffix .build, $(PACKAGES))
test-all: $(addsuffix .test, $(PACKAGES))
build: $(PACKAGE).build
test: $(PACKAGE).test
此解决方案避免了eval
和foreach
,并基于我的初始工作解决方案,其中动态%.build
和%.test
目标包含实际的构建命令。我添加了PACKAGES
变量以方便添加新包,添加了默认的PACKAGES
以防止执行错误配置的构建命令,并添加了公共目标all
和clean
作为补充
从命令行,您只需调用make
all
,clean
,build PACKAGE=x
,build all
,等等,即仅调用静态目标,然后将触发动态目标中的构建命令。静态目标和两个变量在Bash/Zsh自动完成中也可见
我认为这是构建多个动态目标的最灵活且可读的方法。我意识到这只是一个示例,但这里没有需要make的东西。如果这真的是全部,那么您使用了错误的工具,只需编写一个shell脚本。正如上的第一句所指出的,“GNU Make是一个工具,它控制从程序的源文件生成程序的可执行文件和其他非源文件。”我使用此模式从go代码生成和测试可执行文件,例如,调用
go build
或go install
,和go test
,用于不同分区中的包。我还使用此模式在docker映像内构建可执行文件,并构建docker映像本身。好的,因此我需要foreach
和eval
。我想避免那样。然而,这回答了我的问题。谢谢如果您只有两种目标类型(build
和test
),那么编写它们肯定更简单、更可读。
.PHONY: all build test clean %.build %.test build-all test-all
PACKAGES = a b c e f g
PACKAGE = a
all: clean build-all test-all
%.build %.test: PACKAGE = $*
%.build:
@echo build $(PACKAGE)
%.test:
@echo test $(PACKAGE)
clean:
@echo remove build dir
build-all: $(addsuffix .build, $(PACKAGES))
test-all: $(addsuffix .test, $(PACKAGES))
build: $(PACKAGE).build
test: $(PACKAGE).test