【问题标题】:Order of targets in Makefile when rule created by evaleval 创建规则时 Makefile 中的目标顺序
【发布时间】:2015-04-19 02:45:31
【问题描述】:

我编写了一个 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)

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

here 问题就清楚了。由于我使用的是-j,因此make 命令似乎在扩展foreach 创建的规则之前开始评估program_name。我尝试在规则中编写foreach,这样我可以保证program_nameforeach 之间的执行顺序,但随后出现错误prerequisites cannot be defined in recipes

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

【问题讨论】:

  • 如果使用 GNU make 4,您可以使用其 Guile 可脚本性功能。

标签: linux makefile


【解决方案1】:

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

# ...

prereq: $(foreach dir ...)

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

似乎在我的测试设置上工作,但我只测试了几个目录和对象。管道是order-only prerequisite,看起来可以把for循环放到一个target里面。

建议

如果你真的想要,你可以下载GNU Make 3.82 source,使用patch &lt; function.c.patch 应用下面的补丁,然后使用make --debug=b -j32 ... 调用make 并注意CallEvaluatingExecuting 行。

--- 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 是否在不应该运行的情况下运行。就我而言,输出是:

GNU Make 3.82
Built for x86_64-apple-darwin14.3.0
Copyright (C) 2010  Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Executing shell command: find . -type d
Call compile_rule: compile_rule .
Evaluating: ./%.foo: ./%.txt
    @echo build $@ from $<
Call compile_rule: compile_rule ./1
Evaluating: ./1/%.foo: ./1/%.txt
    @echo build $@ from $<
Call compile_rule: compile_rule ./2
Evaluating: ./2/%.foo: ./2/%.txt
    @echo build $@ from $<
Updating goal targets....
 File `program' does not exist.
   File `1/1.foo' does not exist.
  Must remake target `1/1.foo'.
Invoking recipe from Makefile:11 to update target `1/1.foo'.
   File `2/2.foo' does not exist.
  Must remake target `2/2.foo'.
Invoking recipe from Makefile:11 to update target `2/2.foo'.
   File `prereq' does not exist.
  Must remake target `prereq'.
  Successfully remade target file `prereq'.
build 1/1.foo from 1/1.txt
 File `program' does not exist.
build 2/2.foo from 2/2.txt
 File `program' does not exist.
Must remake target `program'.
Invoking recipe from Makefile:9 to update target `program'.
link program w/args 1/1.foo 2/2.foo

【讨论】:

  • 不幸的是,同样的问题存在。当你说它对你有用时,我相信你,它也对我有用,但并非总是如此。我在 AWS EC2 服务上编译我的程序,大部分时间实例都关闭了。当我想编译时,我有一个 python 脚本(使用boto)打开实例并运行make -j32 命令。在打开实例的第一次编译时,几乎每次都会重现此问题。如果您有更好的想法,请告诉我。
  • 您使用哪个版本的 GNU?
  • 尝试使用 -d 标志运行 make 命令。它应该打印出很多调试信息,这些信息也许可以用来查看为什么会发生这种情况。
  • 所以-d 加上将输出重定向到文件解决了这个问题(间接)我猜是因为将调试信息写入文件所需的时间允许 Makefile 解决所有规则。这当然不是我一直在寻找的解决方案,但它确实有帮助 :-) 最后我非常感谢您花时间让我知道您对我的 Makefile 问题的看法。
  • 作为最后的评论,我想说这个问题主要(但不仅)在系统启动时重现。我想在启动时会满足一些条件,这比在系统的其余时间运行时更容易产生这个问题。但是,在研究了这个问题一周之后,我承认我一无所知。我能想到的唯一真正的解决方案是明确编写所有规则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 2014-01-23
相关资源
最近更新 更多