在上一个系列3的文章:https://blog.csdn.net/u010312436/article/details/52461906 中已经实现具有子目录层次结构的makefile写法,即主目录Makefile调用到每个子目录中的Makefile编译相应子目录的代码。但是每增加一个子目录又得为这个子目录添加一个为该子目录编译的Makefile文件,似乎有点麻烦。于是想到是不是可以写一个Makefile的模板文件,主目录和子目录只需要include这个模板,并且修改写变量就可以。
百度搜索了下,参考了下https://blog.csdn.net/hmsiwtv/article/details/20905177/这篇文章并修改了下使其可以编译c和c++程序。感谢这篇文章作者的分享。
(1)首先看下我的目录结构:
文章图片
将Makefile模板文件Makefile.base放在include目录下, lib目录存放logout,receiver, responser, sender子模块编译出的静态库。
其中logout为c语言写的程序,其他三个子目录为c++写的程序。
Makefile 的模板 Makefile.base如下,具体说明可以查看https://blog.csdn.net/hmsiwtv/article/details/20905177/:
###########MakeFile.env##########
# Top level pattern, include by Makefile of child directory
# in which variable like TOPDIR, TARGET or LIB may be neededCC=gcc
XX=g++MAKE=makeAR=ar cr
RM = -rm -rfCFLAGS+=-Wall -g### 查找当前目录下的子目录####
dirs:=$(shell find . -maxdepth 1 -type d)
dirs:=$(basename $(patsubst ./%,%,$(dirs)))
dirs:=$(filter-out $(exclude_dirs),$(dirs))
SUBDIRS := $(dirs)XX_SRCS=$(wildcard *.cpp)
SRCS=$(wildcard *.c)XX_OBJS=$(XX_SRCS:%.cpp=%.o)
OBJS+=$(SRCS:%.c=%.o)XX_DEPENDS=$(XX_SRCS:%.cpp=%.d)
DEPENDS=$(SRCS:%.c=%.d)all:$(TARGET) $(XX_TARGET) $(LIB) subdirs$(LIB):$(XX_OBJS) $(OBJS)
$(AR)$@$^
cp $@ $(LIBPATH)#######如果不是main 所在的目录
#######当target和xx_target都不存在的时候
#ifeq ($(TARGET)$(XX_TARGET),)
# for dir in $(SUBDIRS);
\
#do $(MAKE) -C $$dir all||exit 1;
\
# done
#endif####编译目标文件前先编译子目录的文件#####
$(TARGET):$(OBJS) subdirs
$(CC) -o $@ $< $(LDFLAGS)
#cp $@ $(EXEPATH)$(XX_TARGET):$(XX_OBJS) subdirs
$(XX) -o $@ $< $(LDFLAGS)
#cp $@ $(EXEPATH)subdirs:$(SUBDIRS)
for dir in $(SUBDIRS);
\
do $(MAKE) -C $$dir all||exit 1;
\
done$(OBJS):%.o:%.c
$(CC) -c $< -o $@ $(CFLAGS)
$(XX_OBJS):%.o:%.cpp
$(XX) -c $< -o $@ $(CFLAGS)-include $(DEPENDS)$(DEPENDS):%.d:%.c
set -e;
rm -f $@;
\
$(CC) -MM $(CFLAGS) $< > $@.$$$$;
\
sed 's,\($*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@;
\
rm $@.$$$$-include $(XX_DEPENDS)$(XX_DEPENDS):%.d:%.cpp
set -e;
rm -f $@;
\
$(XX) -MM $(CFLAGS) $< > $@.$$$$;
\
sed 's,\($*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@;
\
rm $@.$$$$
.PHONY : clean
clean:
$(RM) mainApp lib/*.a
for dir in $(SUBDIRS);
\
do $(MAKE) -C $$dir clean||exit 1;
\
done
$(RM) $(TARGET) $(LIB)$(OBJS) $(DEPENDS) \
$(XX_TARGET) $(XX_OBJS) $(XX_DEPENDS)
主目录下的Makefile如下:
TOPDIR=.exclude_dirs= include libXX_TARGET=mainAppLIBPATH=$(TOPDIR)/lib/
EXEPATH=$(TOPDIR)CFLAGS=-I$(TOPDIR)/include/ -I$(TOPDIR)/sender/ -I$(TOPDIR)/receiver/\
-I$(TOPDIR)/responser/ -I$(TOPDIR)/logout/
LDFLAGS= -L$(LIBPATH) -lSender -lResponser -lReceiver -lLogout -lpthread -lrtinclude $(TOPDIR)/include/Makefile.base
exclude_dirs:表示遍历该文件下子目录时需要排除的目录,因为include和lib目录不需要编译所以在这里把它们添加进去。
XX_TARGET:表示编译出的目标可执行文件
CFLAGS 指定头文件的目录
LDFLAGS 指定需要的链接库
可以看出这个makefile只需定义一些参数然后include 模板Makefile.base文件即可。
再来看下子目录的Makefile写法:
TOPDIR=./..LIB=libReceiver.aLIBPATH=$(TOPDIR)/lib
CFLAGS= -I$(TOPDIR)/include/ -I$(TOPDIR)/responser/ -I./include $(TOPDIR)/include/Makefile.base
也变得更简单了。
【Makefile学习笔记系列4(Makefile模板化)】有了模板其他目录的Makefile写的更简单了有木有。哈哈
代码github仓库地址:https://github.com/fanchenxinok/Makefile_models
有错误麻烦指出,谢谢。
推荐阅读
- 定位|浅谈大规模红蓝对抗攻与防
- android|Android驱动例子(LED灯控制)
- 工具使用|glmark2跑分工具移植到arm实机上运行
- 编程语言|学习笔记:relocation R_X86_64_32 against `.rodata' can not be used when making a shared object;