目录
1.需求分析
- 工程项目中不希望源码文件夹在编译时被改动(只读文件夹)
- 在编译时自动创建文件夹(build)用于存放编译结果
- 编译过程中能够自动搜索需要的文件
- makefile易于扩展,能够复用于相同类型的项目
- 支持调试版本的编译选项
2.项目类型分析
3.工具原料
4.关键技巧
1.自动获取源文件列表(函数调用)
2.根据源文件列表生成目标文件列表(变量的值替换)
3.替换每一个目标文件的路径前缀(函数调用)
5.编译规则的依赖
.PHONY : all clean
DIR_BUILD := build
DIR_SRC := src
DIR_INC := inc
CC := gcc
CFLAGS := -I $(DIR_INC)
MKDIR := mkdir
RM := rm -rf
APP := $(DIR_BUILD)/app.out
HDRS := $(wildcard $(DIR_INC)/*.h)
HDRS := $(notdir $(HDRS))
OBJS := $(wildcard $(DIR_SRC)/*.c)
OBJS := $(OBJS:.c=.o)
OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_BUILD)/%, $(OBJS))
vpath %.h $(DIR_INC)
vpath %.c $(DIR_SRC)
all : $(DIR_BUILD) $(APP)
@echo "Target File => $(APP)"
$(DIR_BUILD) :
$(MKDIR) $@
$(APP) : $(OBJS)
$(CC) -o $@ $^
$(DIR_BUILD)/%.o : %.c $(HDRS)
$(CC) $(CFLAGS) -o $@ -c $<
clean :
$(RM) $(DIR_BUILD)
如果是使用的c++编写的,那么复用性不好,目前只适用于C语言编写的
进一步的优化,再一次使用变量进行优化
.PHONY : all clean
DIR_BUILD := build
DIR_SRC := src
DIR_INC := inc
TYPE_INC := .h
TYPE_SRC := .c
TYPE_OBJ := .o
CC := gcc
CFLAGS := -I $(DIR_INC)
MKDIR := mkdir
RM := rm -rf
APP := $(DIR_BUILD)/app.out
HDRS := $(wildcard $(DIR_INC)/*$(TYPE_INC))
HDRS := $(notdir $(HDRS))
OBJS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC))
OBJS := $(OBJS:$(TYPE_SRC)=$(TYPE_OBJ))
OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_BUILD)/%, $(OBJS))
vpath %$(TYPE_INC) $(DIR_INC)
vpath %$(TYPE_SRC) $(DIR_SRC)
all : $(DIR_BUILD) $(APP)
@echo "Target File => $(APP)"
$(DIR_BUILD) :
$(MKDIR) $@
$(APP) : $(OBJS)
$(CC) -o $@ $^
$(DIR_BUILD)/%$(TYPE_OBJ) : %$(TYPE_SRC) $(HDRS)
$(CC) $(CFLAGS) -o $@ -c $<
clean :
$(RM) $(DIR_BUILD)
如果要增加扩展性,改进如下
1.定义LFLAGS变量,定义编译时需要的链接选项的,这个例子不需要,其他项目可能需要
比如使用了多线程就需要指定链接:-pthread
2.为了方便调试,需要加上if语句,来支持调试版本
.PHONY : all clean
DIR_BUILD := build
DIR_SRC := src
DIR_INC := inc
TYPE_INC := .h
TYPE_SRC := .c
TYPE_OBJ := .o
CC := gcc
LFLAGS :=
CFLAGS := -I $(DIR_INC)
ifeq ($(DEBUG),ture)
CFLAGS += -g
endif
MKDIR := mkdir
RM := rm -rf
APP := $(DIR_BUILD)/app.out
HDRS := $(wildcard $(DIR_INC)/*$(TYPE_INC))
HDRS := $(notdir $(HDRS))
OBJS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC))
OBJS := $(OBJS:$(TYPE_SRC)=$(TYPE_OBJ))
OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_BUILD)/%, $(OBJS))
vpath %$(TYPE_INC) $(DIR_INC)
vpath %$(TYPE_SRC) $(DIR_SRC)
all : $(DIR_BUILD) $(APP)
@echo "Target File => $(APP)"
$(DIR_BUILD) :
$(MKDIR) $@
$(APP) : $(OBJS)
$(CC) $(LFLAGS) -o $@ $^
$(DIR_BUILD)/%$(TYPE_OBJ) : %$(TYPE_SRC) $(HDRS)
$(CC) $(CFLAGS) -o $@ -c $<
clean :
$(RM) $(DIR_BUILD)
6.值得斟酌的问题
对于规模比较小的项目,makefile中是否也需要使用自动生成依赖关系的解决方案?
7.小结
- 工程项目中不希望源码文件夹在编译时被改动
- 模式规则的灵活运用使得makefile具有复用性
- 变量的灵活运用使得makefile具有扩展性
- 规模较小的项目没必要使用自动依赖关系的解决方案
- 规模较大的项目可以直接让源文件依赖于头文件(易于维护)