通用makefile是如何炼成的(IV)
来源:互联网 发布:袜子品牌 知乎 编辑:程序博客网 时间:2024/06/04 04:46
现在我们的主makefile已经是这样的
# main.mk#include build/systems/system.mk## 定义产品信息。这里BUILD_SPECS设置为spec.mkPRODUCT_SPECS :=build/spec.mkinclude build/products/product.mk## 定义平台相关的编译命令。这里PLATFORM_SPECS为空,表示我们不做额外定制化。PLATFORM_SPECS :=include build/platforms/platform.mk## 将产品信息中的定义的feature与平台定义的编译选项混合CXXFLAGS+=$(OPTIONS)OBJS:=hello.o main.oTARGET:=hello.exe## 定义obj文件的编译规则hello.o : hello.cpp hello.h$(CXX) $(CXXFLAGS) -c $< -o $@main.o : main.cpp hello.h$(CXX) $(CXXFLAGS) -c $< -o $@## 定义可执行文件hello.exe的编译规则$(TARGET):$(OBJS)$(CXX) $(CXXFLAGS) -o $@ $^all: ...
在此之际,回顾一下一开始提到的最原始的makefile的几个毛病
地方
1. makefile内容依赖于源文件。如果再增加一个world.cpp, 则必须再修改makefile后才能编译。只好期望源文件不要太多了
2. 生成obj文件时,依赖的源文件和头文件是手动添加的,不会自动推导。这就导致以后修改源文件时,必须同步维护makefile中头文件依赖关系。太累了
3. g++ 以及相应的编译选项都是写死的,如果想要交叉编译一个arm平台上运行的可执行文件,哦,又要修改makefile
4. 没有编译产品的信息,好歹给个立牌坊的机会
想现在毛病3,4已经基本漂亮的解决了(“基本”的含义是?,请看后文),地也圈了,楼也盖了不少(products目录,platforms目录,systems目录),本来坐等发财,结果发现就因为毛病2,集团内容沟通不利。随便改改源文件,可以就要同步调整makefile了。要解决这个头文件依赖关系的自动推导问题,呵呵,GNU中直接有尚方宝剑MMD,MF, MT。
SRC_FILES:= hello.cpp main.cppOBJS:=hello.o main.oTARGET:=hello.exe## -MMD 可以用于自动生成头文件依赖关系%.o : %.cpp$(CXX) $(CXXFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -MT"$(@:%.o=%.d)" -c "$<" -o "$@" DEPS := hello.d main.difneq "$(MAKECMDGOALS)" "clean"-include $(DEPS)endif## 定义可执行文件hello.exe的编译规则$(TARGET):$(OBJS)$(CXX) $(CXXFLAGS) -o $@ $^
关于hello.d, main.d,他们的内容就是具体的依赖关系,然后通过include将依赖关系导入,如此就大功告成。
## hello.dhello.o hello.d: hello.cpp hello.hhello.h:
详细的,hello.d具体怎么生成的,或者其他更多自动生成头文件依赖关系的,就“不要问我从哪里来,我的答案在度娘”
现在依赖关系是自动生成了,不过obj文件列表,还有那些.d文件列表,都是手动填写的,可以自动化吗?
答案是肯定的,要不然通用makefile就炼不成了。(就像是看电视剧或者动漫的,都知道主角光环,无论前面如何复杂艰险,主角总是能化险为夷的)
makefile中有一种类似于shell脚本中的变量替换一样,我们可以直接从源文件列表导出obj文件列表,以及.d文件列表。不多说,直接上代码
SRC_FILES:= hello.cpp main.cppOBJS:=$(SRC_FILES:.cpp=.o)DEPS:=$(OBJS:.o=.d)TARGET:=hello.exe## -MMD 可以用于自动生成头文件依赖关系%.o : %.cpp$(CXX) $(CXXFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -MT"$(@:%.o=%.d)" -c "$<" -o "$@" ifneq "$(MAKECMDGOALS)" "clean"-include $(DEPS)endif## 定义可执行文件hello.exe的编译规则$(TARGET):$(OBJS)$(CXX) $(CXXFLAGS) -o $@ $^
如果你愿意,源文件列表也是可以自动推导的:给定源文件路径,通过$(foreach dir, $(LOCAL_SRC_PATHS), $(wildcard $(dir)/*.cpp))命令,可以自动将指定目录下的.cpp文件全部找出来。
今天的工作做得很漂亮,以后只要配置好makefile,以及列出源文件列表,就可以直接编译了,其他什么也不用改。甚至对于源文件列表,也可以通过指定目录以及命令wildcard自动推导出来。
走到这里,感觉人生已经无欲无求了,通用makefile真的已经通用了。However,我又是看得太远,看这段makefile,我想到两个问题
1. 上面的生成obj文件和.exe文件的代码是很形式化的,如果可以应该同product一样,单独归类到某个文件夹中,防止在修改makefile时不小心改了这些代码
2. 如果我是多模块编译,怎么办呢?
路漫漫其修远兮,吾将上下而求索...
- 通用makefile是如何炼成的(IV)
- 通用makefile是如何炼成的(II)
- 通用makefile是如何炼成的(III)
- 通用makefile是如何炼成的(V)
- 通用makefile是如何炼成的(VI)
- 通用makefile是如何炼成的(VII)
- 通用makefile是如何炼成的(VIII)
- 通用makefile是如何炼成的(I)
- 通用makefile是如何炼成的(XI)--最后的完结篇,envsetup.sh
- 通用makefile是如何炼成的(Ⅸ)整体框架
- 通用makefile是如何炼成的(X)—— 导入单元测试
- vmlinux是如何炼成的--kernel makefile
- vmlinux是如何炼成的--kernel makefile
- makefile 必知必会以及Makefile是怎样炼成的
- 一个简单RPC框架是如何炼成的(IV)——实现RPC消息的编解码
- 好口才是如何炼成的!
- DBA是如何炼成的
- 一个APK是如何炼成的
- 关于TrueType字体
- Vasya and the Bus
- 冬天的温泉
- Java POI操作XML
- 简单介绍基于颜色的阴影检测算法
- 通用makefile是如何炼成的(IV)
- Android百度地图如何计算两点之间距离?
- 运放总结
- linux jira安装
- JSON对象
- the thinker of code complete -- convention
- VMware下ubuntu上网设置2
- java获取classpath路径
- Oracle “CONNECT BY” 使用