工程级Makefile编译模板

文章目录

1. 一点说明

2. 顶层目录的Makefile模板

3. 顶层目录的共通设定

4. 子目录中的Makefile模板

5. 应用实例 

6. 后记


1. 一点说明

如果要使用Makefile编译一个工程,则需要使用多个Makefile文件共同作用才比较合理。工程中的每个目录都有一个Makefile文件,负责编译当前目录的源文件,然后将编译好的对象文件打包,供上一级的Makefile使用。经过学习各种资料,在这里记录一种多个Makefile文件共同编译工程的模板,以供学习和查看。

2. 顶层目录的Makefile模板

顶层目录的Makefile模板的内容如下,附上代码的说明,便于更好的理解和记忆,文件名为Makefile,放在顶层目录中。

#最终目标名称定义
TGT := main
#顶层目录的获取,export关键字,表面TOP_DIR在子目录中可以使用,相当于全局变量,
#否则,定义的变量仅在本文件中有用
export TOP_DIR := $(shell pwd)
#导入子MaKefile文件,Header.mk是放在顶层目录中,用来导入.h文件
-include $(TOP_DIR)/Header.mk
#CXXFLAGS是Makefile的环境变量,用来定义编译选项
CXXFLAGS := -Wall -O2
#SUB_DIR是自定义变量,记录工程中当前目录的子目录
SUB_DIR := src
# SUB_TGT是当前目录各个文件编译后,打包所得的文件的命名,当然,它也是自定义变量,
# 并且是全局变量,因为以下每一个目录的打包名称都可以叫‘build_in.o’这个统一的名称
#,这么做是为了方便起见,你也可以为每一个目录起一个不同的名字。
export SUB_TGT := bulid_in.o
# SRC和OBJ都是自定义名称,SRC是取得当前目录中的.cpp文件的名称,wildcard是Makefile
# 内置的函数,为了获取当前目录中满足一定条件的文件的名称,patsubst也是内置函数,它是替
# 函数,利用已知后缀名的一些列的文件名,转换得到另一后缀名的一系列系同名文件。本Makefile
# 中就是.cpp的文件,换成.o的文件
SRC := $(wildcard *.cpp)
OBJ := $(patsubst %.cpp,%.o,$(SRC))

# all是伪目标
all:$(TGT)
   @echo "make successfull [0]"

#总目标的依赖关系,总目标依赖当前文件的.o文件和子目录打包后的目标build_in.o
#其中$(SUB_DIR:=/$(SUB_TGT))表示各子目录下的build_in.o
$(TGT):$(OBJ) $(SUB_DIR)
   $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OBJ) $(SUB_DIR:=/$(SUB_TGT))  -o $@
#调用各个子目录中的子Makefile,$@代表依赖关系中的目标
$(SUB_DIR):
   $(MAKE) -C $@

#当前目录下各个文件的编译目标和源文件的依赖关系,$<代表依赖关系中被依赖的各个文件的统称。
%.o:%.cpp
   $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

# 依赖关系生成.d文件中记录着。o依赖.cpp和.h文件的关系,书写此依赖关系,是为了防止修改.h
# 文件,对应的.o文件没有重新编译,进而导致整个总目标没有正确的编译
%.d:%.cpp
   $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MM $< -o $@

#导入上一步生成的.d中记录的关系
sinclude $(SRC:.cpp=.d)

#伪目标,是为了重新编译的方便,清楚编译所产生的所有文件
clean:
   $(RM) $(TGT) $(OBJ) $(SRC:.cpp=.d)
   $(MAKE) -C $(SUB_DIR) $@            #调用子目录中的clean
   @echo "clean successful[0]"

#伪目标的声明
.PHONY:all clean $(SUB_DIR)

3. 顶层目录的共通设定

顶层目录的共通设定的目的是设定编译选项变量CPPFLAGS, 用此变量累计各个模块的.h文件,文件名Header.mk,放在顶层目录中,代码示例如下

CPPFLAGS := -I.
CPPFLAGS += -I$(TOP_DIR)
CPPFLAGS += -I$(TOP_DIR)/src
...

4. 子目录中的Makefile模板

值得说明的是,各个子目录中的Makefile的内容可以是相同的,如果子目录下还有子目录,即二级或三级子目录,可以参考顶层的目录继续调用其下一级的子目录中的Makefile,以下给出的是子目录中没有二级或三级子目录的Makefile的写法。文件名同样是Makefile,放在了各个子目录中。

#导顶层目录中共通设定Header.mk
-include $(TOP_DIR)/Header.mk

#----get common files---
SRC := $(wildcard *.cpp)
OBJ := $(SRC:.cpp=.o)
DEP := $(SRC:.cpp=.d)

# 打包各文件的编译对象,得到build_in.o
$(SUB_TGT):$(OBJ)
    $(LD) -r $^ -o $@

#获取各文件对应的.d文件
$(DEP):$(SRC)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $< -o  $@

#导入d文件记录的依赖关系,即.o对.cpp和.h的依赖
sinclude $(DEP)

clean:
    $(RM) *.o *.d $(SUB_TGT)

.PHONY:clean

5. 应用实例 

应用示例见

一个组合模式的例子+makefile模板_青草地溪水旁的博客-CSDN博客

6. 后记

上述记录的模板,可以应用在项目中,非常方便,在套用的过程中,如果出错,需要慢慢调试,在调试的过程中学习Makefile,会学得更踏实,凡知识和技能都是在应用过程时摸爬滚打中,才能真正的掌握。

你可能感兴趣的:(Makefile,linux)