简易makefile笔记

目的:使用一个makefile,实现多源文件夹和多库文件夹的编译。

目录结构:test.c作为main函数所在文件,内部引用了test_a,test_b,test_c的函数和一个lib库。

方案1缺点,每次make所有文件都会重新编译。

原因:${TARGET_OUT}:$(notdir ${OBJECT}) ${LIB_OUT}。最终文件生成依赖$(notdir ${OBJECT}),会在根路径下寻找o文件,但是所有o文件都存在于out/obj下,找不到后就会重新生成依赖项

CC:=gcc
AR:=ar

BASE_DIR=${shell pwd}
BIN_DIR=${BASE_DIR}/out/bin
OBJ_DIR=${BASE_DIR}/out/obj
LIB_DIR=${BASE_DIR}/out/lib
SRC_DIR=${BASE_DIR}

LIB_NAME=lib_test.a
LIB_INCLUDE_LIST=-I${BASE_DIR}/lib/include
LIB_SRC_LIST=${BASE_DIR}/lib/src
LIB_OUT=${LIB_DIR}/${LIB_NAME}

INCLUDE_LIST+=-I${BASE_DIR}/a/include
INCLUDE_LIST+=-I${BASE_DIR}/b/include
INCLUDE_LIST+=-I${BASE_DIR}/c/include

SRC_LIST+=${BASE_DIR}
SRC_LIST+=${BASE_DIR}/a/src
SRC_LIST+=${BASE_DIR}/b/src
SRC_LIST+=${BASE_DIR}/c/src

VPATH+=${SRC_LIST}
VPATH+=${LIB_SRC_LIST}

CFLAGS+=-g 
CFLAGS+=${INCLUDE_LIST}
CFLAGS+=${LIB_INCLUDE_LIST}
CFLAGS+=-L${LIB_DIR}


TARGET=test_out
TARGET_OUT=${BIN_DIR}/${TARGET}

SOURCE=$(foreach src_list_temp,${SRC_LIST},${shell find ${src_list_temp} -maxdepth 1 -name "*.c"})
OBJECT=$(foreach src_temp,${SOURCE},$(subst ${SRC_DIR},${OBJ_DIR},$(patsubst %.c,%.o,${src_temp})))

LIB_SOURCE=$(foreach lib_src_list_temp,${LIB_SRC_LIST},${shell find ${lib_src_list_temp} -maxdepth 1 -name "*.c"})
LIB_OBJECT=$(foreach lib_src_temp,${LIB_SOURCE},$(subst ${SRC_DIR},${OBJ_DIR},$(patsubst %.c,%.o,${lib_src_temp})))


${TARGET_OUT}:$(notdir ${OBJECT}) ${LIB_OUT}
	@mkdir -p ${BIN_DIR}
	${CC} -o $@ $(foreach temp,$(filter %.o,$^),${shell find ${OBJ_DIR} -name ${temp}}) ${LIB_OUT}

%.o:%.c
	@mkdir -p ${OBJ_DIR}$(subst ${SRC_DIR},,$(subst .,,$(dir $^)))
	${CC} -c -o ${OBJ_DIR}$(subst ${SRC_DIR},,$(subst .,,$(dir $^)))$@ $^ ${CFLAGS}

${LIB_OUT}:$(notdir ${LIB_OBJECT})
	@mkdir -p ${LIB_DIR}
	${AR} -cr $@ $(foreach temp,$^,${shell find ${OBJ_DIR} -name ${temp}})


.PHONY:clean
clean:
	@find ./ -name "*.i" -or -name "*.s" -or -name "*.o" -or -name "${TARGET}" -or -name "*.a" | xargs rm -f
	@rm -rf ${BASE_DIR}/out

.PHONY:print-%
print-%:
	@echo '$*="${$*}"'

方案2缺点,修改文件后不重新编译文件。

原因:${OBJECT} ${LIB_OBJECT}: 前面的OBJ是带有路径的变量,但是后面却没有相应的依赖。每当make时,可以查找到o文件,但是没法查找o文件依赖的c文件,导致不会重新编译,只有删除对应o文件才能重新编译

CC:=gcc
AR:=ar

BASE_DIR=${shell pwd}
BIN_DIR=${BASE_DIR}/out/bin
OBJ_DIR=${BASE_DIR}/out/obj
LIB_DIR=${BASE_DIR}/out/lib
SRC_DIR=${BASE_DIR}

LIB_NAME=lib_test.a
LIB_INCLUDE_LIST=-I${BASE_DIR}/lib/include
LIB_SRC_LIST=${BASE_DIR}/lib/src
LIB_OUT=${LIB_DIR}/${LIB_NAME}

INCLUDE_LIST+=-I${BASE_DIR}/a/include
INCLUDE_LIST+=-I${BASE_DIR}/b/include
INCLUDE_LIST+=-I${BASE_DIR}/c/include

