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

 唐古拉风情2502931431 发布于 2023-01-08 14:01

我正在尝试将一些复杂的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与使用参数运行命令相同.这就是为什么它似乎是"运行你的目录".bazVARIANTLIST_DETECTEDfoo

你可能想要这个:

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变量的意义.你永远不会对它们做任何事情.

1 个回答
  • 你需要退后一点,想想这里发生了什么:你似乎只是把东西扔到你的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与使用参数运行命令相同.这就是为什么它似乎是"运行你的目录".bazVARIANTLIST_DETECTEDfoo

    你可能想要这个:

    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变量的意义.你永远不会对它们做任何事情.

    2023-01-08 14:03 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有