make--(2) makefile

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

猜你喜欢

转载自blog.csdn.net/qq_35651984/article/details/85942290