SRC_LIST+=${BASE_DIR}
SRC_LIST+=${BASE_DIR}/a/src
SRC_LIST+=${BASE_DIR}/b/src
SRC_LIST+=${BASE_DIR}/c/src

VPATH+=${SRC_LIST}
VPATH+=${LIB_SRC_LIST}

CFLAGS+=-g 
CFLAGS+=${INCLUDE_LIST}
CFLAGS+=${LIB_INCLUDE_LIST}
CFLAGS+=-L${LIB_DIR}


TARGET=test_out
TARGET_OUT=${BIN_DIR}/${TARGET}

SOURCE=$(foreach src_list_temp,${SRC_LIST},${shell find ${src_list_temp} -maxdepth 1 -name "*.c"})
OBJECT=$(foreach src_temp,${SOURCE},$(subst ${SRC_DIR},${OBJ_DIR},$(patsubst %.c,%.o,${src_temp})))

LIB_SOURCE=$(foreach lib_src_list_temp,${LIB_SRC_LIST},${shell find ${lib_src_list_temp} -maxdepth 1 -name "*.c"})
LIB_OBJECT=$(foreach lib_src_temp,${LIB_SOURCE},$(subst ${SRC_DIR},${OBJ_DIR},$(patsubst %.c,%.o,${lib_src_temp})))


${TARGET_OUT}:${OBJECT} ${LIB_OUT}
	@mkdir -p ${BIN_DIR}
	${CC} -o $@ $^

${OBJECT} ${LIB_OBJECT}: 
	@mkdir -p $(dir $@)
	${CC} -c -o $@ $(patsubst %.o,%.c,$(subst ${OBJ_DIR},$(SRC_DIR),$@))  ${CFLAGS}

${LIB_OUT}:${LIB_OBJECT}
	@mkdir -p ${LIB_DIR}
	${AR} -cr $@ $^


.PHONY:clean
clean:
	@find ./ -name "*.i" -or -name "*.s" -or -name "*.o" -or -name "${TARGET}" -or -name "*.a" | xargs rm -f
	@rm -rf ${BASE_DIR}/out

.PHONY:print-%
print-%:
	@echo '$*="${$*}"'

方案3缺点:所有的o文件在同一文件夹下,没有更细的区分

CC:=gcc
AR:=ar

BASE_DIR=${shell pwd}
BIN_DIR=${BASE_DIR}/out/bin
OBJ_DIR=${BASE_DIR}/out/obj
LIB_DIR=${BASE_DIR}/out/lib
SRC_DIR=${BASE_DIR}

LIB_NAME=lib_test.a
LIB_INCLUDE_LIST=-I${BASE_DIR}/lib/include
LIB_SRC_LIST=${BASE_DIR}/lib/src
LIB_OUT=${LIB_DIR}/${LIB_NAME}

INCLUDE_LIST+=-I${BASE_DIR}/a/include
INCLUDE_LIST+=-I${BASE_DIR}/b/include
INCLUDE_LIST+=-I${BASE_DIR}/c/include

SRC_LIST+=${BASE_DIR}
SRC_LIST+=${BASE_DIR}/a/src
SRC_LIST+=${BASE_DIR}/b/src
SRC_LIST+=${BASE_DIR}/c/src

VPATH+=${SRC_LIST}
VPATH+=${LIB_SRC_LIST}

CFLAGS+=-g 
CFLAGS+=${INCLUDE_LIST}
CFLAGS+=${LIB_INCLUDE_LIST}
CFLAGS+=-L${LIB_DIR}


TARGET=test_out
TARGET_OUT=${BIN_DIR}/${TARGET}

SOURCE=$(foreach src_list_temp,${SRC_LIST},${shell find ${src_list_temp} -maxdepth 1 -name "*.c"})
OBJECT=$(foreach src_temp,${SOURCE},${OBJ_DIR}/$(notdir $(patsubst %.c,%.o,${src_temp})))

LIB_SOURCE=$(foreach lib_src_list_temp,${LIB_SRC_LIST},${shell find ${lib_src_list_temp} -maxdepth 1 -name "*.c"})
LIB_OBJECT=$(foreach lib_src_temp,${LIB_SOURCE},${OBJ_DIR}/$(notdir $(patsubst %.c,%.o,${lib_src_temp})))


${TARGET_OUT}:${OBJECT} ${LIB_OUT}
	@mkdir -p ${BIN_DIR}
	${CC} -o $@ $^

${OBJ_DIR}/%.o:%.c 
	@mkdir -p ${OBJ_DIR}
	${CC} -c -o $@ $^ ${CFLAGS}

${LIB_OUT}:${LIB_OBJECT}
	@mkdir -p ${LIB_DIR}
	${AR} -cr $@ $<

.PHONY:clean
clean:
	@find ./ -name "*.i" -or -name "*.s" -or -name "*.o" -or -name "${TARGET}" -or -name "*.a" | xargs rm -f
	@rm -rf ${BASE_DIR}/out

