通用makefile是如何炼成的(VIII)

 停在这里不敢走下去,     让悲伤无法上演

 下一页你亲手写上的离别, 由不得我拒绝

 这条路我们走得太匆忙,  拥抱着并不真实的欲望,   来不及等不及回头欣赏

大笑摘自《步步惊心 》片尾曲 《三寸天堂》)


走到这里,实际上我们的makefile框架已经是搭得差不多了。这一路小跑过来,感觉一切都很美好,实际上我想,我们只是太匆忙,来不及细细回想。

如果真的回首详观,各种琐碎细节会让你崩溃。

无论如何,该面对的终是要面对的


第一个工作是,让我们的module.mk更像是一个模块mk,为此引入MODULE_NAME, MODULE_PATH. 这两项结合起来,以后也可以作为module的唯一标识。

hello模块的module.mk

# module.mk
#
MODULE_PATH			:= $(call current_path)
MODULE_NAME			:= hello


获取模块路径时,我用了一个小小的技巧。很多书上都有提到,原理是利用了makefile的环境变量MAKEFILE_LIST.

这里简单贴一下实现代码

define current_path
$(patsubst %/,%, \
$(dir $(word $(words $(MAKEFILE_LIST)), $(MAKEFILE_LIST))))
endef


D第二个我们要做的琐事是调整一些路径。现在的makefile,编译生成的中间文件还是和源文件混杂在一起的,为了美观和方便版本控制,我们把它们集中到INTERMEDIATE_OBJ_PATH,对其他的一些自动生成的文件,也是类似处理。

做这项工作时注意要”步步惊心“, 还好我们是从一开始就知道故事结局的大笑,就是要正确编译得到可执行文件。


另外,不同的人,可以对路径的处理不同。例如,为了区分不同产品,不同平台,有些同学喜欢为各个产品、各个平台分别建立文件夹,构成深目录层次, 有些同学喜欢采用 <product>--<platform>这样的浅层次的目录结构。

这里选择了浅目录形式,因为大部分情况下我们是不需要多平台的。


这里为了方便测试,特意引入了产品信息TEST, 平台信息X86



所有的路径信息,统一集中在paths/path.mk。这里引入两个重要概念TARGET_PRODUCT, TARGET_PLATFORM,这是由make命令行参数传入的。这里为了测试方便,直接在脚本中写入了。

# path.mk


## 目前的路径策略,根目录下建立out,bin,lib,src,build五大目录,out目录下可以再建立bin.lib,obj目录

PROJECT_OUT_PATH 		:= out
PROJECT_BIN_PATH 		:= bin
PROJECT_LIB_PATH 		:= lib

TARGET_PRODUCT := TEST
TARGET_PLATFORM:= X86


ifneq "$(TARGET_PRODUCT)" ""
  PRODUCT_SUFFIX 		:= $(TARGET_PRODUCT)
else
  PRODUCT_SUFFIX 		:= 
endif

ifneq "$(TARGET_PLATFORM)" ""
  PRODUCT_SUFFIX        := $(PRODUCT_SUFFIX)-$(TARGET_PLATFORM)
endif

## 产品和平台附加的路径后缀不为空,就以此建立子目录
ifneq "$(PRODUCT_SUFFIX)" ""
PRODUCT_OUT_PATH 		:= $(PROJECT_OUT_PATH)/$(PRODUCT_SUFFIX)
PRODUCT_BIN_PATH 		:= $(PROJECT_BIN_PATH)/$(PRODUCT_SUFFIX)
PRODUCT_LIB_PATH 		:= $(PROJECT_LIB_PATH)/$(PRODUCT_SUFFIX)
else
PRODUCT_OUT_PATH 		:= $(PROJECT_OUT_PATH)
PRODUCT_BIN_PATH 		:= $(PROJECT_BIN_PATH)
PRODUCT_LIB_PATH 		:= $(PROJECT_LIB_PATH)
endif

INSTALL_PATH := $(PRODUCT_BIN_PATH)
INTERMEDIATE_PATH := $(PRODUCT_OUT_PATH)
INTERMEDIATE_OBJS_PATH:=$(INTERMEDIATE_PATH)/obj
INTERMEDIATE_LIB_PATH:=$(INTERMEDIATE_PATH)/lib
INTERMEDIATE_BIN_PATH:=$(INTERMEDIATE_PATH)/bin

$(info INSTALL_PATH=$(INSTALL_PATH))
$(info INTERMEDIATE_PATH=$(INTERMEDIATE_PATH))

配置后,注意同步调整targets目录下的mk文件,利用object.mk

# object.mk

## 从源文件列表中分别提取出C文件和C++文件
C_OBJS  := $(patsubst %.c, $(INTERMEDIATE_OBJS_PATH)/%.o, $(filter %.c, $(SRC_FILES)))
CPP_OBJS:= $(patsubst %.cpp, $(INTERMEDIATE_OBJS_PATH)/%.o, $(filter %.cpp, $(SRC_FILES)))
OBJS    := $(C_OBJS) $(CPP_OBJS)
DEPS    := $(OBJS:.o=.d)


## -MMD 可以用于自动生成头文件依赖关系
$(INTERMEDIATE_OBJS_PATH)/%.o : %.cpp
	$(hide)$(MAKEDIR) $(dir $@)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -MT"$(@:%.o=%.d)" -c "$<" -o "$@" 
$(INTERMEDIATE_OBJS_PATH)/%.o : %.c
	$(hide)$(MAKEDIR) $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -MT"$(@:%.o=%.d)" -c "$<" -o "$@" 
....


另外,如果在module.mk中没有定义目标时, 我们根据模块名 自动生成目标

# executable.mk
#

## 编译生成obj文件的通用规则
include build/targets/object.mk

## 如果目标未定义,则默认是out/bin/<module-name>
ifeq "$(TARGET)" ""
  TARGET := $(INTERMEDIATE_BIN_PATH)/$(MODULE_NAME)
endif

。。。。


今天的工作到此为止。主要是琐事缠身




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值