ubuntu20.04/16.04下C++的通用Makefile模板解析
一、解析Makefile
本文给出万能Makefile的具体实现,以及对其中的关键点进行解析。
号称万能Makefile,一统江湖。我对原版的Makefile做了些修改。首先揭开它的庐山真面目:
####################################################
# Generic makefile - 万能Makefile
# for compiling and linking C++ projects on Linux
# Author: George Foot Modified:Jackie Lee
####################################################
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable's filename, and LIBS is a list of libraries to link in
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's
# command line of course, if you prefer to do it that way.
#
#
EXECUTABLE := main
LIBS :=
INCLUDES:=.
#
# # Now alter any implicit rules' variables if you like, e.g.:
CC:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found' error messages. If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files.
#
RM-F := rm -f
# # You shouldn't need to change anything below this point.
#
SRCS := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))
.PHONY : all deps objs clean veryclean rebuild info
all: $(EXECUTABLE)
deps : $(DEPS)
objs : $(OBJS)
clean :
@$(RM-F) *.o
@$(RM-F) *.d
veryclean: clean
@$(RM-F) $(EXECUTABLE)
rebuild: veryclean all
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))
info:
@echo $(SRCS)
@echo $(OBJS)
@echo $(DEPS)
@echo $(MISSING_DEPS)
@echo $(MISSING_DEPS_SOURCES)
注:1)命令行前的空白符必须为一个制表符(Tab);如,@$(RM-F) *.o前不是空格,而是一个制表符;
内容解析
1.Makefile基本语法
target为要生成的目标文件;dependency为target的依赖文件;command为用于生成target的命令行;
: …
(tab)
(tab)
.
.
.
2.赋值符号 := 与 =
:=与=的区别在于,符号:=表示立即展开变量值。例如:
A:=foo
B:=$(A)
A:=bar
这时,B的值仍为foo,因为它已被展开,不会再随A的值改变而改变。
3.符号#是Makefile的注释符号
4.wildcard函数
SRCS:=$(wildcard *.cpp) 表示列举当前目录中扩展名为.cpp的所有文件,然后赋值给变量SRCS。详细请google之。
5.patsubst函数
OBJS := ( p a t s u b s t (patsubst %.cpp,%.o, (patsubst(SRCS))表示,将$(SRCS)中所有满足模式%.cpp的字符串替换为%.o。
6.filter-out函数
$(filter-out ( A ) , (A), (A),(B))表示从B中过滤掉A中的内容,返回剩余内容;
7. “.PHONY”
用.PHONY修饰的target是“伪目标”,不需要生成真实的文件;make假定phony target是已经生成的,然后更新它后边的依赖文件和执行它下边的命令(command);
8.all deps objs clean veryclean rebuild info
这些都是“伪目标”。
all是第一个目标,所以输入make时它被默认执行;all生成或更新所有*.cpp文件对应的*.d文件和*.o文件,并链接所有*.o文件生成可执行文件$(EXECUTABLE)。
deps仅仅生成*.d文件;.d文件是什么文件?它包含了代码文件的依赖信息。
objs仅仅生成*.o文件;.o文件是C++代码编译后的中间结果文件,废话!
clean用于删除*.d文件和*.o文件。
veryclean删除*.d文件、*.o文件,还有名为$(EXECUTABLE)的可执行文件。
rebuild先调用veryclean清除结果文件,再调用all重新编译和链接。
info查看某些信息。
使用方法:
make deps即可执行deps;
9.ifneq…else…endif
条件语句,ifneq表示如果不想等,则…;
10.include 语句
include表示把的内容包含进来;
$(DEPS)是包含依赖信息的文件,每个源文件对应一个.d文件;-include $(DEPS)表示把这些依赖信息包含进来;
11.链接*.o文件,生成可执行文件
主菜来了!
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS)
(
a
d
d
p
r
e
f
i
x
−
l
,
(addprefix -l,
(addprefix−l,(LIBS))
( E X E C U T A B L E ) 为 可 执 行 文 件 名 ; (EXECUTABLE)为可执行文件名; (EXECUTABLE)为可执行文件名;(OBJS)为所有.o文件名; ( C C ) 在 这 里 是 g + + ; (CC)在这里是g++; (CC)在这里是g++;(addprefix -l,$(LIBS)添加引用库;
前面说好的*.d文件和*.o文件是怎么生成的呢?貌似没有命令指出要生成它们呀!请看隐含规则!
12. 隐含规则(Implicit rules)
( E X E C U T A B L E ) 依 赖 于 (EXECUTABLE)依赖于 (EXECUTABLE)依赖于(OBJS),但makefile中没有指明$(OBJS)依赖于谁,也没指明命令生成它们;
这时,make的隐含规则开始起作用;针对$(OBJS)中的每个目标,make自动调用:
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
依次生成.o文件和.d文件;
$<表示依赖文件列表的第一个文件名;
$@表示目标文件名;
之所以会生成.d文件,是由于“-MMD”这一编译选项。为g++加上这一选项后,编译器会生成文件依赖信息,并存放至.d文件中。
每一个.cpp文件相应地生成一个.d文件和一个.o文件。
13.@符号
命令行前的@符号表示不回显命令行;
14.CFLAGS和CPPFLAGS
这两者包含编译选项,更详细内容请Google之。
-g 添加gdb调试信息;
-Wall 提示warning信息;
-O3 表示第3级优化;
二、Makefile模板
#指定编译器
CC=g++
#找出当前目录下,所有的源文件(以.c或者是.cpp结尾)
SRCS:=$(shell find ./* -type f | egrep '\.c|\.cpp')
#确定c源文件对应的目标文件
OBJS:=$(patsubst %.c, %.o, $(filter %.c, $(SRCS)))
#$(warning SRCS is ${SRCS})
#$(warning OBJS is ${OBJS})
#确定cpp源文件对应的目标文件
OBJS+=$(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS)))
$(warning SRCS is ${SRCS})
$(warning OBJS is ${OBJS})
FLAG=-g
#找出当前目录下所有的头文件
TEMP_INCLUDE_PATH=$(shell find ./* -type d)
INCLUDE_PATH=$(patsubst %,-I %, $(TEMP_INCLUDE_PATH))
$(warning INCLUDE_PATH is ${INCLUDE_PATH})
#宏定义,用以格式化输出信息
CFLAGS=-DDEBUG_TEST\(fmt,arg...\)=printf\(\"Litost_Cheng\ \"fmt,\#\#arg\)
#链接过程中,所需要添加的一些依赖库,以及配置
#MODE为1 视为生成可执行文件,否则都视为生成可执行文件
$(warning MODE is ${MODE})
ifeq (${MODE}, 1)
LINKFLG=-shared -lpthread -std=c++0x
OBJFLG=-fPIC
TARGET=lib$(notdir $(shell pwd)).so
$(warning Create Share Library [${TARGET}]!)
else
LINKFLG=-lpthread -std=c++0x
TARGET=$(notdir $(shell pwd))
$(warning Create Execute File [${TARGET}]!)
endif
#生成目标文件时,所需要添加的配置
$(warning TARGET is ${TARGET})
$(TARGET):$(OBJS)
$(CC) -o $@ $^ $(FLAG) $(CFLAGS) $(INCLUDE_PATH) $(LINKFLG)
$(OBJS):$(SRCS)
#找出同名的源文件
# echo $(basename $@)
# echo $(filter $(basename $@)%, $^)
$(CC) $(CFLAGS) -o $@ -c $(filter $(basename $@)%, $^) -g $(INCLUDE_PATH) $(OBJFLG)
clean:
rm -rf $(TARGET) $(OBJS) lib$(notdir $(shell pwd)).so
相关文章
- 【C/C++学院】0814-引用高级、引用高级增加/auto自动变量自动根据类型创建数据/Bool/Enum/newdelete全局/大数据乘法与结构体/函数模板与auto/宽字符本地化/inline
- 【C/C++学院】(12)C++标准模板库STL
- Effective C++笔记(六):继承与面向对象设计
- c++模板学习05之类模板
- C++中new与malloc的区别
- C++ 获取十六进制随机数
- C++函数模板(模板函数)详解
- c++ split模板实现
- C++11实现模板手柄:委托构造函数、defaultkeyword分析
- C++ Primer第九章课后编程问题
- C++学习笔记36 (模板的细节明确template specialization)和显式实例(template instantiation)
- AI模型C++部署:ubuntu安装Cython并使用C/C++调用python动态库【附加c++与python互相调用算法demo程序接口的源码】
- C++模板类实例化
- C++函数模板的重载
- C++类模板(一)
- C++成员变量初始化列表中初始化顺序(七十)
- C++ 实现十大排序算法
- Linux C/C++开发
- C++ 模板
- C++11 局部和匿名类型作模板实参
- C++11 快速初始化成员变量
- OpenCV(C++)图像处理基础05:图像的亮度与对比度
- C++的学习心得和知识总结(十七)|Visual Studios 2019配置游戏开发引擎HGE1.8教程
- C++之Singleton单例和单例模板类讲解
- 跟老菜鸟学C++-蔡军生-专题视频课程
- C++ list不是模板
- 关于C++中的模板