目的:使用一个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.若有侵权,联系即删