.PHONY:print-%
print-%:
	@echo '$*="${$*}"'

方案4:在方案3的基础上增加了自动依赖

重点:直接产生的依赖文件格式为:

test.o: test.c /home/jin/test_jin_V4/a/include/test_a.h \
 /home/jin/test_jin_V4/b/include/test_b.h        \…………省略

这里和规则${OBJ_D_DIR}/%.d:%.c是重复的,所以编译时会使用第一个出现的规则。

但是,makefile有个隐藏规则,目标相同的多条规则会自动进行合并的机制。

这里,采取指令:

sed '1s,^,$$\{OBJ_DIR\}/,g'  $@.$$$$ > $@

将依赖文件变为

这样,相同的目标文件第一条规则的cmd段为空,会将两个规则合并

ps:这里感谢大佬Makefile中自动生成头文件依赖 - Yong_无止境 - 博客园 (cnblogs.com)

CC:=gcc
AR:=ar

BASE_DIR=${shell pwd}
BIN_DIR=${BASE_DIR}/out/bin
OBJ_DIR=${BASE_DIR}/out/obj
OBJ_D_DIR=${BASE_DIR}/out/obj_d
LIB_DIR=${BASE_DIR}/out/lib
SRC_DIR=${BASE_DIR}

LIB_NAME=lib_test.a
LIB_INCLUDE_LIST=-I${BASE_DIR}/lib/include
LIB_SRC_LIST=${BASE_DIR}/lib/src
LIB_OUT=${LIB_DIR}/${LIB_NAME}

INCLUDE_LIST+=-I${BASE_DIR}/a/include
INCLUDE_LIST+=-I${BASE_DIR}/b/include
INCLUDE_LIST+=-I${BASE_DIR}/c/include

SRC_LIST+=${BASE_DIR}
SRC_LIST+=${BASE_DIR}/a/src
SRC_LIST+=${BASE_DIR}/b/src
SRC_LIST+=${BASE_DIR}/c/src

VPATH+=${SRC_LIST}
VPATH+=${LIB_SRC_LIST}

CFLAGS+=-g 
CFLAGS+=${INCLUDE_LIST}
CFLAGS+=${LIB_INCLUDE_LIST}
CFLAGS+=-L${LIB_DIR}


TARGET=test_out
TARGET_OUT=${BIN_DIR}/${TARGET}

SOURCE=$(foreach src_list_temp,${SRC_LIST},${shell find ${src_list_temp} -maxdepth 1 -name "*.c"})
OBJECT=$(foreach src_temp,${SOURCE},${OBJ_DIR}/$(notdir $(patsubst %.c,%.o,${src_temp})))
OBJECT_D=$(foreach src_temp,${SOURCE},${OBJ_D_DIR}/$(notdir $(patsubst %.c,%.d,${src_temp})))


LIB_SOURCE=$(foreach lib_src_list_temp,${LIB_SRC_LIST},${shell find ${lib_src_list_temp} -maxdepth 1 -name "*.c"})
LIB_OBJECT=$(foreach lib_src_temp,${LIB_SOURCE},${OBJ_DIR}/$(notdir $(patsubst %.c,%.o,${lib_src_temp})))
LIB_OBJECT_D=$(foreach lib_src_temp,${LIB_SOURCE},${OBJ_D_DIR}/$(notdir $(patsubst %.c,%.d,${lib_src_temp})))

${TARGET_OUT}:${OBJECT} ${LIB_OUT}
	@mkdir -p ${BIN_DIR};\
	${CC} -o $@ $^


include ${OBJECT_D}
include ${LIB_OBJECT_D}

${OBJ_DIR}/%.o:%.c
	@mkdir -p ${OBJ_DIR};\
	${CC} -c -o $@ $< ${CFLAGS} 

${OBJ_D_DIR}/%.d:%.c
	@mkdir -p ${OBJ_D_DIR};\
	${CC} -MM $< ${CFLAGS} > $@.$$$$;\
	sed '1s,^,$$\{OBJ_DIR\}/,g'  $@.$$$$ > $@;\
	rm -rf $@.$$$$


${LIB_OUT}:${LIB_OBJECT}
	@mkdir -p ${LIB_DIR};\
	${AR} -cr $@ $<

.PHONY:clean
clean:
	@find ./ -name "*.i" -or -name "*.s" -or -name "*.o" -or -name "${TARGET}" -or -name "*.a" | xargs rm -f
	@rm -rf ${BASE_DIR}/out

.PHONY:print-%
print-%:
	@echo '$*="${$*}"'

写在文后:

1.本文章只作为自我的记录,并不保证正确和规范。
2.makefile知识点参考了文章,详细知识请移步阅读:跟我一起写 Makefile(一)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客_makefile

3.若有侵权,联系即删

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值