今天看到"那谁的技术博客"的我的项目Makefile文件模板。平时在linux上小打小闹, 上上周,恰好自己准备做个linux的C++项目(我的第一个linux项目), ,因此自己也整理出来了一套Makefile模板,一共花了三天时间才全部写完, 一直想抽空整理一下, 今天恰好看到“那谁”的分享, 我这里也分享一下。
项目分模块,不同模块的代码放在不同的文件夹下,main.cpp(包含main函数)单独放在main文件夹下。每个模块的文件夹下都有一个Makefile,其中的每一个CPP文件都生成一个.o和.d文件, 同一个目录下的所有.o文件会被make成一个.a库文件(也就是Windows下的.lib文件), 最终调用main目录下的Makefile依次来调用不同模块的文件夹下的Makefile,将这些模块目录下的.a文件和main.cpp生成的main.o文件链接成可执行文件。
且看我的login目录下的Makefile文件:
2 GTK_INCLUDE=`pkg-config --cflags gtk+-2.0`
3 SOURCES:=$(wildcard *.cpp)
4 OBJS:=$(subst .cpp,.o,$(SOURCES))
5 DEPS:=$(subst .cpp,.d,$(SOURCES))
6 CPPINCLUDE:=..
7 CPPFLAGS = -g -Wall -I$(CPPINCLUDE) $(GTK_INCLUDE)
8 CC=g++
9
10 .PHONY: all clean
11 all:lib$(DIR).a
12
13 lib$(DIR).a: $(OBJS)
14 ar crv $@ $(OBJS)
15
16 %.o:%.cpp
17 $(CC) $(CPPFLAGS) -c $<
18
19 include $(subst .cpp,.d,$(SOURCES))
20
21 %.d:%.cpp
22 $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /
23 sed 's,/($*/)/.o[ :]*,/1.o $@:, g' < $@.$$$$ > $@; /
24 rm -f $@.$$$$
25
26 clean:
27 -rm *.o *.a *.d
在linux下写Makefile的最大难点是源代码文件(这里是.cpp)的头文件依赖关系,如果一个cpp文件直接或间接包含的头文件变化,那么这个cpp文件就需要重新编译。使用cc -MM test.cpp就可以生成cpp的.o文件的依赖关系。关于.d文件以及依赖关系,最好的教程是:
main
《《Managing Projects with GNU make, 3rd Edition》》 |
上面那一段也是从这本书里学习来的。
main文件夹下的Makefile如下:
1 LOGIN_DIR:=../login
2 NETWORK_DIR:=../network
3 UTILS_DIR:=../utils
4 SRC_DIRS:=$(LOGIN_DIR) $(NETWORK_DIR) $(UTILS_DIR)
5 ARS:=$(LOGIN_DIR)/liblogin.a $(NETWORK_DIR)/libnetwork.a $(UTILS_DIR)/libutils.a
6
7 DIR=main
8 SOURCES:=$(wildcard *.cpp)
9 OBJS:=$(subst .cpp,.o,$(SOURCES))
10 DEPS:=$(subst .cpp,.d,$(SOURCES))
11 CPPINCLUDE:=..
12 GTK_INCLUDE=`pkg-config --cflags gtk+-2.0`
13 GTK_LIB=`pkg-config --libs gtk+-2.0`
14 CPPFLAGS = -g -Wall -I$(CPPINCLUDE) $(GTK_INCLUDE)
15 CC=g++
16
17 .PHONY: all $(SRC_DIRS) $(SRC_DIRS_FOR_CLEAN) clean
18
19 all: $(SRC_DIRS) main
20
21
22 main: $(OBJS) $(ARS)
23 $(CC) -o main $(OBJS) $(ARS) $(GTK_LIB)
24
25
26 $(SRC_DIRS):
27 $(MAKE) --directory=$@
28
29
30
31 #以下为生成本目录下的.o文件
32 %.o:%.cpp
33 $(CC) $(CPPFLAGS) -c $<
34
35 include $(subst .cpp,.d,$(SOURCES))
36
37 %.d:%.cpp
38 $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /
39 sed 's,/($*/)/.o[ :]*,/1.o $@:, g' < $@.$$$$ > $@; /
40 rm -f $@.$$$$
41
42
43 clean:
44 for d in $(SRC_DIRS); /
45 do /
46 cd $$d; /
47 $(MAKE) clean; /
48 done /
49
50 -rm main *.o *.a *.d
其中,make clean也会循环依赖调用各个模块文件夹下的Makefile中的clean target。
参考的资料如下:
1. 跟我一起写 Makefile 陈皓 (优快云)
2. Managing Projects with GNU make, 3rd Edition
当前这套模板的缺陷也很显然:
main里面需要手工写上所有模块的子目录名,当时没有网络,不能google,反正只好用上刚学到的所有Makefile知识了。可喜的是,对于小项目来说,这套Makefile模板可以清晰地分模块,处理依赖关系,清理垃圾等,已经符合当前我的项目需求了。等以后不够用的时候再重构吧。
makefile也是一门语言,也有函数,也可以嵌入shell脚本,也可以写出死循环(我不幸经历了一次),也可以调试。最重要的目前我认为有两点:
1. 头文件的依赖关系
2. 调试, 测试,自己先做个简单的demo,建立几个文件夹,验证一下自己的想法
写完Makefile, 人生完整了一些。
不知道csdn博客如何上传附件(或许就没有?),想要这套mk_template的,可以问我要。