目录
1.问题
一般而言,不同工程师负责不同模块的开发;编译环境中如何支持模块的独立编译?
2.问题背景
- 大型项目的代码文件成千上万,完整编译的时间较长
- 编写模块代码时,可通过编译检查语法
- 为了提高开发效率,需要支持指定模块的独立编译
示例:
3.解决方案
- 将模块(module作为目标名(伪目标)建立规则
- 目标(module)对应的依赖为build build/module
- 规则中的命令进入对应的模块文件夹进行编译
- 编译结果存放于build文件夹下
pro-rule.mk增加以下内容
.PHONY : all compile link clean rebuild $(MODULES)
……………
$(MODULES) :
@echo "Begin to compile $@"
测试一下
aston@ubuntu:~/disciple$ make main
Begin to compile main
aston@ubuntu:~/disciple$ make common
Begin to compile common
aston@ubuntu:~/disciple$ make module
Begin to compile module
4.关键技术点
- 如何获取make命令行中指定编译的模块名?
- 预定义变量:
命令行中指定的目标名(make的命令行参数)
不可以
然后开始写依赖,测试一下:
$(MODULES) : $(DIR_BUILD) $(DIR_BUILD)/$@
@echo "Begin to compile $@"
aston@ubuntu:~/disciple$ make common
mkdir build
Begin to compile common
看起来没问题,但是只创建了build目录,并没有创建common目录
怎么解决呢?使用MAKECMDGOALS
$(MODULES) : $(DIR_BUILD) $(DIR_BUILD)/$(MAKECMDGOALS)
@echo "Begin to compile $@"
测试一下:
make common
mkdir build
mkdir build/common
Begin to compile common
接下来就是编译代码了,直接复制就可以了
$(MODULES) : $(DIR_BUILD) $(DIR_BUILD)/$(MAKECMDGOALS)
@echo "Begin to compile $@"
@set -e; \
cd $@ && \
$(MAKE) all \
DEBUG:=$(DEBUG) \
DIR_BUILD:=$(addprefix $(DIR_PROJECT)/, $(DIR_BUILD)) \
DIR_COMMON_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_COMMON_INC)) \
MOD_CFG:=$(addprefix $(DIR_PROJECT)/, $(MOD_CFG)) \
MOD_RULE:=$(addprefix $(DIR_PROJECT)/, $(MOD_RULE)) \
CMD_CFG:=$(addprefix $(DIR_PROJECT)/, $(CMD_CFG)) &&\
cd ..; \
测试一下:
make common
mkdir build
mkdir build/common
Begin to compile common
make[1]: Entering directory `/home/aston/disciple/common'
/home/aston/disciple/mod-rule.mk:19: /home/aston/disciple/build/common/common.dep: No such file or directory
/home/aston/disciple/mod-rule.mk:19: /home/aston/disciple/build/common/func.dep: No such file or directory
Creating /home/aston/disciple/build/common/func.dep...
Creating /home/aston/disciple/build/common/common.dep...
make[1]: Leaving directory `/home/aston/disciple/common'
make[1]: Entering directory `/home/aston/disciple/common'
ar crs /home/aston/disciple/build/common.a /home/aston/disciple/build/common/common.o /home/aston/disciple/build/common/func.o
make[1]: Leaving directory `/home/aston/disciple/common'
aston@ubuntu:~/disciple$ ls build/
common common.a
5.makefile中代码复用
- 当不同规则中的命令大量重复时,可以考虑自定义函数
- makefile中的自定义函数是代码复用的一种方式
上面我们是直接复制粘贴,我们就得考虑代码复用了
define makemodule
cd $@ && \
$(MAKE) all \
DEBUG:=$(DEBUG) \
DIR_BUILD:=$(addprefix $(DIR_PROJECT)/, $(DIR_BUILD)) \
DIR_COMMON_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_COMMON_INC)) \
MOD_CFG:=$(addprefix $(DIR_PROJECT)/, $(MOD_CFG)) \
MOD_RULE:=$(addprefix $(DIR_PROJECT)/, $(MOD_RULE)) \
CMD_CFG:=$(addprefix $(DIR_PROJECT)/, $(CMD_CFG)) &&\
cd ..;
endef
…………………..
$(MODULES) : $(DIR_BUILD) $(DIR_BUILD)/$(MAKECMDGOALS)
@echo "Begin to compile $@"
@set -e; \
$(call makemodule, $@)
测试ok
把make all也改成函数调用
compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
@echo "Begin to compile..."
@set -e; \
for dir in $(MODULES); \
do \
$(call makemodule, $$dir) \
done
@echo "success compile ..."
测试发现:
make all
Begin to compile...
/bin/sh: 4: cd: can't cd to compile
/bin/sh: 4: cd: can't cd to compile
/bin/sh: 4: cd: can't cd to compile
make: *** [compile] Error 2
解决:问题出在函数定义,我们要使用函数调用时的第一个参数
define makemodule
cd ${1} && \
$(MAKE) all \
DEBUG:=$(DEBUG) \
DIR_BUILD:=$(addprefix $(DIR_PROJECT)/, $(DIR_BUILD)) \
DIR_COMMON_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_COMMON_INC)) \
MOD_CFG:=$(addprefix $(DIR_PROJECT)/, $(MOD_CFG)) \
MOD_RULE:=$(addprefix $(DIR_PROJECT)/, $(MOD_RULE)) \
CMD_CFG:=$(addprefix $(DIR_PROJECT)/, $(CMD_CFG)) &&\
cd ..;
endef
测试ok
6.思路
- 将编译模块的命令集作为自定义函数的具体实现
- 函数参数为模块名,函数调用后编译参数指定的模块
- 在不同的规则中调用该函数
7.小结
- 编写模块代码时可通过模块独立编译快速检查语法错误
- 自动白能量只能在规则的命令中使用,不能再依赖中使用
- makefile中的自定义函数是代码复用的一种方式
- 当不同规则中的命令大量复用时,可考虑自定义函数