nmake
当你的程序只有一个源文件时,直接就可以用gcc命令编译它。但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,就会很麻烦,所以需要make工具来进行批处理编译。make工具的使用主要是编写makefile,用来描述make该如何进行编译。make有许多种类,这里用vc++的nmake
nmake环境
nmake在安装的vc++目录中,我的在D:\study\vs 2015\VC\bin中。
可以右键我的电脑设置全局的环境变量,也可以在控制台设置
set path=D:\study\vs 2015\VC\bin,这样设置的环境变量只在当前控制台有用,且当控制台关闭时候,控制台设置的环境变量会被销毁,不会影响全局的环境变量。
makefile
使用make的重点在于编写makefile。还是用上篇的测试代码。
先打开控制台将路径跳转到当前目录/make,编写一个makefile。nmake 有点类似于批处理文件bat。执行批处理的命令。
test.exe :
echo Test.exe
makefile的描述块
makefile是有固定格式的,由一个个描述块构成。描述块第一行是目标和依赖需要顶格书写,第二行命令不能顶格,看过有的文章说,目标后不能直接跟上冒号需要隔个空格,实测是错的,可以不加。描述块必须是目标行和命令行连贯,中间有空行也会报错。
targets(目标) : dependents(依赖)
commands… (命令)
目标就是要生成的文件,依赖就是需要哪个文件生成目标文件,命令就是依赖生成目标需要执行的命令。描述块可以多个,但默认执行第一个描述块
如输入: nmake /fmake.mak test.exe test2.exe 将执行两个描述块
test.exe:
echo Test.exe
test2.exe:
echo test2.exe
makefile的依赖
目标的生成需要依赖,当没有依赖时候,make会查找符合依赖的描述块,先对依赖进行编译。如下,我只有一个test.c,我可以这么写makefile
test.exe:test.obj
gcc -o test.exe test.obj
test.obj:test.s
gcc -c -o test.obj test.s
test.s:test.c
gcc -S -o test.s test.c
makefile的合并
一个exe的生成不止一个.c,还有库文件资源文件等,所以 test.exe 的依赖是不止一个的,makefile规则允许目标文件重复,他会将其合并。根据是单冒号还是双冒号有一些划分
单冒号:合并后只保留第一个的命令,会参生一个警告
test.exe :a---------------> test.exe :a b
run1 合并 run1
test.exe :b a:
run2 run_a
a : b:
run_a run_b
b :
run_b
双冒号: 合并后保留全部的命令
test.exe ::a---------------> test.exe :a b
run1 合并 run1
test.exe ::b run2
run2 a:
a : run_a
run_a b:
b : run_b
run_b
makefile的宏
makefile支持宏,类似于c的宏定义,宏区分大小写。宏的定义需要顶格书写 ,宏名=,用$( 宏名)来引用一个宏。宏必须写在描述块的外面,宏可以替换一个比较复杂的字符串或者重复的语句,使代码更简单方便
G=test.c
test.exe::test.obj
gcc -o test.exe test.obj
test.obj:test.s
gcc -c -o test.obj test.s
test.s:test.c
gcc -S -o test.s $(G)
宏可以多次赋值,赋值后,引用宏的值是离他最近的宏
宏与宏之间可以替换。格式为
将依赖的c文件的宏替换生成一个依赖的obj文件的宏
C=test.c test1.c test2.c
OBJ=$(C:.c=.obj)
# OBJ=test.obj test1.obj test2.obj
文件名宏
文件名宏预定义为依赖项中指定的文件名(不是磁盘上的完整文件名规范)。调用时,不需要将这些宏括在括号中; 如图所示仅指定$。
宏 | 含义 |
---|---|
$ @ | 当前目标的全名(路径,基本名称,扩展名),如当前指定的那样。 |
$$ @ | 当前目标的全名(路径,基本名称,扩展名),如当前指定的那样。仅作为依赖项中的依赖项有效。 |
$ * | 当前目标的路径和基本名称减去文件扩展名。 |
$ ** | 当前目标的所有家属。 |
$? | 所有家属的时间戳都晚于当前目标。 |
$ < | 具有比当前目标更晚的时间戳的从属文件。仅在推理规则中的命令中有效。 |
在当前环境打印这些文件宏
test.exe:test.obj
gcc -o test.exe test.obj
echo $@ #test.exe 当前目标名
echo $$@ #$@
echo $* #test
echo $** #test.obj
echo $? #test.obj test.c
echo $< #warning
test.obj:test.s
gcc -c -o test.obj test.s
test.s:test.c
gcc -S -o test.s test.c