Recursive use of the GNU Make
下面所称的 make 都假定是 GNU Make,也是所有 Linux 发行版所采用的 make 版本。本文内容主要来自从 GNU Make manual(在 Debian/Ubuntu 中,安装软件包 make-doc,然后执行命令 info make 就可以看到;对于自己编译的 make 版本,自身就带有 doc)。
这里所称递归使用指从 Makefile 里再调用 make 去执行另一个 Makefile,对于具有目录结构的工程很有用,通常可以为每个目录创建一个 Makefile,然后用一个总的 Makefile 进行管理。
(1) 基本用法
在一个 Makefile 里调用另一个 Makefile 的命令是:
cd subdir && $(MAKE)
因为每一条命令都使用一个单独的 shell 环境,具有独立的当前目录,故 MAKE 后面无需再加上 cd..。Make 的 manual 建议:永远使用 $(MAKE) 而不要直接在 Makefile 中写 make,这可以保证在系统中装有不同版本的 make 时父进程与子进程是相同版本,这可以保证进程之间的通信正确。
(2) 变量传递
make 可以将变量传递给子 make 进程,按照以下规则:
a. 用户在命令行上赋值的变量默认传递,并且仍以命令行方式传递(这可保证子进程再有子进程时一直传下去)
b. Makefile 中赋值的变量默认不传递
c. 用 export 命令可明令传递某一个变量(用法类似 bash,如 export MYVAR)
d. 用 unexport 命令可明令不传递某一个变量
e. 如果对一个变量有多次赋值,则它们的优先级顺序为:命令行赋值优先级最高;Makefile 自身的赋值次之;父进程传来的变量最低(父进程传来的命令行除外)。
举例:
./Makefile文件内容为(注意 tab 在这里都显示成了空格):
export MYVAR=abc
all:
cd subdir && $(MAKE)
subdir/Makefile 文件内容为:
MYVAR=def
all:
@echo $(MYVAR)
那么在当前目录下执行 make,显示的结果是 def;执行 make MYVAR=ghi,显示的是 ghi;如果删掉 subdir/Makefile 的第一行再 make,显示的是 abc
(3) 命令行参数传递
通常不用担心,make 会把它们处理得很好,-B, -i 等参数都会一直传下去。至于 -j<N> 参数,也不用担心,make 的多个进程之前会相互通信,以保证工作进程数不超过 <N>。(如果操作系统不支持这种通信,则始终传递 "-j1" 给子进程——作为当代最流行的类 Unix 系统,Linux 当然支持这种通信)在特殊情况下有可能需要改变这种默认的处理方式,这也很容易做到,这里就不写了,参见 info make。