目录
简介
公共部分makefile
模块目录makefile
顶层makefile
实际输出
简介 学习完《跟我一起写makefile》之后,对于makefile的各种规则和函数有了初步了解,但是对于层级调用的makefile不是很熟悉,接下来的内容是搜索的网上的一个模板,对其中内容自己做了一些修改,并且简单实验了一下可以正常工作.这个模板与其他的不相同的是,他把公共部分封装成了一个makefile,这个思路感觉很有意思。
原文链接 《一个适用于层级目录结构的makefile模版》
本次makefile工程的目录内容如下
公共部分makefile 首先来看看公共部分的makefile,该makefile将各个makefile公用的部分整个起来,节省了很多工作,具体解释见其中注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 CC=gcc MAKE=make AR=ar cr CFLAGS=-Wall -g -O0 dirs:=$(shell find . -maxdepth 1 -type d) dirs:=$(basename $(patsubst ./%,%,$(dirs) ) ) dirs:=$(filter -out $(exclude_dirs) ,$(dirs) ) SUBDIRS:=$(dirs) SOURCEDIR=main TMPDIR:=$(filter $(SOURCEDIR) ,$(dirs) ) ifeq ($(TMPDIR) ,$(SOURCEDIR) )SUBDIRS:=$(filter -out $(SOURCEDIR) ,$(dirs) ) $(SOURCEDIR) endif SRCS=$(wildcard *.c) OBJS=$(patsubst %.c,%.o,$(SRCS) ) DEPS=$(patsubst %.c,%.d,$(SRCS) ) .PHONY=all all:$(TARGET) $(LIB) subdirs $(LIB) :$(OBJS) @echo "$(shell pwd) TARGET=$(TARGET) LIB=$(LIB) SUBDIRS=$(SUBDIRS) " $(AR) $@ $^ cp $@ $(LIBPATH) cp $(INCLUDE) $(INCLUDEPATH) subdirs:$(SUBDIRS) @echo "$(shell pwd) TARGET=$(TARGET) LIB=$(LIB) SUBDIRS=$(SUBDIRS) " for dir in $(SUBDIRS) ;\ do $(MAKE) -C $$dir all||exit 1;\ done $(TARGET) :$(OBJS) @echo "$(shell pwd) TARGET=$(TARGET) LIB=$(LIB) SUBDIRS=$(SUBDIRS) " @echo "Compiling $(TARGET) " $(CC) $^ -o $@ $(LDFLAGS) -L $(LIBPATH) cp $(TARGET) $(EXEPATH) %.o:%.c @echo "Compiling $< " $(CC) -c $< -o $@ $(CFLAGS) -I $(INCLUDEPATH) ifneq ($(MAKECMDGOALS) ,clean)include $(DEPS) endif %.d:%.c @echo "creating $@ " $(CC) $< -MM -MF $@ -MT $* .o -MT $* .d -I $(INCLUDEPATH) .PHONY=clean clean: @echo "$(shell pwd) cleaning " for dir in $(SUBDIRS) ;\ do $(MAKE) -C $$dir clean||exit 1;\ done rm -f $(OBJS) $(TARGET) $(LIB) $(DEPS)
其实这个公共部分的makefile,主要的地方就是all的依赖,除了subdirs,LIB和TARGET都是不存在的,所以后面的规则也就不会执行,subdirs的规则主要是调用下一层目录的makefile。而在下一层的makefiel中将LIB或者TARGET传入,用来编译各自的内容。
模块目录makefile
src目录的makefile
这个makefile很简单,由于该目录下无源文件,继续调用下一层makefile即可。
add目录makefile
1 2 3 4 5 6 7 8 9 TOPDIR=./../.. LIB=libadd.a INCLUDE=add.h INCLUDEPATH=$(TOPDIR) /include LIBPATH=$(TOPDIR) /lib include $(TOPDIR) /Makefile.env
这里提供了LIB变量,那么在公共部分的makefile中的LIB的规则就会执行啦,另外还传入了一些规则中用到的变量.
main目录的makefile
1 2 3 4 5 6 7 8 9 10 TOPDIR=./../.. TARGET=main LIBPATH=$(TOPDIR) /lib EXEPATH=$(TOPDIR) /bin INCLUDEPATH=$(TOPDIR) /include LDFLAGS= -ladd include $(TOPDIR) /Makefile.env
这里提供了TARGET变量,那么在公共部分的makefile中的TARGET的规则就会执行,另外还传入了一些规则中用到的变量
顶层makefile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 TOPDIR=./ exclude_dirs= include bin lib export exclude_dirs.PHONY=all all: make -f $(TOPDIR) /Makefile.env all .PHONY=clean clean: make -f $(TOPDIR) /Makefile.env clean -rm -f include /* bin/* lib/*
在这个makefile中,给出了不需要进行检索的目录变量exclude_dirs,另外这里的变量使用了export,是为了在后续调用的makefile中都存在这个变量,因为是使用make -f调用的,而上面的几个makefile是使用include直接引用的,所以不存在这个问题。
实际输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 [root@VM_0_4_centos qwe]# make make -f .//Makefile.env all make[1]: Entering directory `/home/yu.tian/qwe' /home/yu.tian/qwe TARGET= LIB= SUBDIRS=src for dir in src;\ do make -C $dir all||exit 1;\ done make[2]: Entering directory `/home/yu.tian/qwe/src' /home/yu.tian/qwe/src TARGET= LIB= SUBDIRS=add main for dir in add main;\ do make -C $dir all||exit 1;\ done make[3]: Entering directory `/home/yu.tian/qwe/src/add' ../../Makefile.env:58: add.d: No such file or directory creating add.d gcc add.c -MM -MF add.d -MT add.o -MT add.d -I ./../../include make[3]: Leaving directory `/home/yu.tian/qwe/src/add' make[3]: Entering directory `/home/yu.tian/qwe/src/add' Compiling add.c gcc -c add.c -o add.o -Wall -I ./../../include /home/yu.tian/qwe/src/add TARGET= LIB=libadd.a SUBDIRS= ar cr libadd.a add.o cp libadd.a ./../../lib cp add.h ./../../include /home/yu.tian/qwe/src/add TARGET= LIB=libadd.a SUBDIRS= for dir in ;\ do make -C $dir all||exit 1;\ done make[3]: Leaving directory `/home/yu.tian/qwe/src/add' make[3]: Entering directory `/home/yu.tian/qwe/src/main' ../../Makefile.env:58: main.d: No such file or directory creating main.d gcc main.c -MM -MF main.d -MT main.o -MT main.d -I ./../../include make[3]: Leaving directory `/home/yu.tian/qwe/src/main' make[3]: Entering directory `/home/yu.tian/qwe/src/main' Compiling main.c gcc -c main.c -o main.o -Wall -I ./../../include /home/yu.tian/qwe/src/main TARGET=main LIB= SUBDIRS= Compiling main gcc main.o -o main -ladd -L ./../../lib cp main ./../../bin /home/yu.tian/qwe/src/main TARGET=main LIB= SUBDIRS= for dir in ;\ do make -C $dir all||exit 1;\ done make[3]: Leaving directory `/home/yu.tian/qwe/src/main' make[2]: Leaving directory `/home/yu.tian/qwe/src' make[1]: Leaving directory `/home/yu.tian/qwe'
编译过程基本和我们构想的一致,并且该makefile无论修改任何一个模块的.c或.h文件,都会重新编译涉及的文件。