Sheng Wang

利用总控Makefile一次性编译所有子程序包

当一个大的项目由很多子程序组成,而每一个子程序包都有自己独立的Makefile,这时候就需要一个总控Makefile来一次性完成所有的编译工作。以下给出了一个例子,以说明如何构建总控Makefile

文件结构

项目PRJ包含了三个子程序包。每个子程序包都拥有自己的Makefile,从而可以在各目录下使用Make完成编译。但是这样很麻烦。通过构建总控Makefile(PRJ/Makefile),可以一次性编译prj_sub1,prj_sub2,prj_sub3三个子程序包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PRJ/
├── prj_sub1/
│  ├── a.c
│  ├── b.c
│  ├── c.c
│  └── Makefile
|
├── prj_sub2/
│  ├── d.c
│  ├── e.c
│  └── Makefile
├── prj_sub3/
│  ├── f.c
│  ├── g.c
│  └── Makefile
├── ...
└── Makefile

子程序包Makfile

子程序包中的Makefile包含了编译,install,clean操作。以下例子中,有关函数foreach,自动化变量$@ $<,以及静态模式的内容可以参见X
需要注意的是变量BIN并没有在Makefile中声明赋值,而是通过总控Makefile中的export来传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#Makefile for prj_sub1/
CC = gcc
EXEC = a b c
OBJ = $(foreach exe, ${EXEC}, ${exe}.o)

all: ${OBJ} ${EXEC}

${EXEC}:%:%.o
${CC} -o $@ $<

${OBJ}:%.o:%.c
${CC} -c -o $@ $<

install:
cp ${EXEC} ${BIN}

clean:
rm ${EXEC} ${OBJ}

总控Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export BIN=../bin

SUBS = prj_sub1 prj_sub2 prj_sub3
SUBS_make = $(foreach sub, ${SUBS}, ${sub}.make)
SUBS_clean = $(foreach sub, ${SUBS}, ${sub}.clean)
SUBS_install = $(foreach sub, ${SUBS}, ${sub}.install)

all: ${SUBS_make}

${SUBS_make}:%.make:%
make -C $<

install: ${SUBS_install}

${SUBS_install}:%.install:%
-make -C $< install

clean: ${SUBS_clean}

${SUBS_clean}:%.clean:%
-make -C $< clean

总控Makefile一次性编译了prj_sub1,prj_sub2,prj_sub3三个子程序包。
首先对变量SUBS_make赋值,为prj_sub1.make prj_sub2.make prj_sub3.make。类似的,完成变量SUBS_cleanSUBS_install的赋值。
随后,在编译中,${SUBS_make}:%.make:%声明从变量SUBS_make中逐次提取以.make结尾的字段作为编译目标,去掉
.make之后的内容作为编译依赖项目,进而利用make -C $<完成编译。第10,11行等价于:

1
2
3
4
5
6
7
8
prj_sub1.make: prj_sub1
make -C prj_sub1

prj_sub2.make: prj_sub2
make -C prj_sub2

prj_sub3.make: prj_sub3
make -C prj_sub3

make -C prj_sub1等价于cd prj_sub1; make。其相当于先进入目录prj_sub1,然后执行make命令。
与编译类似,installclean操作一次性完成所有子程序包的安装及清理操作。
需要注意的是,利用export BIN=../bin,将变量BIN传递至被调用Makefile