linux源码Makefile详解(完整) - Daniel.G - 博客园
Makefile文件由一系列规则(rules)构成。每条规则的形式如下。
<target> : <prerequisites>
[tab] <commands>
上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。
"目标"是必需的,不可省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。
每条规则就明确两件事:构建目标的前置条件是什么,以及如何构建。
语法介绍:
1.命令以制表符TAB开头
2. $@表示要生成的目标
3. $^ 表示全部的依赖文件
4. $< 表示第一个依赖文件
5. 通配符主要有星号(*)、问号(?)和 [...]
%是模式匹配符,进行类似正则匹配
%.o : %.c
$(CC) $< -o $@
# 目标是.o文件,依赖对应的.c文件
# .o文件的生成命令是 $(CC)
# $< 表示第1个依赖,即对应的.c文件
# $@ 表示目标,即.o文件
6.注释符用"#"
7.$表示makefile文件中的变量,例如$(CC)表示用于编译c语言文件的可执行程序
变量需要放在 $( ) 之中
$$表示shell变量
foo = $(call <expression>, <parm1>, <parm2>, <parm3>...)
# foo是一个makefile变量
# 当make执行这个函数时,<expression>参数中的变量,如$(1),$(2),$(3)等,会被参数<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函数的返回值。
reverse = $(1)$(2)
foo = $(call reverse, a, b)
# foo的值就是“ab”
Makefile一共提供了四个赋值运算符 (=、:=、?=、+=),它们的区别请看StackOverflow。
VARIABLE = value
# 在执行时扩展,允许递归扩展。
VARIABLE := value
# 在定义时扩展。
VARIABLE ?= value
# 只有在该变量为空时才设置值。
VARIABLE += value
# 将值追加到变量的尾端。
在Makefile规则中,通配符会被自动展开。
但在变量的定义和函数引用时,通配符将失效。如果需要在变量定义或函数引用中使用通配符,就需要使用函数“wildcard”。
SOURCE = $(wildcard *.c)
# 获取工作目录下的所有的.c文件列表
SOURCE = $(patsubst %.c, %.o, $(wildcard *.c))
# 首先使用wildcard函数获取工作目录下的.c文件列表
# 之后将列表中所有文件名的后缀.c替换为.o。
# patsubst函数的作用是替换通配符
过滤器
$(filter %.c, SOURCES)
# SOURCES表示包含.c .cc .cpp等多种类型的源文件
# 该过滤器函数将c文件过滤出来,而%.c即为此过滤器规则。
伪目标
.PHONY: clean
clean:
rm *.o temp
目标既可以是一个文件,也可以是某个操作。上述代码定义了名为clean的操作。
其中.PHONY行的意义是:明确指定clean是一个伪目标,即不是文件目标。
一般不建议直接在makefile中写入创建文件夹的规则,可以采用下面的方法:
%.o : %.cpp
@cachedir=`dirname $@`;\
if [ ! -d $$cachedir ]; then mkdir -p $$cachedir; fi;
$(CC) -o $@ $<
Make命令本身可带有四种参数:标志、宏定义、描述文档名和目标文档名。其标准形式为:
Make [flags] [macro definitions] [targets]
-f file 指定file文档为描述文档.假如没有"-f"参数,则系统将默认当前目录下名为makefile或名为Makefile的文档为描述文档。在Linux中, GNU make 工具在当前工作目录中按照GNUmakefile、makefile、Makefile的顺序搜索 makefile文档。
-c dir 在读取 makefile 之前改变到指定的目录dir。
-w 在处理 makefile 之前和之后,都显示工作目录。
$(MAKECMDGLOBALS) 获取targets
gcc 的3个参数:
1. -o 指定输出文件名(包括对象文件,可执行文件2)
gcc sources/main.c -o bin/main
2. -c 编译的时候只生产目标文件不链接
gcc -c sources/main.c -o obj/main.o
3. -I 主要指定头文件的搜索路径
gcc -I headers -c main.c -o main.o
4. -l 指定静态库
gcc -lpthread ...
g++ helloworld.cpp
编译器默认的动作:编译源代码文件生成对象文件(object file),链接对象文件和 libstd c++ 库中的函数得到可执行程序。然后删除对象文件。由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。
程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示:
$ gcc helloworld.cpp -lstdc++ -o helloworld
选项 -l (ell) 通过添加前缀 lib 和后缀 .a 将跟随它的名字变换为库的名字 libstdc++.a。而后它在标准库路径中查找该库。gcc 的编译过程和输出文件与 g++ 是完全相同的。
创建静态库
静态库是编译器生成的一系列对象文件的集合。链接一个程序时用库中的对象文件还是目录中的对象文件都是一样的。库中的成员包括普通函数,类定义,类的对象实例等等。静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫 ar 。
下面的命令序列将源码文件编译成对象文件,命令 ar 将其存进库中:
$ g++ -c sayhello.cpp
$ g++ -c say.cpp
$ ar -r libsay.a sayhello.o say.o
程序 ar 配合参数 -r 创建一个新库 libsay.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。
一般来说,在默认情况下,在程序崩溃时,core文件是不生成的(很多Linux发行版在默认时禁止生成核心文件)。所以,你必须修改这个默认选项,在命令行执行:
ulimit -c unlimited //unlimited 表示不限制生成的core文件的大小