Makefile 制造;制造;在一个规则中更改跟踪两个目录

Makefile 制造;制造;在一个规则中更改跟踪两个目录,makefile,gnu-make,Makefile,Gnu Make,我正在使用GNU Make,但如果需要,我愿意更改为其他版本 我有两个目录字母和数字,内容如下 ./ALPHABETIC: A.txt B.txt C.txt ./NUMERIC: 1.txt 2.txt 3.txt 以及一个程序foo,它将字母中的一个文件和数字中的一个文件作为输入,并输出一些东西 我想创建这样一个规则:如果字母中的文件c发生更改,请在c上重新运行foo,并在数字中重新运行每个文件。如果n中的文件NUMERIC发生更改,请在n上重新运行foo,并按字母顺序运行中的每

我正在使用GNU Make,但如果需要,我愿意更改为其他版本

我有两个目录
字母
数字
,内容如下

./ALPHABETIC:
A.txt  B.txt  C.txt

./NUMERIC:
1.txt  2.txt  3.txt
以及一个程序
foo
,它将
字母中的一个文件和
数字中的一个文件作为输入,并输出一些东西

我想创建这样一个规则:如果
字母
中的文件
c
发生更改,请在
c
上重新运行
foo
,并在
数字
中重新运行每个文件。如果
n
中的文件
NUMERIC
发生更改,请在
n
上重新运行
foo
,并按字母顺序运行
中的每个文件

示例:
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
构造,包括一些
$
符号需要加倍的原因(
$
)。有关详细说明,请参见中的

演示(
host>
是shell提示符):

但是如果
fooa.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…
    )来跟踪已经完成的工作和时间
  • $(TAGSDIR)
    用于确保包含空文件的目录在使用前创建,而不会在每次修改其内容时强制重新生成

  • foo A.txt 1.txt
    是否生成一个输出文件,其名称将其标识为
    A
    1
    的产品?这将节省一些工作…很好的答案+100
    .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)))))