我正试图将一些复杂的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
我有两个问题。首先,尽管通过$$cpu
对cpu
进行了双转义,但它在
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的最后两根荆棘。
谢谢!
引用
- 将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
,因为您不需要分配动态命名的变量。你可以直接写赋值。
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 );