我正在尝试将一些复杂的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
,它在行中转换为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完成的最后两个刺.
谢谢!
参考
将makefile变量值分配给bash命令结果?,访问2014-06-19,
MadScientist.. 5
你需要退后一点,想想这里发生了什么:你似乎只是把东西扔到你的makefile中,并希望结果是你想要的,而不是真正了解正在发生的事情,并着手解决你的问题.
首先要理解的是make如何调用配方:首先,make 扩展配方.扩展意味着查看配方文本并查找以a开头的任何内容$
并将其视为make函数或变量,并对其进行求值.因此,$$
转换为单个$
,$(CPU_LIST_DETECTED)
扩展为该变量的值,并且$(shell ....)
是一个运行的make函数,结果包含在配方文本中.也许你已经可以看到你的食谱出错了...
然后,在扩展了所有配方之后,make获取配方的扩展文本并将其传递给shell.Make然后等待shell完成,并查看shell的退出代码.如果是0
,那么配方成功并继续.如果不是0
,则配方失败并退出并显示错误.make和shell之间没有交互,除了make以脚本运行启动它,然后返回退出代码.如果你以前不能,也许你现在可以看到你的食谱出错了.
在配方中使用函数几乎总是一个错误(或者至少是不必要的)$(shell ...)
...配方已经在shell中运行了!您不需要make先运行另一个shell,然后将这些结果提供给新的shell.
你的shell调用试图使用shell变量$cpu
.但是当make运行$(shell ...)
函数时,这个变量在这里没有任何价值,因为make 在启动shell脚本之前运行该函数.你的make函数中没有东西可以引用在配方运行之前不会定义的东西.这将运行shell脚本2>&1 find ./.build/linux/$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' | grep -v warning
,但shell变量cpu
未设置,因此find将通过其下的所有内容进行递归./.build/linux/
.
其次,你在eval
这里滥用.shell函数扩展为单词列表,比如foo bar baz.然后eval
看起来像这样:
eval VARIANTLIST_DETECTED=foo bar baz
这与写这个是一样的:
VARIANTLIST_DETECTED=foo bar baz
在将变量设置为值后,bar
与使用参数运行命令相同.这就是为什么它似乎是"运行你的目录".baz
VARIANTLIST_DETECTED
foo
你可能想要这个:
VARIANTLIST_DETECTED="foo bar baz"
(注意引用).但是,通过a获取引用是eval
很棘手的"你必须逃避它们.幸运的是,你根本不需要eval
这里,因为你没有尝试分配一个动态命名的变量.你可以直接编写赋值.
因此,丢失shell函数和eval,应写入该行:
VARIANTLIST_DETECTED=`2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' | grep -v warning`; \
同样的回声:你不需要eval
那里.
但是,我真的没有看到设置这个变量或variant_$cpu
变量的意义.你永远不会对它们做任何事情.
你需要退后一点,想想这里发生了什么:你似乎只是把东西扔到你的makefile中,并希望结果是你想要的,而不是真正了解正在发生的事情,并着手解决你的问题.
首先要理解的是make如何调用配方:首先,make 扩展配方.扩展意味着查看配方文本并查找以a开头的任何内容$
并将其视为make函数或变量,并对其进行求值.因此,$$
转换为单个$
,$(CPU_LIST_DETECTED)
扩展为该变量的值,并且$(shell ....)
是一个运行的make函数,结果包含在配方文本中.也许你已经可以看到你的食谱出错了...
然后,在扩展了所有配方之后,make获取配方的扩展文本并将其传递给shell.Make然后等待shell完成,并查看shell的退出代码.如果是0
,那么配方成功并继续.如果不是0
,则配方失败并退出并显示错误.make和shell之间没有交互,除了make以脚本运行启动它,然后返回退出代码.如果你以前不能,也许你现在可以看到你的食谱出错了.
在配方中使用函数几乎总是一个错误(或者至少是不必要的)$(shell ...)
...配方已经在shell中运行了!您不需要make先运行另一个shell,然后将这些结果提供给新的shell.
你的shell调用试图使用shell变量$cpu
.但是当make运行$(shell ...)
函数时,这个变量在这里没有任何价值,因为make 在启动shell脚本之前运行该函数.你的make函数中没有东西可以引用在配方运行之前不会定义的东西.这将运行shell脚本2>&1 find ./.build/linux/$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' | grep -v warning
,但shell变量cpu
未设置,因此find将通过其下的所有内容进行递归./.build/linux/
.
其次,你在eval
这里滥用.shell函数扩展为单词列表,比如foo bar baz.然后eval
看起来像这样:
eval VARIANTLIST_DETECTED=foo bar baz
这与写这个是一样的:
VARIANTLIST_DETECTED=foo bar baz
在将变量设置为值后,bar
与使用参数运行命令相同.这就是为什么它似乎是"运行你的目录".baz
VARIANTLIST_DETECTED
foo
你可能想要这个:
VARIANTLIST_DETECTED="foo bar baz"
(注意引用).但是,通过a获取引用是eval
很棘手的"你必须逃避它们.幸运的是,你根本不需要eval
这里,因为你没有尝试分配一个动态命名的变量.你可以直接编写赋值.
因此,丢失shell函数和eval,应写入该行:
VARIANTLIST_DETECTED=`2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' | grep -v warning`; \
同样的回声:你不需要eval
那里.
但是,我真的没有看到设置这个变量或variant_$cpu
变量的意义.你永远不会对它们做任何事情.