首页
论坛
课程
招聘
雪    币: 1675
活跃值: 活跃值 (11)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝

[原创]Windows 下的 Makefile 编写(三)推理规则

2010-12-24 11:26 7242

[原创]Windows 下的 Makefile 编写(三)推理规则

2010-12-24 11:26
7242
Windows 下的 Makefile 编写(三)推理规则

作者:cntrump

推理规则是Makefile中自动化的核心功能之一,掌握了推理规则会让Makefile的编写更简单和更易维护。

推理规则

推理规则提供命令来更新目标并推理目标的依赖项。推理规则是用户自定义的或者是预定义的,预定义的推理规则可以被重新定义。

定义规则

.fromExt.toExt:

    commands


fromExt是依赖文件的扩展名,toExt是目标文件的扩展名。在依赖文件扩展名前面的 . 号必须被放在行首。

All:main.obj func.obj

    link $**

main.obj:main.cpp

    cl /c main.cpp

func.obj:func.cpp

    cl /c func.cpp


在应用了推理规则之后,可以简单地写为

All:main.obj func.obj

    link $**

.cpp.obj:

    cl /c $<


在命令行下的输出结果如下:
F:\我的文章\hello>nmake

Microsoft (R) Program Maintenance Utility   Version 6.00.9782.0

Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

 

        cl /c main.cpp

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86

Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

 

main.cpp

        cl /c func.cpp

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86

Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

 

func.cpp

        link main.obj func.obj

Microsoft (R) Incremental Linker Version 6.00.8447

Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

    由此可以看出来,推理规则已经从 .obj 目标文件自动推导出相应的 .cpp 文件,并且为每一个目标执行一次编译命令。

    上述的推理规则叫做标准推理规则,标准推理规则会被调用多次。在文件数量很多的时候,这样显然会降低速度,为此在1.62及以后的版本中,还定义了批模式规则。

    当 N 条命令通过推理规则时,批模式推理规则只调用一次该推理规则。如果没有批模式推理规则,将需要调用 N 条命令。N 是触发推理规则的依赖项的数目。

由于较低版本的nmake不支持批模式推理规则,所以在使用批模式规则时最好先检查一下当前nmake的版本:

_NMAKE_VER 宏可以返回当前nmake的文件版本,返回的是一个字符串文本。

!message $(_NMAKE_VER)


在VC6 SP6下的输出结果为:

6.00.9782.0


批模式和标准模式唯一的差异就是在目标后多加上一个冒号:

All:main.obj func.obj

    link $**

.cpp.obj::

    cl /c $<

执行后的输出结果如下:
[COLOR="Red"]        cl /c main.cpp func.cpp[/COLOR]

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86

Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

 

[COLOR="Red"]main.cpp

func.cpp

Generating Code...[/COLOR]

        link main.obj func.obj

Microsoft (R) Incremental Linker Version 6.00.8447

Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
 


不同的地方我标识了红色,可以看到编译命令只执行一次,并且一次编译多个文件。这样cl.exe 在编译期间只会被调用一次,相对于多次调用速度要快。

需要注意的一个地方是:由于一次处理多个文件,这就得要求执行命令的程序本身支持处理多个文件,假如cl.exe 一次只能处理单个源文件,那么使用批模式肯定会导致失败。

在上面的例子中,目标文件和依赖文件都没有指定路径,所以默认使用当前目录。如果目标文件或者依赖文件不在当前目录下,就需要为其指定搜索路径:

{fromDir}.fromExt{toDir}.toExt:

    command


    fromDir是依赖文件所在目录,toDir是依赖文件所在目录。目录可以使用宏来表示。大括号是必须的,且每个扩展名只能指定一个目录路径,{}(空的大括号)表示当前目录。

例如,.obj文件被编译输出到Debug目录,源文件在当前目录下:

outdir=.\Debug

objects=$(outdir)\main.obj \

         $(outdir)\func.obj

All:$(objects)

    link $**

.cpp{$(outdir)}.obj::

    cl /Fo"$(outdir)/" /c $<


在执行命令之前 Debug目录必须存在,否则编译命令将失败。命令成功执行后,会在Debug目录下生成 .obj文件,最终的可执行文件生成在当前目录下。

为了能更好的理解上面的推理规则,可以将上面的宏进行展开:

All:.\Debug\main.obj .\Debug\func.obj

    link $**

.cpp{.\Debug}.obj::

    cl /Fo".\Debug/" /c $<


    最后需要说明的是,在批模式下,必须使用 $< 宏来指定依赖文件项目。

    如果你理解了宏,预处理和推理规则,那么已经可以阅读大多数Windows下开源项目的Makefile文件了,并且已经可以自己写出实用的Makefile。

    剩下的就是多加练习,试着为IDE向导生成的项目编写Makefile,多尝试几次之后你会发现原来Makefile很简单。

HWS计划·2020安全精英夏令营来了!我们在华为松山湖欧洲小镇等你

上传的附件:
最新回复 (9)
雪    币: 39
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
jiangming 活跃值 2010-12-24 13:46
2
0
沙发
雪    币: 270
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cosplay 活跃值 2010-12-24 15:06
3
0
谢谢分享  。。
雪    币: 230
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MrSmith 活跃值 2010-12-24 16:27
4
0
不错,感谢分享。以前零零散散的学习一些关于MAKEFILE东西,不够全面。楼主共享精神可嘉。
雪    币: 564
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lixupeng 活跃值 2010-12-25 08:34
5
0
收下!!
雪    币: 189
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
adomore 活跃值 2010-12-26 12:39
6
0
感谢楼猪分享了!先学习了!
雪    币: 292
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lummar 活跃值 2010-12-26 20:52
7
0
nice....
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
门栓 活跃值 2010-12-28 21:03
8
0
谢谢楼主,下载收藏了.
雪    币: 348
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jerrylhj 活跃值 2010-12-29 15:47
9
0
看了3篇你的文章,感觉挺有帮助,但是在我看来仅仅只是纯翻译,个人的理解加的太少。比如我想写个makefile,在命令行输入nmake时编译relase版,输入nmake debug=on的时候编译debug版本,就是没弄出来,后来GOOGLE搜索到csdn上的一篇文章才写出来。
NAME = varage

!CMDSWITCHES +D
!IF DEFINED(DEBUG)
!IF "$(DEBUG)" == "ON"
ML_FLAG = /c /coff /Zi
LINK_FLAG = /SUBSYSTEM:WINDOWS /MACHINE:IX86 /DEBUG /DEBUGTYPE:CV
!ENDIF
!ENDIF

ML_FLAG = /c /coff
LINK_FLAG = /SUBSYSTEM:WINDOWS /MACHINE:IX86

$(NAME).exe:$(NAME).obj
Link $(LINK_FLAG) $**

.asm.obj:
Ml $(ML_FLAG) $<


clean:
del *.obj
del *.pdb
del *.pch
del *.exp
雪    币: 1675
活跃值: 活跃值 (11)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
cntrump 活跃值 13 2010-12-29 21:52
10
0
我在PDF中都带有附件的,一般大家都只看PDF本身的内容,容易把附件忽略了。
你没有看 pdf 文件中的附件,Makefile 要结合实际的例子才能理解。
游客
登录 | 注册 方可回帖
返回