使“ make”在一条规则中跟踪两个目录

时间:2018-07-16 10:55:40

标签: makefile gnu-make

我正在使用GNU Make,但如有必要,我愿意更改为其他内容。

我有两个目录 try { val df=spark.table("Hive Table") df.write.mode(SaveMode.Append).jdbc(jdbcURL, "TD Table", properties) }catch {case ex: Exception =><print error by calling getNextException repeatedly> ALPHABETIC,内容如下。

NUMERIC

和程序./ALPHABETIC: A.txt B.txt C.txt ./NUMERIC: 1.txt 2.txt 3.txt ,该程序将foo中的文件和ALPHABETIC中的文件作为输入并输出某些内容。

我要创建一个规则,使得:如果NUMERIC中的文件c发生了变化,请在ALPHABETIC上重新运行foo,并在{{1}中运行每个文件}。如果c中的文件NUMERIC发生了变化,请在nNUMERIC中的每个文件上重新运行foo

示例:n发生变化。然后应该发生的是:

ALPHABETIC

让我们说A.txt发生了变化。那应该发生的是

foo A.txt 1.txt
foo A.txt 2.txt
foo A.txt 3.txt

我尝试使用模式规则来执行此操作,但这没有用。

1 个答案:

答案 0 :(得分:1)

由于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)))))

请注意使用echotouch来模拟真实的foo命令的效果。要理解的最重要的事情是foreach-eval-call构造,包括某些$符号需要加倍($$)的原因。有关详细说明,请参见The eval Function中的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)用于确保包含空文件的目录是在使用前创建的,而不会在每次修改其内容时都强制重新构建。