Makefile将命令输出分配给变量

Makefile将命令输出分配给变量,makefile,Makefile,我有一个压缩css文件并输出输出文件名的脚本。 我正在尝试构建一个makefile来自动化该过程: all: @echo "Compiling CSS" CSS_OUTPUT=$(shell php minify_css.php ) echo $(CSS_OUTPUT) 我试图将输出文件名存储在CSS_输出变量中,但我做错了,因为整个makefile只是打印: $ make abcdefg.css Compiling CSS CSS_OUTPUT= echo 因此,

我有一个压缩css文件并输出输出文件名的脚本。
我正在尝试构建一个makefile来自动化该过程:

all:
    @echo "Compiling CSS"
    CSS_OUTPUT=$(shell php minify_css.php )
    echo $(CSS_OUTPUT)
我试图将输出文件名存储在CSS_输出变量中,但我做错了,因为整个makefile只是打印:

$ make
abcdefg.css
Compiling CSS
CSS_OUTPUT=
echo 
因此,输出未分配给
CSS\u输出
。另外,为什么php输出会在
@echo“编译CSS”
之前打印

我试过这个:

all:
    @echo "Compiling CSS"
    CSS_OUTPUT=$(shell echo php minify_css.php )
    echo $(CSS_OUTPUT)
但情况只会变得更糟:

$ make
Compiling CSS
CSS_OUTPUT=php minify_css.php
./minify_css.php: line 1: ?php: No such file or directory
./minify_css.php: line 3: syntax error near unexpected token `dirname'
./minify_css.php: line 3: `require_once( dirname(__FILE__) . DIRECTORY_SEPARATOR . 'maintenance.php' );'
make: *** [css] Error 2
编辑 根据评论中提供的答案,建议使用eval:

@echo "Compiling CSS"
$(eval CSS_OUTPUT:=$(shell php minify_css.php))
echo ${CSS_OUTPUT}
产出:

make: *** No targets specified and no makefile found.  Stop.

分两个阶段制作作品。首先,它读取makefile,计算变量并构建依赖关系图。使函数在此阶段也得到评估。在第二阶段,它执行必要的配方来更新主目标。这意味着
$(shell…
函数调用在任何配方运行之前的第一阶段得到扩展。命令的输出代替了shell函数调用,但我怀疑php命令的输出不会转到STDOUT,因此,不是以
CSS\u output=abcdefg.CSS
(这就是您想要的)结束,
abcdefg.CSS
会回显到屏幕上,shell函数的结果是空的

接下来将执行配方,但完成后,每一行都在一个单独的shell实例中运行,因此配方中不同行上的命令无法访问另一行上设置的shell变量(由于前面的问题,在本例中这将是无用的)。对付这种情况的一种方法是用分号和反斜杠将这些行粘在一起。现在,它们在单个shell实例中作为一行执行

另一个问题是,在配方的最后一行中,您没有引用shell变量(这就是CSS_输出),而是引用从未设置过的makefile变量

你有没有理由不这样做:

all:
    @echo "Compiling CSS"
    php minify_css.php
问题与解决方案 我自己也遇到过同样的问题。我已经找到了一种方法来解决这个问题,但肯定不是很理想

如上所述,问题归结为执行
$(shell)
命令的时间。它是在计算makefile变量时执行的,这是在解析或处理任何目标之前。为了解决这个问题,您可以将
$(shell)
命令断开,在单独调用makefile时执行。为了增加技巧,我只是为同一个文件中的所有后期文件创建工作创建了一个“隐藏”目标,并对同一个makefile进行了递归make调用。结果如下所示:

override MY_MAKEFILE:=$(MAKEFILE_LIST)
override MY_MAKE_INVOCATION_CMD_LINE:=$(MAKE) -C $(CURDIR) $(if $(MY_MAKEFILE),-f $(MY_MAKEFILE),) --no-print-directory

all: minify_css.php
    @echo "Compiling CSS"
    @$(MY_MAKE_INVOCATION_CMD_LINE) all_hid

minify_css.php:
    <create the minify_css.php file here>    

all_hid:
    @$(MY_MAKE_INVOCATION_CMD_LINE) print_css_hid CSS_OUTPUT=$(shell php minify_css.php )

print_css_hid :
    echo $(CSS_OUTPUT)
覆盖我的生成文件:=$(生成文件列表)
重写MY_MAKE_调用_CMD_行:=$(MAKE)-C$(CURDIR)$(如果$(MY_MAKEFILE),-f$(MY_MAKEFILE),)--无打印目录
全部:minify_css.php
@echo“编译CSS”
@$(我的生成调用命令行)所有隐藏
minify_css.php:
所有人:
@$(MY_MAKE_INVOCATION_CMD_LINE)print_css_hid css_OUTPUT=$(shell php minify_css.php)
打印\u css\u隐藏:
echo$(CSS_输出)
解释 覆盖命令 第一行强制设置一个不能从命令行重写的变量来收集makefile的名称。第一行必须被称为makefile中的绝对第一行,因为包含其他makefile会改变这一点,并且它在包含的makefiles中不起作用。值得注意的是,如果您没有在命令行上指定makefile,那么它将是空的,这意味着当从makefile中调用它时,可以以相同的方式调用它

第二行只是通过设置一些默认选项来构造对makefile的调用,例如更改到最初调用makefile命令行的当前目录,并且仅包括在原始调用中包含的makefile的规范

请注意,前两行目前在我的构建系统中实现,因此它们实际上适用于对同一makefile的多个嵌套递归调用

递归调用 以下两行是回答原始查询的重要行。为了演示文件创建,而不仅仅是使用shell命令的返回,我假设您的文件还需要创建
minify_css.php
文件。当我为target
all\u hid
递归调用makefile时,我知道目标
all
正在被评估。这意味着
minify_css.php
依赖项已经被处理,因此我可以保证它已经存在,这一假设允许在对makefile的第一次递归调用中计算
$(shell php minify_css.php)
命令,并对生成的文件进行操作。下一步是收集
CSS\u输出值
并将其放入另一个递归调用中。为此,我再次从一个已经递归的调用中递归调用makefile,并在命令行上传递它。请记住,在调用makefile期间,只有您显式导出的变量在sub make中可用,因此我们不能只设置它,然后在下一行进行递归调用,它实际上必须作为命令行的一部分传递。在下一级递归makefile中,当我们调用
print\u css\u hid
目标时,该变量似乎是从命令行设置的,可以使用

分包考虑 在本例中,您实际上是在递归地调用自己的makefile,因此需要注意的是,所有其他变量都没有正确设置。幸运的是,这没有发生。传递给原始命令行的选项的任何命令行值都会自动提供给从文件中调用的make的每个子调用。因为在makefile中唯一能影响变量构造的输入源是