【问题标题】:Makefile evaluation question - foreach list doesnt evaluate before executionMakefile 评估问题 - foreach 列表在执行前不评估
【发布时间】:2019-03-29 16:20:09
【问题描述】:

这是来自 Makefile 的一个 sn-p,它在我的环境中是递归的,而且这段代码似乎有一个问题,我不明白为什么 foreach 不评估。变量 TOOLVERSION 和 TOOLSDIR 是根据运行 Ruby 脚本分配的值。这些提供了 C_FLAGS 的包含路径。目标 test2 产生正确的结果,其中以空格分隔的 C_FLAGS 的每个元素都出现在新行上,这是所需的结果。但是 test1 不评估 TOOLVERSION 和 TOOLSDIR 所以会产生垃圾。如果我使用 $(shell getenvval.rb version) 分配 TOOLVERSION 和 TOOLSDIR foreach 工作,但运行脚本的值不正确。我认为这是因为在 Makefile 环境中定义的东西没有进入 shell,所以我使用了 export 但它没有任何区别。

所以问题归结为为什么以下 foreach 循环不起作用:

@$(foreach flag, $(C_FLAGS), `echo  $(flag) >> $(FILE_C1_LIST)`)

虽然这有效:

@echo $(C_FLAGS) >> $(FILE_C2_LIST) 

感谢任何有助于理解评估的帮助。

来自 Makefile 的片段:

export 


TOOLVERSION:= `getenvval.rb version`
TOOLSDIR:=  `getenvval.rb directory`

FILE_C1_LIST := test_c1.f
FILE_C2_LIST := test_c2.f

C_FILES =\
./a.c            \
./b.c             

C_FLAGS := \
-I$(TOOLSDIR)/$(TOOLVERSION)/tools/include \
-I./aa/include \
-I./bb/editline \
-g -DDEBUG   -DPLISIM -DINCLUDE_EDITLINE -DSYS_UNIX 

$(FILE_C1_LIST): $(C_FILES) 
    rm -f $(FILE_C1_LIST) 
    touch $(FILE_C1_LIST) 
    @(echo $(C_FLAGS) )
    @$(foreach flag, $(C_FLAGS), `echo  $(flag) >> $(FILE_C1_LIST)`)
    @$(foreach file, $(C_FILES), `echo $(file) >> $(FILE_C1_LIST)` ) 

$(FILE_C2_LIST): $(C_FILES) 
    @rm -f $(FILE_C2_LIST) 
    @touch $(FILE_C2_LIST) 
    @echo $(C_FLAGS) >> $(FILE_C2_LIST) 
    @$(foreach file, $(C_FILES), `echo $(file) >> $(FILE_C2_LIST)` ) 



test1:  $(FILE_C1_LIST)

test2: $(FILE_C2_LIST)

【问题讨论】:

  • 在您尝试调试的命令前面加上@ 是非常错误的。完成后可能不要将其放回原处(如果您希望它安静地运行,请使用make -s)。
  • 您似乎在想象foreach 函数会以某种方式执行您给它的命令。那不是它的作用。 foreach 是一个文本修改工具。在 foreach 完成后,它会评估该扩展的结果。它实际上不会尝试执行任何shell操作。

标签: shell foreach makefile gnu


【解决方案1】:

你的期望很奇怪。您似乎尝试在不会由 shell 评估的结构中使用 shell 语法;即使它们是,表达式也不会在语法上有效。

不要过多研究细节,试试这个。

    printf '%s\n' $(C_FLAGS) >> $(FILE_C1_LIST)

更详细地说,您的循环将创建文本

    `echo one >>file` `echo two >>file` `echo three >>file`

其中的反引号表示echo 的输出应该是您希望shell 执行的命令的文本;但当然,由于重定向,这些命令中的任何一个都不会输出到标准输出。 (将所有命令放在一行的表面问题可以通过在每个命令后加分号来解决。)

另外,无需rmtouch 将要覆盖的文件。就写吧。您的食谱可以大大简化。

$(FILE_C1_LIST): $(C_FILES)
    printf '%s\n' $(C_FLAGS) $(C_FILES) >$@

$(FILE_C2_LIST): $(C_FILES) 
    echo $(C_FLAGS) >$@
    printf '%s\n' $(C_FILES) >>$@

第一个 echo 周围的括号会不必要地在单独的子 shell 中运行它。我猜你纯粹是为了看看你在做什么。删除食谱上的@ 效果会更好。调试和排序所有内容后,您可以使用 make -s 静默运行 make

【讨论】:

  • 感谢您的回复。 printf 有效,但我希望有一种方法可以使 foreach 工作,并且正如您所指出的,因为重定向它不会被评估,除非我有一个“;”在命令之间,但我认为 foreach 语法不允许这样做。
  • 为什么不呢? $(foreach flag,$(C_FLAGS),echo $(flag) >>$(FILE_C1_LIST);)
  • 试过了,但它没有评估 C_FLAGS 并且 $flag 是作为用于评估 TOOLSDIR 和 TOOLVERSION 的命令本身出现的
  • 为我工作 (demo);但相信我,printf 方法更好。
猜你喜欢
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
相关资源
最近更新 更多