GNU Makefile--命令行参数的传递
make
的命令行变量参数
在Makefile脚本中,可以通过$(MAKE)
递归执行其他的Makefile。make
的一些命令行选项(例如禁止输出当前目录的选项--no-print-directory
等),会对其行为产生一些影响,而递归调用的make
也应当继承这一类选项。此外,在编译u-boot或Linux内核等工程时,常用的命令为:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- ...
命令中的ARCH
和CROSS_COMPILE
两个变量参数也应当在由$(MAKE)
递归生成的新的make
进程中生效;亦即在sub-make
的执行中,也应当默认定义了这两人个变量。而通过查看u-boot/Linux工程中的Makefile脚本,并没有显式传递这两个变量参数的代码。本文记录了笔者探究其实现原理的调试过程。
origin
函数查看变量定义源
Makefile的变量有多种定义的方式,例如默认变量、环境变量、文件显式定义、自动变量等。获取某个变量的定义方式,可以增强编译构建的鲁棒性。GNU Make提供了origin函数,可获取某个变量的定义源;从此入手,可以编写以下两个Makefile脚本,探究命令行变量是如何传递给递归执行的make
。文件名为Makefile
的脚本内容为:
MAKEFLAGS += -r -R
# get the definition origin of `MAKEVAL
MV_ORIG := $(origin MAKEVAL)
ifeq ($(MAKEVAL),)
MAKEVAL := defined in makefile
endif
.PHONY: all
all:
phell -s -p MAKEFLAGS -p MAKEVAL
@echo "Origin: $(MV_ORIG); invoking sub-make..."
@echo "------------------------------------------------"
$(MAKE) --no-print-directory -f dump-env.mk $@
脚本中使用到了phell
调试工具,该工具可在笔者的下载区域获得,它的-p
选项可以查看某个环境变量的值。不过,不使用phell
工具也是可行的,通过echo
命令直接输出环境变量值。该脚本通过$(MAKE)
调用了一个sub-make
,脚本文件dump-env.mk的内容如下:
.PHONY: all
all:
phell -s -p MAKEFLAGS -p MAKEVAL
下面就要根据这两个Makefile文件来调试分析了。以make -f Makefile
命令执行,其结果为:
# make -f Makefile
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR
****** $ENV{MAKEVAL} has not been defined
Origin: undefined; invoking sub-make...
------------------------------------------------
make --no-print-directory -f dump-env.mk all
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR --no-print-directory
****** $ENV{MAKEVAL} has not been defined
两个Makefile脚本的结果大致由-----------
分隔。$(origin MAKEVAL)
的结果为undefined
,表明变量未定义,这是正确的结果。Makefile创建的子进程(实际上是/bin/sh
的子进程)phell
的环境变量MAKEFLAGS
的值为rR
,而dump-env.mk创建的子进程phell
的环境变量MAKEFLAGS
的值为rR --no-print-directory
,这样就可以解答本文中提到的问题:
GNU Make通过环境变量MAKEFLAGS
向递归调用的$(MAKE)
传递选项参数(变量参数另议);在sub-make启动时,它会根据命令行选项以及环境变量MAKEFLAGS
的值,重新设定MAKEFLAGS
。
设定环境变量MAKEVAL
设置MAKEVAL
环境变量(而非以make
的变量参数)并执行make
,相应的命令为:
MAKEVAL='Hello World' make -f Makefile
由结果可知,origin
可以正确地判定MAKEVAL
变量的定义源为environment
:
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR
****** $ENV{MAKEVAL} => Hello World
Origin: environment; invoking sub-make...
------------------------------------------------
make --no-print-directory -f dump-env.mk all
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR --no-print-directory
****** $ENV{MAKEVAL} => Hello World
设定变量参数MAKEVAL
与环境变量的区另是,make
的变量参数在其之后指定:
make MAKEVAL='Hello World' -f Makefile
其结果如下:
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR -- MAKEVAL=Hello\ World
****** $ENV{MAKEVAL} => Hello World
Origin: command line; invoking sub-make...
------------------------------------------------
make --no-print-directory -f dump-env.mk all
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => rR --no-print-directory -- MAKEVAL=Hello\ World
****** $ENV{MAKEVAL} => Hello World
与之前的结果对比可知,源于命令行(command line
)的变量参数,会在make
启动时添加到MAKFFLAGS
变量的尾部,并通过环境变量导出。MAKEFLAGS
变量默认会被make
导出到环境变量中。至此,我们就全完解答了本文提出的问题。
make
的-n
命令行参数
GNU Make工具的-n
参数可以在不执行具体操作的情况下,将操作命令输出。根据官方文档的说明,带有$(MAKE)
的操作是例外:
$ make -n -f Makefile
phell -s -p MAKEFLAGS -p MAKEVAL
echo "Origin: undefined; invoking sub-make..."
echo "------------------------------------------------"
make --no-print-directory -f dump-env.mk all
phell -s -p MAKEFLAGS -p MAKEVAL
最后一行phell -s -p MAKEFLAGS -p MAKEVAL
源于第二个Makefile脚本dump-env.mk。虽然输出了该操作,但没有被执行。可以给相应的操作之前添加+
字符,在带有-n
命令行参数的情况下,依然执行操作。相应的修改为:
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ endif
.PHONY: all
all:
- phell -s -p MAKEFLAGS -p MAKEVAL
+ +phell -s -p MAKEFLAGS -p MAKEVAL
@echo "Origin: $(MV_ORIG); invoking sub-make..."
@echo "------------------------------------------------"
$(MAKE) --no-print-directory -f dump-env.mk $@
--- a/dump-env.mk
+++ b/dump-env.mk
@@ -3,4 +3,4 @@
.PHONY: all
all:
- phell -s -p MAKEFLAGS -p MAKEVAL
+ +phell -s -p MAKEFLAGS -p MAKEVAL
再次执行make -n -f Makefile
,其结果如下:
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => nrR
****** $ENV{MAKEVAL} has not been defined
echo "Origin: undefined; invoking sub-make..."
echo "------------------------------------------------"
make --no-print-directory -f dump-env.mk all
phell -s -p MAKEFLAGS -p MAKEVAL
****** $ENV{MAKEFLAGS} => nrR --no-print-directory
****** $ENV{MAKEVAL} has not been defined
由以上可知,GNU Make的-n
命令行参数也由MAKEFLAGS
通过环境变量传递给递归调用的sub-make。操作命令之前的+
字符不仅影响-n
参数的作用,还会影响-t
/-q
等参数的作用,这一特性增加了make
工具的灵活性;具体的说明请参考GNU Make的官方文档。
更多推荐
所有评论(0)