基于 Makefile 中依赖关系的动态目标
Dynamic targets based on the dependency in Makefile
有几个类似的问题,但我无法将任何提出的概念应用到我的案例中。
只是为了提供一些背景信息:我有一组 Julia 文件,它们将绘图创建为 PDF,这是创建科学论文的制作过程的一部分,例如:
plots = $(shell find $(PLOT_PATH)/*.jl | sed 's/\.jl/\.pdf/g')
$(PLOT_PATH)/%.pdf: $(PLOT_PATH)/%.jl $(JULIA_SYSIMAGE)
$(JL) --project $< -o $(PLOT_PATH)
$(DOCUMENT_FILENAME).pdf: FORCE $(plots) $(figures)
latexmk $(DOCUMENT_FILENAME).tex
在当前的设置中,每个 XYZ.jl
文件都在创建一个 XYZ.pdf
文件并且它工作得很好。
现在我正在处理从单个 Julia 文件创建多个图会更容易的情况,因此脚本如下:
#!/usr/bin/env julia
using PGFPlotsX
...
...
pgfsave("whatever.pdf")
pgfsave("another.pdf")
pgfsave("yetanother.pdf")
这样就可以 grep pgfsave SCRIPT | awk...
找出目标。但是,我不知道如何根据依赖文件(Julia 脚本)的内容生成动态目标(绘图)。
针对我的问题的 MWE 如下:我有几个文件(依赖项)正在生成一堆目标,这些目标在这些文件中定义(并且可以通过 awk/grep/sed/whatever
访问)。现在,假设这些只是 *.txt
个文件,每一行都是一个目标。
文件: a.txt
foo
bar
baz
文件: b.txt
naarf
fjoord
一个非常基本的(非工作)手册 Makefile
来演示目标将是这样的(它不起作用,因为它无法弄清楚如何制作 foo
等等,但它显示需要重复的 *.txt
的模式):
文件: Makefile
all_products := $(shell find *.txt | xargs cat)
final_product: $(all_products)
echo $< > $@
(foo bar baz): a.txt
touch $(shell cat $<)
(narf fjoord): b.txt
touch $(shell cat $<)
所以原则上,我需要一些东西来“处理”依赖项 (*.txt
) 以创建目标列表,例如
$(shell cat $%): %.txt
echo $< > $@
但我无法在目标端获取对依赖项的引用($%
不起作用)。
有什么想法吗?也许整个方法只是一个坏主意 ;)
GNU make foreach
, eval
and call
functions 的组合可能就是您所需要的。以你的例子:
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets): $(1)
echo $$< > $$@
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
(注意宏定义中的$$
,是必须的)。然后:
$ make
make
echo a.txt > foo
echo a.txt > bar
echo a.txt > baz
echo b.txt > naarf
echo b.txt > fjoord
如果您希望配方一次构建所有目标,您将需要足够新的 GNU make 版本(4.3 或更高版本)及其新的 rule with grouped targets (x y z&: w
):
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets)&: $(1)
touch $$($(1)-targets)
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
然后:
$ make
touch foo bar baz
touch naarf fjoord
请注意,在这种情况下,我们还可以使用更简单且更少依赖 GNU make 的解决方案。只需使用空的虚拟文件作为时间戳,例如 .a.txt.tag
用于 a.txt
,以及静态模式规则:
TXT := $(wildcard *.txt)
TAG := $(patsubst %,.%.tag,$(TXT))
.PHONY: all
all: $(TAG)
$(TAG): .%.tag: %
touch `cat $<` $@
有几个类似的问题,但我无法将任何提出的概念应用到我的案例中。
只是为了提供一些背景信息:我有一组 Julia 文件,它们将绘图创建为 PDF,这是创建科学论文的制作过程的一部分,例如:
plots = $(shell find $(PLOT_PATH)/*.jl | sed 's/\.jl/\.pdf/g')
$(PLOT_PATH)/%.pdf: $(PLOT_PATH)/%.jl $(JULIA_SYSIMAGE)
$(JL) --project $< -o $(PLOT_PATH)
$(DOCUMENT_FILENAME).pdf: FORCE $(plots) $(figures)
latexmk $(DOCUMENT_FILENAME).tex
在当前的设置中,每个 XYZ.jl
文件都在创建一个 XYZ.pdf
文件并且它工作得很好。
现在我正在处理从单个 Julia 文件创建多个图会更容易的情况,因此脚本如下:
#!/usr/bin/env julia
using PGFPlotsX
...
...
pgfsave("whatever.pdf")
pgfsave("another.pdf")
pgfsave("yetanother.pdf")
这样就可以 grep pgfsave SCRIPT | awk...
找出目标。但是,我不知道如何根据依赖文件(Julia 脚本)的内容生成动态目标(绘图)。
针对我的问题的 MWE 如下:我有几个文件(依赖项)正在生成一堆目标,这些目标在这些文件中定义(并且可以通过 awk/grep/sed/whatever
访问)。现在,假设这些只是 *.txt
个文件,每一行都是一个目标。
文件: a.txt
foo
bar
baz
文件: b.txt
naarf
fjoord
一个非常基本的(非工作)手册 Makefile
来演示目标将是这样的(它不起作用,因为它无法弄清楚如何制作 foo
等等,但它显示需要重复的 *.txt
的模式):
文件: Makefile
all_products := $(shell find *.txt | xargs cat)
final_product: $(all_products)
echo $< > $@
(foo bar baz): a.txt
touch $(shell cat $<)
(narf fjoord): b.txt
touch $(shell cat $<)
所以原则上,我需要一些东西来“处理”依赖项 (*.txt
) 以创建目标列表,例如
$(shell cat $%): %.txt
echo $< > $@
但我无法在目标端获取对依赖项的引用($%
不起作用)。
有什么想法吗?也许整个方法只是一个坏主意 ;)
GNU make foreach
, eval
and call
functions 的组合可能就是您所需要的。以你的例子:
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets): $(1)
echo $$< > $$@
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
(注意宏定义中的$$
,是必须的)。然后:
$ make
make
echo a.txt > foo
echo a.txt > bar
echo a.txt > baz
echo b.txt > naarf
echo b.txt > fjoord
如果您希望配方一次构建所有目标,您将需要足够新的 GNU make 版本(4.3 或更高版本)及其新的 rule with grouped targets (x y z&: w
):
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets)&: $(1)
touch $$($(1)-targets)
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
然后:
$ make
touch foo bar baz
touch naarf fjoord
请注意,在这种情况下,我们还可以使用更简单且更少依赖 GNU make 的解决方案。只需使用空的虚拟文件作为时间戳,例如 .a.txt.tag
用于 a.txt
,以及静态模式规则:
TXT := $(wildcard *.txt)
TAG := $(patsubst %,.%.tag,$(TXT))
.PHONY: all
all: $(TAG)
$(TAG): .%.tag: %
touch `cat $<` $@