【转】Windows_makefile_03

【原创】Windows 下的 Makefile 编写(三)推理规则 - 看雪安全论坛.html

http://bbs.pediy.com/showthread.php?t=127038

 

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 $<

执行后的输出结果如下:

代码:
        cl /c main.cpp 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.

 

main.cpp

func.cpp

Generating Code...

        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很简单。*转载请注明来自看雪论坛@PEdiy.com 

 

posted @ 2016-12-15 16:07  DriverSkill  阅读(139)  评论(0编辑  收藏  举报