Makefile将命令输出分配给变量

时间:2012-01-31 15:08:35

标签: makefile

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

all:
    @echo "Compiling CSS"
    CSS_OUTPUT=$(shell php minify_css.php )
    echo $(CSS_OUTPUT)

我正在尝试将输出文件名存储在CSS_OUTPUT变量中,但我做错了,因为整个makefile只是打印出来:

$ make
abcdefg.css
Compiling CSS
CSS_OUTPUT=
echo 

因此输出未分配给CSS_OUTPUT。另外,为什么在@echo "Compiling CSS"之前打印php输出?

我试过这个:

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.

2 个答案:

答案 0 :(得分:11)

分两个阶段进行工作。首先,它读入makefile,评估变量并构建依赖图。在此阶段还要对功能进行评估。在第二阶段,它执行必要的配方来更新主目标。这意味着$(shell ...)函数调用在第一阶段,任何配方运行之前都会被扩展。该命令的输出代替shell函数调用,但我怀疑php命令的输出没有转到STDOUT,所以不是以CSS_OUTPUT=abcdefg.css结束(这可能是你想要的),{ {1}}回显到屏幕,shell函数的结果为空。

接下来执行配方,但是当这样做时,每一行都在一个单独的shell实例中运行,因此配方中不同行上的命令无法访问另一行上设置的shell变量(这对于无论如何,这个案子,因为上一期)。解决这个问题的一种方法是通过用分号和反斜杠结束线将它们粘合在一起。现在,它们在单个shell实例中作为一行执行。

另一个问题是,在配方的最后一行,你没有引用shell变量(这是CSS_OUTPUT是什么),而是引用了一个从未设置过的makefile变量。

你有没有理由不这样做:

abcdefg.css

答案 1 :(得分:3)

问题&溶液

我自己遇到了同样的问题。我找到了解决它的方法,但它肯定不太理想。

如上所述,问题归结为执行$(shell)命令的时间。它是在评估makefile变量时执行的,这是在解析或处理任何目标之前。要解决此问题,可以将$(shell)命令分解为单独调用makefile。为了变得棘手,我只是为同一个文件中的所有后期文件创建工作创建了一个“隐藏”目标,并对我的同一个makefile进行了递归调用。结果看起来像这样:

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)

说明

覆盖命令

此句柄的第一行强制设置一个无法从命令行覆盖的变量来收集makefile的名称。第一行必须作为makefile中的绝对第一行调用,因为包含其他makefile可以改变它,并且它不能在包含的makefile中工作。值得注意的是,如果你没有在命令行中指定一个makefile,这将是空的,这意味着当从makefile中调用它时,它可以被调用相同的方式。

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

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

递归召唤

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

子制作注意事项

在这种情况下,您实际上是以递归方式调用自己的makefile,因此需要注意的是所有其他变量都没有正确设置。幸运的是,这不会发生。传递给原始命令行的选项的任何命令行值都会自动提供给从文件中调用的make的每个子调用。因为可以影响makefile中变量构造的唯一输入源是你正在操作的目录的内容,命令行设置,调用makefile的目录,以及makefile本身的设置,你只需要在嵌套调用期间,确保您没有意外地将新生成的文件包含在“源”列表中,并且可以保证环境设置相同。