GNU Make -在规则/目标中设置shell命令输出中的MAKEFILE变量



我正试图将一些复杂的makefile规则放在一起,以自动构建针对多个编译器的项目。我有一个规则,它创建了一些动态生成的变量,并将变量赋值给它们,然后将这些变量传递给一个调用,以构建一个单独的规则。

.PHONY: all
all:
    @echo "Detected CPULIST:${CPULIST_DETECTED}"
    @echo "CPULIST:${CPULIST}"
    @for cpu in $(CPULIST_DETECTED); do                   
        echo "CPU:$${cpu}:";                                
        eval VARIANTLIST_DETECTED=$(shell 2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '.svn' |  grep -v warning ); 
        eval echo "Detected Variant List:$${VARIANTLIST_DETECTED}"; 
        eval variant_$${cpu}=$${cpu};                      
        eval echo "variant_$${cpu}:$${variant_$${cpu}}"; 
        $(MAKE) build CPULIST=$${cpu};                     
    done
.PHONY: build
build: sanity_check $(TARGET)
    @true

我有两个问题。首先,尽管通过$$cpucpu进行了双转义,但它在

行中转换为null:
eval VARIANTLIST_DETECTED=$(shell 2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '.svn' |  grep -v warning ); 

因此,find命令在循环的每次迭代中查找./.build/linux/,而不是像我期望的那样遍历./.build/linux/arm./.build/linux/x86。我在下面的参考资料中包含了一篇文章。我怀疑这可能会导致问题,因为我是在规则本身而不是在makefile的全局赋值部分(在规则之前)中尝试这样做的。

另一个问题正好发生在同一行。似乎shell命令被评估,分配给VARIANTLIST_DETECTED,但随后VARIANTLIST_DETECTED被执行,好像它是一个命令,因为我在构建期间得到以下错误:

Detected CPULIST:arm x86
CPULIST:
CPU:arm:
/bin/sh: 3: ./.build/linux/x86: Permission denied
Detected Variant List:
variant_arm:arm

它试图运行我的查询中的第一个结果,就好像它是一个命令。这一行也应该是./.build/linux/x86/so

我如何着手解决这两个问题?它们是阻碍我完成makefile的最后两根荆棘。

谢谢!

引用

  1. 将makefile变量值分配给bash命令结果?, 2014-06-19发布,<https://stackoverflow.com/questions/2373081/assign-a-makefile-variable-value-to-a-bash-command-result>

您需要退一步思考一下这里发生了什么:您似乎只是将一些东西扔进makefile并希望结果是您想要的,而不是真正理解发生了什么并以解决问题的目的继续进行。

首先要理解的是make如何调用菜谱:首先,make 展开菜谱。展开意味着make查看食谱的文本,找到任何以$开头的内容,并将其视为make函数或变量,并对其求值。因此,$$被转换为单个$, $(CPU_LIST_DETECTED)被扩展为该变量的值,$(shell ....)是运行的make函数,结果包含在配方文本中。也许你已经知道你的食谱哪里出错了…

然后,在所有的都被展开之后,make获取展开的食谱文本并将其传递给shell。Make然后等待shell完成,并查看shell的退出代码。如果是0,则配方成功,继续制作。如果它不是0,则配方失败并以错误退出。make和shell之间没有交互,除了make用一个脚本启动它,并返回退出代码。如果你以前不知道,也许你现在可以看到你的食谱哪里出错了。

实际上总是在配方中使用$(shell ...)函数是错误的(或者至少是不必要的)…食谱已经在蛋壳里运行了!您不需要先运行另一个shell,然后将这些结果提供给新shell。

您的shell调用正在尝试使用shell变量$cpu。但是,当make运行$(shell ...)函数时,该变量在这里没有值,因为make在启动shell脚本之前运行该函数。在make函数中不能有引用直到recipe运行时才定义的东西的东西。这将运行shell脚本2>&1 find ./.build/linux/$cpu -mindepth 1 -maxdepth 1 | grep -v '.svn' | grep -v warning,但没有设置shell变量cpu,因此查找将递归地遍历./.build/linux/下的所有内容。

第二,你在这里误用了eval。shell函数展开为一个单词列表,例如foo bar baz。然后eval看起来像这样:
eval VARIANTLIST_DETECTED=foo bar baz

等于这样写:

VARIANTLIST_DETECTED=foo bar baz

,这与将变量VARIANTLIST_DETECTED设置为值foo后,以参数baz运行bar相同。这就是为什么它看起来像"运行你的目录"。

你可能想要这个:

VARIANTLIST_DETECTED="foo bar baz"

(注意引号)。然而,通过eval获取引号是很棘手的,你必须转义它们。幸运的是,这里根本不需要eval,因为您不需要分配动态命名的变量。你可以直接写赋值。

因此,去掉shell函数和eval,这一行应该写为:
VARIANTLIST_DETECTED=`2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '.svn' |  grep -v warning`; 

对于echo也是一样:这里不需要eval

然而,我真的不明白设置这个变量或variant_$cpu变量的意义。你从来没有和他们做过任何事情。

一般情况下,尽量避免在命令中使用Make语法。试试这个:

VARIANTLIST_DETECTED=$$(find ./.build/linux/$${cpu} -mindepth 1 -maxdepth 1 | grep -v '.svn' |  grep -v warning );

最新更新