一、Makefile简介
Makefile是一个包含了一系列规则和指令的文件,它告诉make工具如何编译和链接程序。直接生成gcc的指令。make是一个在Unix和类Unix系统上广泛使用的构建自动化工具,它能够根据文件的时间戳自动判断哪些文件需要更新,并仅重新编译那些发生变化的部分,从而大大节省构建时间。
二、Makefile的基本结构
一个典型的Makefile包含以下元素:
变量定义:用于存储编译选项、源文件列表等常用信息,便于后续规则引用。
规则:每个规则指定了一个目标文件及其依赖文件,以及生成该目标所需的命令。
模式规则:使用通配符匹配文件,为特定类型的文件(如.c或.cpp)定义统一的编译规则。
伪目标:不以文件名命名的目标,通常用于执行清理、测试等非构建任务。
三、执行顺序
all:$(S_TARGET)
$(S_TARGET):$(SRC_OBJS)
$(AR) -r $@ $^
%.o:%.c
$(CC) $(INCLUDE_DIR) $(CFLAGS) $^ -o $@
%.o:%.cpp
$(CXX) $(INCLUDE_DIR) $(CXXFLAGS) $^ -o $@
首先,make会查看all目标,并发现它依赖于(S_TARGET)。
接着,make会检查(S_TARGET)是否比它的依赖(SRC_OBJS)新。
如果(S_TARGET)不存在或过时,make会开始处理(S_TARGET)的依赖,即(SRC_OBJS)列表中的对象文件。
对于列表中的每个对象文件,make会根据其扩展名选择合适的编译规则(.c文件使用%.o:%.c规则,.cpp文件使用%.o:%.cpp规则)。
一旦所有依赖的对象文件都是最新的,make就会执行构建$(S_TARGET)的规则,链接这些对象文件和任何指定的库来生成最终的目标文件。
四、高级特性
自动变量:如$@(目标文件)、$<(第一个依赖文件)、$^(所有依赖文件)
等,简化了规则的编写。
条件判断:允许根据环境变量或文件的存在与否选择不同的编译路径。
函数:Makefile提供了一系列内置函数,如wildcard(匹配文件)、patsubst(模式字符串替换)等,增强了其灵活性。
递归调用:在大型项目中,可以通过包含子Makefile来实现模块化构建。
五、关于CXXFLAGS
生成库文件:CXXFLAGS += -std=c++11 -O3 -DNDEBUG -c -fPIC -shared
生成执行文件:CXXFLAGS += -std=c++11 -O3 -DNDEBUG -fPIC
-std=c++11:指定使用C++11标准。C++11是C++语言的一个标准版本,引入了许多新特性,比如auto关键字、范围for循环、lambda表达式等。
-O3:这是一个优化级别标志,-O3表示使用最高级别的优化。编译器会尝试通过改变代码的结构、合并循环、使用更快的算法等手段来提高程序的运行速度。但需要注意的是,高级别的优化可能会导致编译时间增加,并且在某些情况下,可能会增加生成的二进制文件大小。
-DNDEBUG:这个标志用于定义宏NDEBUG。在C++标准库中,NDEBUG通常用于控制断言(assertions)的行为。当定义了NDEBUG时,所有的断言都会被禁用,这通常用于提高程序的运行速度,因为断言主要用于调试阶段。
-c:这个标志告诉编译器只进行编译(compile)操作,不进行链接(link)操作。也就是说,它会将源代码编译成目标文件(.o或.obj文件),但不会生成可执行文件。
-fPIC:这个标志用于生成位置无关代码(Position Independent Code)。这在创建共享库时非常重要,因为它允许库被加载到内存中的任何位置。
-shared:这个标志告诉编译器生成共享库(动态链接库)而不是可执行文件。共享库是一种特殊的文件,它包含了代码和数据,可以被多个程序同时使用,从而节省内存和磁盘空间。
六、库文件编译示例
CFLAGS += -O3 -DNDEBUG -c -fPIC -shared
CXXFLAGS += -std=c++11 -O3 -DNDEBUG -c -fPIC -shared
C_SRC_FILES =
# 因为我们只写了cpp的规则,这里不要用cc文件
CXX_SRC_FILES = src/RunParaManager.cpp
# just use g++ command
# g++ -g -I. -I.. -I../.. -I../../commonComponents/ src/RunParaManager.cc -c -o libRunParaManager.o
# g++ -std=c++11 -O3 -DNDEBUG -c -fPIC -shared -I. -I.. -I../.. -I../../commonComponents/ src/RunParaManager.cc -c -o libRunParaManager.o
# ar -r libRunParaManager.a libRunParaManager.o
INCLUDE_DIR = -I./ \
-I../ \
-I../.. \
-I../../commonComponents
LDFLAGS+=
QNX+=
ifeq (${type},qnx)
CFLAGS += -D_QNX_SOURCE -Vgcc_ntoaarch64le
CXXFLAGS += -D_QNX_SOURCE -Vgcc_ntoaarch64le
QNX += -D_QNX_SOURCE -Vgcc_ntoaarch64le
else ifeq (${type},UT)
CFLAGS += -ftest-coverage -fprofile-arcs
CXXFLAGS += -ftest-coverage -fprofile-arcs
LDFLAGS += -lgcov
endif
SRC_OBJS=${patsubst %.c, %.o, ${C_SRC_FILES}}
SRC_OBJS+=${patsubst %.cpp, %.o, ${CXX_SRC_FILES}}
S_TARGET := libRunParaManager.a
unexport CFLAGS
unexport CXX_SRC_FILES
all:$(S_TARGET)
$(S_TARGET):$(SRC_OBJS)
$(AR) -r $@ $^
%.o:%.c
$(CC) $(INCLUDE_DIR) $(CFLAGS) $^ -o $@
%.o:%.cpp
$(CXX) $(INCLUDE_DIR) $(CXXFLAGS) $^ -o $@
clean:
rm -rf $(S_TARGET)
rm -rf src/*.o
rm -rf src/*.gcno
rm -rf src/*.gcda
七、执行文件示例
主要区别是需要链接库
CFLAGS += -O3 -DNDEBUG -c -fPIC -shared
CXXFLAGS += -std=c++11 -O3 -DNDEBUG -fPIC
C_SRC_FILES =
CXX_SRC_FILES = testRunParaManager.cpp
# just use g++ command to replace make
# g++ -g -I. -I.. -I../.. -I../../../commonComponents/ testRunParaManager.cpp -o testRunParaManager -L .. -L ../../../libs/ -L ../../../libs/x86/ -lRunParaManager -lDesayLog -ldbConnector -lsqlite3 -pthread -ldl
INCLUDE_DIR = -I. \
-I../ \
-I../.. \
-I../../../ \
-I../../../commonComponents
LDFLAGS+=
QNX+=
ifeq (${type},qnx)
CFLAGS += -D_QNX_SOURCE -Vgcc_ntoaarch64le
CXXFLAGS += -D_QNX_SOURCE -Vgcc_ntoaarch64le
QNX += -D_QNX_SOURCE -Vgcc_ntoaarch64le
else ifeq (${type},UT)
CFLAGS += -ftest-coverage -fprofile-arcs
CXXFLAGS += -ftest-coverage -fprofile-arcs
LDFLAGS += -lgcov
endif
LIBDIRS = -L.. -L../../../libs/ -L../../../libs/x86/
LIBS = -lRunParaManager -lDesayLog -ldbConnector -lsqlite3 -pthread -ldl
SRC_OBJS=${patsubst %.c, %.o, ${C_SRC_FILES}}
SRC_OBJS+=${patsubst %.cpp, %.o, ${CXX_SRC_FILES}}
S_TARGET := testRunParaManager
unexport CFLAGS
unexport CXX_SRC_FILES
all:$(S_TARGET)
$(S_TARGET):$(SRC_OBJS)
@echo "Building target: $@"
$(CXX) $(QNX) $(INCLUDE_DIR) $(CXXFLAGS) $(SRC_OBJS) $(LIBDIRS) $(LIBS) $(LDFLAGS) -o $@
%.o:%.c
$(CC) $(INCLUDE_DIR) $(CFLAGS) -c $< -o $@
%.o:%.cpp
$(CXX) $(INCLUDE_DIR) $(CXXFLAGS) -c $< -o $@
clean:
rm -rf $(S_TARGET)
rm -rf src/*.o
rm -rf src/*.gcno
rm -rf src/*.gcda