C++ 学习笔记(三) 编写makefile(二)
2015-05-31 13:59
253 查看
前面写了最简单的makefile文件,现在继续学习一下进阶的版本吧。
定义可以个变量的格式为:
变量名 = 变量值 //这里的变量值,一般来说都是字符串
例如:objects = main.o parseMethod.o \
parserBase.o V8Script.o
定义了一个 objects 变量,其代表了一些.o文件的合集。
然后我们就可以直接使用它了:
html:$(objects)
g++ -o html $(objects)
其原理和C/C++中的宏是一样的,都是在使用变量的地方直接用变量值替换变量
clean:
-rm html $(objects) # 减号 的意思是:如果某个文件出现错误了,不要管,继续执行下去
可以定义clean是伪目标,这样在使用中会方便很多;
rm指令前加上了减号(-),表示在删除后面的文件时,如果某个文件出错,则不理会当前错误,删除下一条。
减号(-)在许多指令上都可以使用
其格式为:
include 文件名
例如:
include object.mk这样子我们就可以将全部变量放在一个独立的文件中,以实现整个makefile的整洁以及维护的便利性。
make支持三各通配符:“*”,“?”和“[...]”
定义文件搜寻,主要有两种方法:
冒号(:)为分隔符,表示先在src目录下寻找,再在../headers目录下寻找。但是其默认的第一寻找路径仍然时当前路径
例如:
vpath %.h ../headers
表示所有的.h文件,都在../headers目录下寻找
当然这里也支持多个目录的情况:
vpath %.h ../headers:bin或者
两个的意思都是一样的
因此,我们可以写成这样:
这样子的话,因为all时伪目标,因此,可执行文件html始终会被创建。
其实际效果等同于在makefile文件的第一行直接书写:
当然这是一种简单的情况。实际上,有时候我们需要一次性编译多个可执行文件。那么这个时候,使用伪目标就能实现我们的目的。否则的话,makefile只会将文件第一行的目标作为最终目标,无法实现一次性编译多个目标。
例子如下:
%<用于指代依赖文件,同样是保留后缀名的
其格式如下:
目标集合: 目标: 依赖文件
执行语句
用一个例子来解释一下:
objects = foo.o bar.o test.etc result
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
objects是一个目标集合,含有多种元素(.o)( .etc)以及可执行文件
在静态模式中,首先从目标集合中一个个取出符合条件的目标。
即取出满足( %.o)的目标,也就是所有的.o文件。%在这里属于一个通配符,其代表的就是当前目标的名字(不包含后缀名)
对于每个取出的目标,再生成这个目标对应的依赖文件。也就是生成( %.c),使用当前目标的名字替代%。
实际上这里有时候会隐藏掉( %.c),这是因为makefile可以隐形的推导出目标文件的c文件
再之后,就是对取出的目标,生成对应的执行语句了,同样的时使用变量替代的形式。 $< 和 $@ 参考上面的说明吧
于是,这么一段静态模式,等同于:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
因通常的,我们会让编译器自己生成这种依赖关系,然后存放到同名文件的(.d)文件下
然后我们在主makefile文件中,再引用(.d)文件,来达到一个动态生成依赖文件的目的
但是我们也可以在make后面指定我们的目标。类似于 make clean这样子。
于是,我们可以在makefile中实现多种功能了:
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被make创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。也就是一个tar文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试makefile的流程。
1.使用变量代替重复劳动,实现多处同步修改
Makefile中的变量其实就是C/C++中的宏定义可以个变量的格式为:
变量名 = 变量值 //这里的变量值,一般来说都是字符串
例如:objects = main.o parseMethod.o \
parserBase.o V8Script.o
定义了一个 objects 变量,其代表了一些.o文件的合集。
然后我们就可以直接使用它了:
html:$(objects)
g++ -o html $(objects)
其原理和C/C++中的宏是一样的,都是在使用变量的地方直接用变量值替换变量
2.clean 进阶
.PHONY:cleanclean:
-rm html $(objects) # 减号 的意思是:如果某个文件出现错误了,不要管,继续执行下去
可以定义clean是伪目标,这样在使用中会方便很多;
rm指令前加上了减号(-),表示在删除后面的文件时,如果某个文件出错,则不理会当前错误,删除下一条。
减号(-)在许多指令上都可以使用
3.makefile引入文件include
makefile和C/C++一样,都可以引入别的文件。其格式为:
include 文件名
例如:
include object.mk这样子我们就可以将全部变量放在一个独立的文件中,以实现整个makefile的整洁以及维护的便利性。
3.通配符
波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录。make支持三各通配符:“*”,“?”和“[...]”
4.文件搜寻
文件搜寻主要时用于提示makefile在哪几个目录中寻找目标文件定义文件搜寻,主要有两种方法:
(1)使用系统内置变量VPATH(全大写)
VPATH = src:../headers冒号(:)为分隔符,表示先在src目录下寻找,再在../headers目录下寻找。但是其默认的第一寻找路径仍然时当前路径
(2)使用vpath(全小写)关键字
格式为:vpath 条件 目录例如:
vpath %.h ../headers
表示所有的.h文件,都在../headers目录下寻找
当然这里也支持多个目录的情况:
vpath %.h ../headers:bin或者
vpath %.h ../headers vpath %.h bin
两个的意思都是一样的
5.伪目标
伪目标的一个特性是:它总比它的依赖文件要旧,也就是说,伪目标总是被执行的。因此,我们可以写成这样:
# All Target all: html html: html.o gcc -o html html.o .PHONY all
这样子的话,因为all时伪目标,因此,可执行文件html始终会被创建。
其实际效果等同于在makefile文件的第一行直接书写:
html: html.o gcc -o html html.o
当然这是一种简单的情况。实际上,有时候我们需要一次性编译多个可执行文件。那么这个时候,使用伪目标就能实现我们的目的。否则的话,makefile只会将文件第一行的目标作为最终目标,无法实现一次性编译多个目标。
例子如下:
all : prog1 prog2 prog3 .PHONY : all prog1 : prog1.o utils.o cc -o prog1 prog1.o utils.o prog2 : prog2.o cc -o prog2 prog2.o prog3 : prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o
6.特殊变量 %@ %<
%@用于指代目标,并且是保留后缀名的%<用于指代依赖文件,同样是保留后缀名的
7.静态模式
我个人理解的静态模式,就是一个foreach语句,实现了对目标集合的遍历。其格式如下:
目标集合: 目标: 依赖文件
执行语句
用一个例子来解释一下:
objects = foo.o bar.o test.etc result
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
objects是一个目标集合,含有多种元素(.o)( .etc)以及可执行文件
在静态模式中,首先从目标集合中一个个取出符合条件的目标。
即取出满足( %.o)的目标,也就是所有的.o文件。%在这里属于一个通配符,其代表的就是当前目标的名字(不包含后缀名)
对于每个取出的目标,再生成这个目标对应的依赖文件。也就是生成( %.c),使用当前目标的名字替代%。
实际上这里有时候会隐藏掉( %.c),这是因为makefile可以隐形的推导出目标文件的c文件
再之后,就是对取出的目标,生成对应的执行语句了,同样的时使用变量替代的形式。 $< 和 $@ 参考上面的说明吧
于是,这么一段静态模式,等同于:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
8.自动生成依赖性
编译器语言 gcc -MM main.c 可以自动根据main.c的include语句生成对应的依赖文件例如 main.o : main.c defs.h因通常的,我们会让编译器自己生成这种依赖关系,然后存放到同名文件的(.d)文件下
然后我们在主makefile文件中,再引用(.d)文件,来达到一个动态生成依赖文件的目的
9.指定目标
如果我们直接执行make命令,那么默认的是执行文件中的第一个目标。但是我们也可以在make后面指定我们的目标。类似于 make clean这样子。
于是,我们可以在makefile中实现多种功能了:
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被make创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。也就是一个tar文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试makefile的流程。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++中拷贝构造函数的应用详解
- C++中引用(&)的用法与应用实例分析
- C++使用CriticalSection实现线程同步实例
- C++智能指针实例详解
- 解析C++ 浮点数的格式化输出