make 在执行的时候是分成两个阶段的, 第一阶段叫读入阶段, 第二阶段是更新目标阶段
在第一阶段, make读入include等文件, 并对变量进行替换, 展开隐式规则等, 这一阶段就是生成合适makefile的过程
在第二阶段是执行阶段, 根据第一阶段生成的makefile, 根据规则对需要更新的目标进行更新
但如果在规则下面的命令中, 用到了循环, 则会涉及到二次展开的问题, 所谓二次展开就是在第二阶段再展开一次
比如下面的例子:
由于在规则下面的命令只能是一条一条的, 所以for循环要用 “\” 跟“;”连起来构成一条命令
上面最后的结果是输出三句话
current dir:
current dir:
current dir:
这跟我们想要的不符,我们来看看原因, 先看第一阶段的展开
由于在第一阶段的展开中, d实际上是没有定义的,它被展开成空。 这里要注意的是第一阶段它只是读跟展开,并没有执行, 所以d不会被定义成for循环中对应的现
按照上面的的展开,我们就知道为什么会有那样的输出
为了看的更清楚一点,对makefile稍微改造一下
我们会得到输出:
current dir: /home
current dir: /home
current dir: /home
这是因为它在第一阶段展开成如下的内容
那么我们如何才能得到预期的目标呢? 这就要用到二次展开的概念,让它在第二阶段再展开一次
在第一阶段后展开成
这样在第二阶段执行的时候, $d就会展开成for中对应的列表了, 即dira, dirb跟dirc
在第一阶段, make读入include等文件, 并对变量进行替换, 展开隐式规则等, 这一阶段就是生成合适makefile的过程
在第二阶段是执行阶段, 根据第一阶段生成的makefile, 根据规则对需要更新的目标进行更新
但如果在规则下面的命令中, 用到了循环, 则会涉及到二次展开的问题, 所谓二次展开就是在第二阶段再展开一次
比如下面的例子:
dirs= dira, dirb, dirc all: for d in $(dirs); \ do \ echo "current dir: $d"; \ done; |
由于在规则下面的命令只能是一条一条的, 所以for循环要用 “\” 跟“;”连起来构成一条命令
上面最后的结果是输出三句话
current dir:
current dir:
current dir:
这跟我们想要的不符,我们来看看原因, 先看第一阶段的展开
dirs= dira, dirb, dirc all: for d in dira dirb dirc; \ do \ echo "current dir: $d"; \, d实际上是没有定义的,它被展开成空字符串 done; |
按照上面的的展开,我们就知道为什么会有那样的输出
为了看的更清楚一点,对makefile稍微改造一下
dirs= dira, dirb, dirc d=/home all: for d in $(dirs); \ do \ echo "current dir: $d"; \ done; |
current dir: /home
current dir: /home
current dir: /home
这是因为它在第一阶段展开成如下的内容
dirs= dira, dirb, dirc d=/home all: for d in dira dirb dirc; \ do \ echo "current dir: /home"; \d被展开成了/home done; |
那么我们如何才能得到预期的目标呢? 这就要用到二次展开的概念,让它在第二阶段再展开一次
dirs= dira, dirb, dirc all: for d in $(dirs); \ do \ echo "current dir: $$d"; \ done; |
dirs= dira, dirb, dirc all: for d in dira dirb dirc; \ do \ echo "current dir: $d"; \ done; |
这样在第二阶段执行的时候, $d就会展开成for中对应的列表了, 即dira, dirb跟dirc