当eval创建规则时,Makefile中的目标顺序

时间:2015-04-18 15:56:17

标签: linux makefile

我写了一个Makefile,它使用与here类似的想法。也就是说,我定义了一组目录并使用foreachdefine我在每个目录中构建所有对象。这里我的Makefile看起来粗略

all_dirs := $(shell ...) # long shell command which finds all directories
all_objs := $(shell ...) # long shell command which finds all objects

define compile_rule
$(BUILDDIR)/$(1)/%.o :  $(1)/%.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@ -MD -MF $(@:.o=.dep)
endef

$(foreach dir,$(all_dirs:$(BUILDDIR)/%=%),$(eval $(call compile_rule,$(dir))))

all : program_name

program_name: $(all_objs)
    $(LD) -o $@ $(all_objs) $(LDFLAGS)

我总是使用make参数运行-j32命令。通常它工作正常但在某些情况下我从Makefile中得到一个错误,它自带No rule to make target $(all_objs)列表needed by program_name中的第一个目标文件名。

here问题很明显。由于我正在使用-j,因此似乎make命令在扩展program_name创建的规则之前开始评估foreach。我尝试在规则中编写foreach,以便保证program_nameforeach之间的执行顺序,但后来我收到错误prerequisites cannot be defined in recipes

知道如何解决这个问题吗?我或许可以使用两步制作来解决这个问题,即首先使用类似$(all_objs)的{​​{1}}构建make objs然后将其与make prog之类的内容链接在一起,但我更喜欢它在一个命令中发生,我有一种感觉,我想念一些简单的东西。请指教。

1 个答案:

答案 0 :(得分:2)

这可能有效,但我没有测试过:

# ...

prereq: $(foreach dir ...)

program_name: $(all_objs) | prereq
  $(LD) ...

似乎 来处理我的测试设置,但我只测试了一些目录和对象。管道是order-only prerequisite,看起来将for循环放在目标中是可以的。

<强>建议

如果您真的想要,可以下载GNU Make 3.82 source,使用patch < function.c.patch应用下面的补丁,然后使用make --debug=b -j32 ...调用make并注意Call,{{ 1}}和Evaluating行。

Executing

通过这种方式,如果--- function.c 2010-07-13 03:20:39.000000000 +0200 +++ function.c.patched 2015-04-18 20:41:15.000000000 +0200 @@ -1371,6 +1371,8 @@ install_variable_buffer (&buf, &len); + DB (DB_BASIC, (_("Evaluating: %s\n"), argv[0])); + eval_buffer (argv[0]); restore_variable_buffer (buf, len); @@ -1652,6 +1654,11 @@ return o; } + DB (DB_BASIC, (_("Executing shell command:"))); + for ( char **p=command_argv; *p!=NULL; ++p ) + DB (DB_BASIC, (_(" %s"), *p)); + DB (DB_BASIC, (_("\n"))); + # ifdef __EMX__ /* close some handles that are unnecessary for the child process */ CLOSE_ON_EXEC(pipedes[1]); @@ -2311,6 +2318,12 @@ --cp; cp[1] = '\0'; + DB (DB_BASIC, (_("Call %s:"), fname)); + for ( char **p=argv; *p!=NULL; ++p ) + DB (DB_BASIC, (_(" %s"), *p)); + DB (DB_BASIC, (_("\n"))); + + /* Calling nothing is a no-op */ if (*fname == '\0') return o; 运行时,您实际上可以查看。在我的例子中,输出是:

call compile_rule