Linux下C++的通用Makefile与解析

本文给出万能Makefile的具体实现,以及对其中的关键点进行解析。所谓C++万能Makefile,即可编译链接所有的C++程序,而只需作很少的修改。

号称万能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    # 可执行文件名
LIBDIR:=              # 静态库目录
LIBS :=               # 静态库文件名
INCLUDES:=.           # 头文件目录
SRCDIR:=              # 除了当前目录外,其他的源代码文件目录
#
# # 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) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
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,[email protected])
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(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的命令行;

<target> : <dependency> <dependency> ...
(tab)<command>
(tab)<command>
 .
 .
 .

2.赋值符号 := 与 =

:=与=的区别在于,符号:=表示立即展开变量值。例如:

A:=foo

B:=$(A)

A:=bar

这时,B的值仍为foo,因为它已被展开,不会再随A的值改变而改变。

3.符号#是Makefile的注释符号

4.wildcard函数

SRCS:=$(wildcard *.cpp) 表示列举当前目录中扩展名为.cpp的所有文件,然后赋值给变量SRCS。详细请google之。

5.patsubst函数

OBJS := $(patsubst %.cpp,%.o,$(SRCS))表示,将$(SRCS)中所有满足模式%.cpp的字符串替换为%.o。

6.filter-out函数

$(filter-out $(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 <files>语句

include表示把<files>的内容包含进来;

$(DEPS)是包含依赖信息的文件,每个源文件对应一个.d文件;-include $(DEPS)表示把这些依赖信息包含进来;

11.链接*.o文件,生成可执行文件

主菜来了!

$(EXECUTABLE) : $(OBJS)
        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))

$(EXECUTABLE)为可执行文件名;$(OBJS)为所有.o文件名;$(CC)在这里是g++;$(addprefix -l,$(LIBS)添加引用库;

前面说好的*.d文件和*.o文件是怎么生成的呢?貌似没有命令指出要生成它们呀!请看隐含规则!

12. 隐含规则(Implicit rules)

$(EXECUTABLE)依赖于$(OBJS),但makefile中没有指明$(OBJS)依赖于谁,也没指明命令生成它们;

这时,make的隐含规则开始起作用;针对$(OBJS)中的每个目标,make自动调用:

$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o [email protected]

依次生成.o文件和.d文件;

$<表示依赖文件列表的第一个文件名;

[email protected]表示目标文件名;

之所以会生成.d文件,是由于“-MMD”这一编译选项。为g++加上这一选项后,编译器会生成文件依赖信息,并存放至.d文件中。

每一个.cpp文件相应地生成一个.d文件和一个.o文件。

[email protected]符号

命令行前的@符号表示不回显命令行;

14.CFLAGS和CPPFLAGS

这两者包含编译选项,更详细内容请Google之。

-g 添加gdb调试信息;

-Wall 提示warning信息;

-O3 表示第3级优化;

时间: 2024-10-29 19:11:56

Linux下C++的通用Makefile与解析的相关文章

(原创)Linux下的floating point exception错误解析

很多人也许都碰到过这样的错误:linux下程序刚一运行就报错:Floating point exception. 其实这个问题很容易排查,绝大多数情况情况都是逻辑的问题,如:c = a/b;或 c = a%b; 如果这里面的b不小心是0,则一定会出现Floating point exception的问题,大家可以检查检查啦!哈哈! 当然也有可能是版本的原因:同一个程序在一台高版本Linux上运行时没有问题,而在另一台低版本机器上运行报Floating Point Exception时,那么这极有

Linux下的ELF可执行文件的格式解析 (转)

LInux命令只是和Kernel一起被编译进操作系统的存在于FS的ELF格式二进制文件,或者权限足够的脚本,或者一个软链 ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西.它自最早在 System V 系统上出现后,被 xNIX 世界所广泛接受,作为缺省的二进制文件格式来使用.可以说,ELF是构成众多xNIX系统的基础之一,所以作为嵌入式Linux系统

linux下eclipse用自定义Makefile交叉编译

eclipse的安装就不介绍了,大家自行安装,下面进入正题. 一)打开eclipse,新建个C或C++工程 建一个Makefile project,再把目前的原代码与写好的makefile复制到婚丧婚丧建好的工程目录下,按F5刷新就可以把代码加入工程中 二,点击project->properties,选择c/c++build中的Environment ,添加PATH跟系统的PATH一样,这个目的我们是要把交叉编译器的路径加到PATH中.如果已有PATH,看有没有交叉编译器的路径,有的话增加即可.

linux下 几个常用makefile模板,亲测可用

一 生成动态链接库的模板: 1 ####################### 2 # Makefile 3 ####################### 4 5 # compile and lib parameter 6 CC := g++ 7 LIBS := 8 LDFLAGS := 9 DEFINES := 10 INCLUDE := -I. 11 CFLAGS := 12 CXXFLAGS:= 13 14 # link parameter 15 #LIB := libfunc.so 1

linux下arm汇编的常用指令解析

1. ldr 和 str : (1) ldr 作为指令,叫做寄存器加载指令.将内存中的值加载到寄存器中. (2) ldr 作为伪指令,实现一个32位常数或地址值加载到寄存器中.后面加载的常量或地址值标号前面必须有一个 “=” ,编译器会将伪指令替换成指令实现. (3) str 将寄存器中的值保存到内存单元中. 2. .long 伪操作,给数值分配内存单元. start: virable: .long start 如上,表示将start表示的值存到virable所代表的内存中. virable:

一个简单的通用Makefile实现

Makefile是Linux下程序开发的自动化编译工具,一个好的Makefile应该准确的识别编译目标与源文件的依赖关系,并且有着高效的编译效率,即每次重新make时只需要处理那些修改过的文件即可.Makefile拥有很多复杂的功能,这里不可能也没必要一一介绍,为了简化问题的复杂性,本文仅和大家讨论针对单目录下的C/C++项目开发,如何写一个通用的Makefile. 首先,我们假设当前工程目录为prj/,该目录下有6个文件,分别是:main.c.abc.c.xyz.c.abc.h.xyz.h和M

Linux下C++的编程——GDB进行程序调试

GDB简介 我们在Linux下C++的编程--开偏介绍一文中已经简单介绍了GDB的功能,是类Unix系统的主要调试工具,可进行断点调试,跟踪程序,动态改变执行环境等功能. 从一个程序开始调试 下面我们就从一个程序开始讲解一下GDB的简单用法.假设我们有如下的程序: GDBTest1.cpp #include <iostream> int Accumulation(int n) { int result = 0; for(int i = 0; i < n; i ++) { result +

android SDK下各目录的用途,以及在不同系统下哪些是通用的。

Android SDK 目录下有很多文件夹,主要都是干什么的呢? 1. add-ons 这里面保存着附加库,比如google Maps,当然你如果安装了OPhone SDK,这里也会有一些类库在里面. 2. docs 这里面是Android SDK API参考文档,所有的API都可以在这里查到. 3. market_licensing 作为Android Market版权保护组件,一般发布付费应用到电子市场可以用它来反盗版. 4. platforms 是每个平台的SDK真正的文件,里面会根据AP

windos下创建软链接,附Linux下创建软链接

用过好多次老是忘记: 写在这里忘了就来看下 Windows下(win7) mklink /D D:\phpStudy\WWW\yii\school\teacher\web\uploads\public D:\phpStudy\WWW\yii\school\api\web\uploads\public 参数解析: 第一个参数:/D 创建软链接 不可或缺 第二个参数:D:\phpStudy\WWW\yii\school\teacher\web\uploads\public  ---新生成的文件夹(原