使 "make" 在一个规则中更改跟踪两个目录
Make "make" change-track two directories in one rule
我正在使用 GNU Make,但如有必要,我愿意更改为其他软件。
我有两个目录 ALPHABETIC
和 NUMERIC
,内容如下。
./ALPHABETIC:
A.txt B.txt C.txt
./NUMERIC:
1.txt 2.txt 3.txt
和一个程序 foo
,它将 ALPHABETIC
中的文件和 NUMERIC
中的文件作为输入并输出一些东西。
我想创建这样的规则:如果 ALPHABETIC
中的文件 c
发生更改,则在 c
上重新 运行 foo
并且每个NUMERIC
中的文件。如果 NUMERIC
中的文件 n
更改,则 n
上的 运行 foo
以及 ALPHABETIC
.
中的每个文件
示例:A.txt
更改。那么应该发生的是:
foo A.txt 1.txt
foo A.txt 2.txt
foo A.txt 3.txt
让我们说现在 2.txt
变化。那么应该发生的是
foo A.txt 2.txt
foo B.txt 2.txt
foo C.txt 2.txt
我尝试使用模式规则来执行此操作,但没有成功。
由于 make 旨在管理从文件生成文件的构建系统,我们首先假设 foo A.txt 1.txt
在主目录中生成一个名为 A.1.txt
的文件。你可以尝试类似的东西:
.PHONY: all
.DEFAULT_GOAL := all
ALPHA := $(patsubst ALPHABETIC/%.txt,%,$(wildcard ALPHABETIC/*.txt))
NUM := $(patsubst NUMERIC/%.txt,%,$(wildcard NUMERIC/*.txt))
# $(1): ALPHA
# $(2): NUM
define ALPHANUM_rule
$(1).$(2).txt: ALPHABETIC/$(1).txt NUMERIC/$(2).txt
@echo foo $(1).txt $(2).txt && \
touch $$@
all: $(1).$(2).txt
endef
$(foreach a,$(ALPHA),$(foreach n,$(NUM),$(eval $(call ALPHANUM_rule,$(a),$(n)))))
请注意使用 echo
和 touch
来模拟真正的 foo
命令的效果。最重要的是要理解 foreach-eval-call
结构,包括为什么某些 $
符号需要加倍 ($$
) 的原因。有关详细说明,请参阅 The eval Function from the GNU make manual。
演示(host>
是shell提示符):
host> make
foo B.txt 2.txt
foo B.txt 3.txt
foo B.txt 1.txt
foo A.txt 2.txt
foo A.txt 3.txt
foo A.txt 1.txt
foo C.txt 2.txt
foo C.txt 3.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
host> touch NUMERIC/1.txt
host> make
foo B.txt 1.txt
foo A.txt 1.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
host> touch ALPHABETIC/C.txt
host> make
foo C.txt 2.txt
foo C.txt 3.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
但是如果 foo A.txt 1.txt
没有生成文件怎么办?在这种情况下,最简单的做法就是生成空文件。我们将在单独的目录中创建它们以便于清理:
.PHONY: all
.DEFAULT_GOAL := all
ALPHA := $(patsubst ALPHABETIC/%.txt,%,$(wildcard ALPHABETIC/*.txt))
NUM := $(patsubst NUMERIC/%.txt,%,$(wildcard NUMERIC/*.txt))
TAGSDIR := tags
$(TAGSDIR):
@mkdir -p $@
# $(1): ALPHA
# $(2): NUM
define ALPHANUM_rule
$(TAGSDIR)/$(1).$(2).txt: ALPHABETIC/$(1).txt NUMERIC/$(2).txt | $(TAGSDIR)
@echo foo $(1).txt $(2).txt && \
touch $$@
all: $(TAGSDIR)/$(1).$(2).txt
endef
$(foreach a,$(ALPHA),$(foreach n,$(NUM),$(eval $(call ALPHANUM_rule,$(a),$(n)))))
还有两点需要理解:
- 使用空文件 (
$(TAGSDIR)/A.1.txt...
) 来跟踪已经完成的工作和时间。
- Order-only prerequisite
$(TAGSDIR)
用于保证包含空文件的目录在使用前创建,而不会在每次修改其内容时强制重新构建。
我正在使用 GNU Make,但如有必要,我愿意更改为其他软件。
我有两个目录 ALPHABETIC
和 NUMERIC
,内容如下。
./ALPHABETIC:
A.txt B.txt C.txt
./NUMERIC:
1.txt 2.txt 3.txt
和一个程序 foo
,它将 ALPHABETIC
中的文件和 NUMERIC
中的文件作为输入并输出一些东西。
我想创建这样的规则:如果 ALPHABETIC
中的文件 c
发生更改,则在 c
上重新 运行 foo
并且每个NUMERIC
中的文件。如果 NUMERIC
中的文件 n
更改,则 n
上的 运行 foo
以及 ALPHABETIC
.
示例:A.txt
更改。那么应该发生的是:
foo A.txt 1.txt
foo A.txt 2.txt
foo A.txt 3.txt
让我们说现在 2.txt
变化。那么应该发生的是
foo A.txt 2.txt
foo B.txt 2.txt
foo C.txt 2.txt
我尝试使用模式规则来执行此操作,但没有成功。
由于 make 旨在管理从文件生成文件的构建系统,我们首先假设 foo A.txt 1.txt
在主目录中生成一个名为 A.1.txt
的文件。你可以尝试类似的东西:
.PHONY: all
.DEFAULT_GOAL := all
ALPHA := $(patsubst ALPHABETIC/%.txt,%,$(wildcard ALPHABETIC/*.txt))
NUM := $(patsubst NUMERIC/%.txt,%,$(wildcard NUMERIC/*.txt))
# $(1): ALPHA
# $(2): NUM
define ALPHANUM_rule
$(1).$(2).txt: ALPHABETIC/$(1).txt NUMERIC/$(2).txt
@echo foo $(1).txt $(2).txt && \
touch $$@
all: $(1).$(2).txt
endef
$(foreach a,$(ALPHA),$(foreach n,$(NUM),$(eval $(call ALPHANUM_rule,$(a),$(n)))))
请注意使用 echo
和 touch
来模拟真正的 foo
命令的效果。最重要的是要理解 foreach-eval-call
结构,包括为什么某些 $
符号需要加倍 ($$
) 的原因。有关详细说明,请参阅 The eval Function from the GNU make manual。
演示(host>
是shell提示符):
host> make
foo B.txt 2.txt
foo B.txt 3.txt
foo B.txt 1.txt
foo A.txt 2.txt
foo A.txt 3.txt
foo A.txt 1.txt
foo C.txt 2.txt
foo C.txt 3.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
host> touch NUMERIC/1.txt
host> make
foo B.txt 1.txt
foo A.txt 1.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
host> touch ALPHABETIC/C.txt
host> make
foo C.txt 2.txt
foo C.txt 3.txt
foo C.txt 1.txt
host> make
make: Nothing to be done for 'all'.
但是如果 foo A.txt 1.txt
没有生成文件怎么办?在这种情况下,最简单的做法就是生成空文件。我们将在单独的目录中创建它们以便于清理:
.PHONY: all
.DEFAULT_GOAL := all
ALPHA := $(patsubst ALPHABETIC/%.txt,%,$(wildcard ALPHABETIC/*.txt))
NUM := $(patsubst NUMERIC/%.txt,%,$(wildcard NUMERIC/*.txt))
TAGSDIR := tags
$(TAGSDIR):
@mkdir -p $@
# $(1): ALPHA
# $(2): NUM
define ALPHANUM_rule
$(TAGSDIR)/$(1).$(2).txt: ALPHABETIC/$(1).txt NUMERIC/$(2).txt | $(TAGSDIR)
@echo foo $(1).txt $(2).txt && \
touch $$@
all: $(TAGSDIR)/$(1).$(2).txt
endef
$(foreach a,$(ALPHA),$(foreach n,$(NUM),$(eval $(call ALPHANUM_rule,$(a),$(n)))))
还有两点需要理解:
- 使用空文件 (
$(TAGSDIR)/A.1.txt...
) 来跟踪已经完成的工作和时间。 - Order-only prerequisite
$(TAGSDIR)
用于保证包含空文件的目录在使用前创建,而不会在每次修改其内容时强制重新构建。