我尝试使用Go的codegen工具根据其他go文件的内容自动生成一些代码。 codegen工具将获得标准参数,这些参数可以从其生成的文件名称和它解析的文件名称中推断出来。如果我手动完成所有操作,它将如下所示:
foo-tool -name FooInterface -file foo/api.go
foo-tool -name BarInterface -file foo/api.go
foo-tool -name BingInterface -file foo/bing.go
foo-tool -name BazInterface -file foo/baz.go
但我不想手动操作,我想使用Make!所以我尝试使用Makefile和模式规则完成同样的事情。
foo_FooInterface.go : foo/api.go
foo_BarInterface.go : foo/api.go
foo_BingInterface.go : foo/bing.go
foo_BazInterface.go : foo/baz.go
foo_%.go : %.go
$(eval foo_name=$(subst mock_,,$(subst .go,,$(@F))))
build-foo -name $(foo_name) -file $<
在我看来,前3条规则会设置依赖图,模式规则会告诉Make如何处理依赖项。但是当我尝试运行make foo_BarInterface.go
时,我得到make: Nothing to be done for foo_BarInterface.go
。我理解为什么会发生这种情况,因为Make期望将foo_FooInterface.go与FooInterface.go匹配,但我不想重构我的项目文件。
这是可能的,还是我需要做类似的事情:
foo_FooInterface.go : foo/api.go
build-foo -name FooInterface -file foo/api.go
foo_BarInterface.go : foo/api.go
build-foo -name BarInterface -file foo/api.go
foo_BingInterface.go : foo/bing.go
build-foo -name BingInterface -file foo/bing.go
foo_BazInterface.go : foo/baz.go
build-foo -name BingInterface -file foo/baz.go
我真的不想这样做,因为随着代码库的增长会添加新的Interface
,而且我不想要求人们每次都输入所有内容。
编辑:我不介意每次都手动指定规则,但我需要一个规则来收集所有生成的文件,而且我不想指定每个foo _ *。 。有没有办法说&#34;这个规则取决于与模式匹配的所有规则(而不是文件)?&#34;我能够做到
foo_files := $(shell grep 'foo_\w\+.go' Makefile | cut -d : -f1)
但这对我来说似乎很糟糕。
答案 0 :(得分:1)
您可以为这三个规则编写一个通用配方:
foo_FooInterface.go foo_BarInterface.go foo_BingInterface.go: foo/api.go
foo-tool -name $(@:foo_%.go=%) -file $<
对于每个单独的目标单独执行,单独 ,即:foo_FooInterface.go
一次,foo_BarInterface.go
一次和一次对于foo_BingInterface.go
,不仅适用于所有人。
答案 1 :(得分:1)
没有比这更容易了:
foo_%.go : foo/api.go
foo-tool -name $* -file $<
如果你想要一个将它们聚集在一起的规则:
INTERFACES := Foo Bar Bing
FILES := $(patsubst %, foo_%Interface.go, $(INTERFACES))
all: $(FILES)
@echo do something with $^
答案 2 :(得分:1)
如果每个目标文件都有不同的先决条件,则无法避免单独指定它们。您可以使用空规则执行此操作,如下所示:
foo_FooInterface.go : foo/api.go
foo_BarInterface.go : foo/api.go
foo_BingInterface.go : foo/bing.go
foo_BazInterface.go : foo/baz.go
但是,使用这种样式的makefile,构建目标的规则不能具有先决条件:如果这样做,则忽略空规则中指定的先决条件。所以你需要的是简单的规则
foo_%.go:
foo-tool -name $* -file $<
(请注意$^
已扩展为所有先决条件的列表,$<
仅为第一个。在您的示例中没有区别,但可能有。)
我不知道有任何方法指定“匹配模式的makefile中的所有规则”。但正如@Beta建议的那样,在变量中“注册”所有所需名称的成本很低。把它们放在一起:
# Register all your components here
INTERFACES := Foo Bar Bing Baz
# Make ’em all
.PHONY : all
all: $(patsubst %, foo_%Interface.go, $(INTERFACES))
# Specify individual dependencies with empty rules
foo_FooInterface.go : foo/api.go
foo_BarInterface.go : foo/api.go
foo_BingInterface.go : foo/bing.go
foo_BazInterface.go : foo/baz.go
# This is your catch-(almost-)all rule
foo_%.go:
foo-tool -name $* -file $<
因此,每个新目标只需要在INTERFACES
中注册其名称并添加具有依赖性的行。在我看来,尝试仅添加依赖行并从中推断出新目标的存在(正如您通过grepping foo_\w\+.go
的makefile所做的那样),降低了整体可读性而没有任何实际好处。