【问题标题】:Re-evaluating GNU make makefile variable重新评估 GNU make makefile 变量
【发布时间】:2019-05-14 05:17:12
【问题描述】:

我继承了一个大型的分支项目?这需要将一组易失的 .a 档案 $(LIB_FILES) 包含在链接目标中,该链接目标位于某些目录 $(LIB_DIRS) 中。我可以这样写一个表达式:

LIBDEP = $(foreach ldir, $(LIB_DIRS), \
    $(filter $(addprefix %/, $(LIB_FILES)), $(wildcard $(ldir)/* )))

问题是它们可能在 make 调用时不存在,而是通过在另一个目标的规则中调用 $(MAKE) 来构建,这是链接步骤的先决条件。

问题是应该创建的文件的实际列表因构建步骤中确定的外部因素而异,我无法正确地对其进行硬编码,而不会将 makefile 变成意大利面条式的混乱,并且不会重新评估所述变量在链接命令调用的那一刻。

我怀疑 $(eval ) 函数可以以某种方式使用,但是手册不是很及时,而且我没有找到以这种方式使用它的示例。

工具链:GCC 和 binutils,制作 3.81

【问题讨论】:

  • 你的意思是,它出现在链接规则的先决条件中?
  • @Vroomfondel no,作为命令的参数
  • 看到您的回复为时已晚 - 虽然我的回答有效,但我认为您的问题出在其他地方。您正在使用一个递归变量,该变量仅在使用时才会扩展 - 因此,如果在调用链接命令时存在错误/缺失的库,那么 there are 错误/缺失的库。
  • 另一种可能性是您的 makefile 对自己撒谎,并且链接时 $(LIB_FILES) 的内容并没有真正显示要链接的内容。
  • @Vroomfondel 不,它没有,libfiles 是可能的文件名列表,但没有信息可能是它们的确切位置(不是完整路径,同名文件可能存在于多个目录中)。它总是在第二次运行时正确链接。这是一个带有自注册子系统的有点奇怪的 ECS 架构。复制粘贴而不寻找后果的程序员的遗产

标签: makefile gnu-make


【解决方案1】:

另一个解决方案是在当前创建变量 $(LIB_FILES) 的步骤的输出上创建 make 脚本的显式依赖关系。这是手册在How makefiles are remade 章节中处理的内容,它针对的是 make 最擅长的技术,即从文件的存在和时间戳(而不是变量)派生依赖关系。下面希望通过推导由两个变量 $(LIBS_THIS_TIME)$(LIB_CONFIG_SET) 模拟的一组新库的过程来描述您的情况。

LIBS_THIS_TIME = foo.a:baz.a:bar.a
LIB_CONFIG_SET = $(subst :,_,$(LIBS_THIS_TIME))

include libdeps.d

linkstep:
    @echo I am linking $^ now
    touch $@

libdeps.d: $(LIB_CONFIG_SET)
    -rm libdeps.d
    $(foreach lib,$(subst :, ,$(LIBS_THIS_TIME)),echo linkstep: $(lib) >> libdeps.d;)

$(LIB_CONFIG_SET):
    touch $@

如果 make 发现 libdeps.d 不是最新的到您当前的库配置,它会在 make 执行任何其他规则之前重新制作,尽管它不是 makefile 中的第一个目标。这样,如果您的构建过程创建了一组新的或不同的库,libdeps.d 将首先被重新制作,然后 make 将继续使用您的顶级 makefile 中的其他目标,现在具有正确的依赖信息。

【讨论】:

  • 如果 make 发现 libdeps.d 已更新,我是否理解正确?好奇,你提供的链接还提到了我不知道的双冒号规则。
  • 是的,首先查看它included(加上它自己)的任何文件是否是目标。我认为这是为了促进平稳的自动依赖生成周期而引入的。
【解决方案2】:

有时您需要连续多次调用 make。这样做的一种可能性是使用条件:

ifeq ($(STEP),)
all:
    <do-first-step>
    $(MAKE) STEP=2 $@
else ifeq ($(STEP),2)
all:
    <do-second-step>
    $(MAKE) STEP=3 $@
else ifeq ($(STEP),3)
all:
    <do-third-step>
endif

在每个步骤中,您都可以生成新文件并让它们存在以供下一步使用。

【讨论】:

  • 那不是STEP=2 $(MAKE) 传递变量STEP吗?我知道递归制作,只是意识到“环境污染”和高内存使用\性能。是的,我正处于重要的阶段\情况。
  • STEP=2 $(MAKE) 设置 shell 环境变量,就像$(MAKE) 之外的任何其他 shell 命令一样。 $(MAKE) STEP=2 设置 make 变量。在大多数情况下,结果是相同的,因为 make 将环境变量视为 make 变量,并且在执行配方时,它会将 make 变量作为环境变量传递给 shell。
  • 但是存在差异。默认情况下,命令行上传递的 make 变量 ($(MAKE) STEP=2) 会覆盖 makefile 中定义的变量,但环境变量不会(您可以更改此行为)。因此,如果您在 makefile 中添加一行 STEP := 4$(MAKE) STEP=2STEP=2 $(MAKE) 的行为将不同。
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多