Makefile:声明虚假目标为配方先决条件

Makefile:声明虚假目标为配方先决条件,makefile,Makefile,我的Makefile正在捆绑配方以并行处理大量文件(make-j8等)。但在处理文件之前,需要使用find找到它们。这是一个耗时的操作,所以我只想针对用户调用的确切配方运行它。我可以这样做: test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX)) test: $(FILES) $(FILES): echo "do thing with file $@ h

我的Makefile正在捆绑配方以并行处理大量文件(
make-j8
等)。但在处理文件之前,需要使用
find
找到它们。这是一个耗时的操作,所以我只想针对用户调用的确切配方运行它。我可以这样做:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
.PHONY: $(FILES)
test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: .PHONY: $(FILES)
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
FIND_FILES :=
FILES :=
ifneq ($(FIND_FILES),)
FILES := $(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
endif

test:
        $(MAKE) test-recurse FIND_FILES=1

test-recurse: $(FILES)
$(FILES):
        echo "do thing with file $@ here"
.PHONY: test test-recurse $(FILES)
问题在于,由于文件本身已经存在,因此需要将它们声明为
.PHONY
,以便运行配方,如下所示:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
.PHONY: $(FILES)
test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: .PHONY: $(FILES)
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
FIND_FILES :=
FILES :=
ifneq ($(FIND_FILES),)
FILES := $(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
endif

test:
        $(MAKE) test-recurse FIND_FILES=1

test-recurse: $(FILES)
$(FILES):
        echo "do thing with file $@ here"
.PHONY: test test-recurse $(FILES)
但是为了使其工作,需要存在并填充
FILES
变量,这需要我运行
find
命令。这违背了我的目标,即在调用
test
之前不执行搜索以查找
文件。我需要的是这样的东西:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
.PHONY: $(FILES)
test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: .PHONY: $(FILES)
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
FIND_FILES :=
FILES :=
ifneq ($(FIND_FILES),)
FILES := $(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
endif

test:
        $(MAKE) test-recurse FIND_FILES=1

test-recurse: $(FILES)
$(FILES):
        echo "do thing with file $@ here"
.PHONY: test test-recurse $(FILES)

但是
test:.PHONY:$(文件)
的语法无效,无法工作

即使没有
.PHONY
功能,您的makefile也无法工作;只是:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))

$(FILES):
        echo "do thing with file $@ here"
失败,因为当
make
在开始运行
test
目标之前解析makefile时,规则目标中的
$(FILES)
扩展为空字符串

我建议您在这里使用递归make;像这样编写makefile:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
.PHONY: $(FILES)
test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: .PHONY: $(FILES)
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
FIND_FILES :=
FILES :=
ifneq ($(FIND_FILES),)
FILES := $(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
endif

test:
        $(MAKE) test-recurse FIND_FILES=1

test-recurse: $(FILES)
$(FILES):
        echo "do thing with file $@ here"
.PHONY: test test-recurse $(FILES)

即使没有
.PHONY
这个东西,你的makefile也已经不能工作了;只是:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))

$(FILES):
        echo "do thing with file $@ here"
失败,因为当
make
在开始运行
test
目标之前解析makefile时,规则目标中的
$(FILES)
扩展为空字符串

我建议您在这里使用递归make;像这样编写makefile:

test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
.PHONY: $(FILES)
test: FILES=$(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
test: .PHONY: $(FILES)
test: $(FILES)
$(FILES):
    echo "do thing with file $@ here"
FIND_FILES :=
FILES :=
ifneq ($(FIND_FILES),)
FILES := $(shell find "$(SEARCHDIR)/" -mindepth 3 -maxdepth 3 -type f ! -regex $(SOMEREGEX))
endif

test:
        $(MAKE) test-recurse FIND_FILES=1

test-recurse: $(FILES)
$(FILES):
        echo "do thing with file $@ here"
.PHONY: test test-recurse $(FILES)

需要明确的是,您的
$(文件)
配方实际上不会生成特定于其目标的文件,对吗?@Beta-Correct。它实际上是在删除
文件中找到的文件,在其他情况下是将符号链接转换为文件等。需要明确的是,您的
$(文件)
配方实际上不会生成特定于其目标的文件,对吗?@Beta-Correct。它实际上是在删除
文件中找到的文件,在其他情况下将符号链接转换为文件,等等。FWIW,原因是我没有在递归生成的配方中使用
find
命令,如
$(make)test recursive files='$(shell…)
,因为您说过有很多文件,如果有很多文件,您可能会耗尽环境空间,递归make命令将无法工作。如果这还不足以引起关注,那么这样做并避免
FIND_文件
ifneq
肯定更简单、更清晰。我一直在寻找递归解决方案,但当我需要向原始命令传递额外的参数时,比如
make test-j4 ARG1=foo ARG2=bar…
等,然后我必须硬编码,将所有参数传递给递归的
$(MAKE)
调用?这里的答案似乎是:您不必执行任何操作。如果您使用
$(MAKE)
变量(或
${MAKE}
)调用它,所有命令行选项和重写都会自动神奇地提供给sub makes。我应该非常清楚:尽管所有命令行选项和变量重写都会自动提供给sub makes,但命令行上给出的目标不会传递给submakes(这没什么意义)。但既然这里您只想运行一个特定的目标,那应该没问题。FWIW,我之所以没有在递归make的配方中使用
find
命令,就像在
$(make)test recursive FILES='$(shell…)中一样“
,是因为您说过有很多文件,如果有很多文件可以在环境空间之外运行,那么递归make命令将不起作用。如果没有足够的内容来考虑这一点,那么执行此操作并避免
FIND_files
,而
ifneq
肯定更简单、更清晰。我一直在寻找g在递归解决方案中,但当我需要向原始命令传递额外的参数时,如
make test-j4 ARG1=foo ARG2=bar…
等,那么我必须硬编码,将所有参数传递给递归
$(make)
call?看起来答案就在这里:您不必执行任何操作。如果您使用
$(MAKE)
变量(或
${MAKE}
),所有命令行选项和覆盖都会自动神奇地提供给sub MAKE我应该非常清楚:虽然所有命令行选项和变量覆盖都自动提供给sub make,但命令行上给出的目标不会传递给submakes(这没有意义)。但是,既然这里您只想运行特定的目标,那就好了。