VC编译链接选项全解析

集成开发环境Visual C++封装了微软CL编译器的LINK链接器的参数,在Windows编程中会遇到因为不熟悉编译和链接参数导致的问题,因此本文对这方面的细节做了一个总结。更加详细的内容,可以参考微软官方的编译链接参数文档:VC编译链接选项

一. 编译参数

1. /I(附加包含目录)

/I 将目录添加到要在其中搜索包含文件的目录列表中。命令行使用方式: CL /I \INCLUDE /I \MY\INCLUDE MAIN.C , 或者在VS中设置,VC项目属性 -> 配置属性 -> C/C++ -> 常规 -> 附加包含目录

编译器按下列顺序搜索头文件所在的目录:

  1. 包含源文件的目录。
  2. 用 /I 选项指定的目录(按照 CL 遇到它们的顺序排列)。
  3. 在 INCLUDE 环境变量中指定的目录(是由VC++ Directories -> Include Directories设置的 )。

2. /Z7、/Zi、/ZI (调试信息格式)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 常规 -> 调试信息格式

/Z7 将调试器需要用到的调试信息放入 .obj 文件中,不生成任何 .pdb 文件,调试信息中包含变量的名称和类型以及函数和行号。

/Zi  生成一个程序数据库(PDB),其中包含供调试器使用的类型信息和符号化调试信息。符号化调试信息中包含变量名称和类型 以及 函数和行号

/ZI 采用支持”编辑并继续”功能的格式生成程序数据库(PDB),/ZI仅可在面向x86的编译器中使用,且与 /clr 不兼容

3. /Wn、/WX(警告信息展示)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 常规 -> 警告等级/将警告视为错误

/Wn 指定警告等级,n在[0,4]之间。/W0不显示警告信息; /W1只显示严重的警告; /W2显示所有 /W1的警告和不如/W1严重的警告; /W3显示所有/W2的警告和所有其他出于生产目的而建议的警告; /W4显示所有的警告和信息性警告,建议选择该选项

/WX 将所有编译器警告都视为错误

4. /Od、/O1、/O2、/Ox(优化)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 优化 -> 优化

/Od 关闭程序中的所有优化并加快编译,此选项是默认设置。 由于 /Od 取消代码移动,所以简化了调试过程。

/O1 创建最小尺寸的代码,即空间优化

/O2 创建运行速度最快的代码,即时间优化

/Ox 完全优化,优先选择生成执行速度更快的代码而不是大小更小的代码

5. /Ob0、/Ob1、/Ob2(内联函数展开)

/Ob0 禁用内联扩展

/Ob1 仅允许对标记为 inline__inline 或 __forceinline 的函数或是在类声明中定义的 C++ 成员函数中进行扩展

/Ob2 默认值,允许对标记为 inline__inline 或 __forceinline 的函数或是编译器选择的任何其他函数进行扩展。此选项要求启用使用 /O1、/O2、/Ox 或 /Og 进行的优化。

6. /Oi(生成内部函数)

/Oi 用于将某些函数调用替换为内部函数;为产生更好的性能,编译器可能还是会调用函数(而不会将该函数调用替换为内部函数)

注意:可以用   #pragma intrinsic( function1 [, function2, …] )   这个杂注告诉编译器那些函数是内部函数

7. /Os、/Ot(代码大小优先、代码速度优先)

/Os (代码大小优先)通过告诉编译器优先选择大小而非速度来最小化 EXE 和 DLL 的大小。

/Ot  (代码速度优先)通过告诉编译器优先选择速度而非大小来最大化 EXE 和 DLL 的速度。

8. /Oy(框架指针省略)

/Oy 因为无需设置和移除任何框架指针,该选项可以加快函数调用的速度,它还可以使一个或多个寄存器(Intel 386 或更高版本上的 EBP)空出来,另作它用。

注意:该选项只能用于x86编译器中,且因为编译器取消了帧指针信息,使得不便调试,如果选择了 /Z7、/Zi、/ZI这些调试信息格式,则最好去掉此选项(/Oy- 是禁止省略的意思)

9. /GL(全程序优化)

/GL 该选项允许编译器用有关程序中所有模块的信息执行优化。 如果不执行全程序优化,则基于每个模块 (compiland) 执行优化。默认情况下,全程序优化是关闭的,因此必须显式地启用它。 但是,也可以用 /GL- 显式地禁用它

使用有关所有模块的信息,编译器能够:

  • 跨越函数边界优化寄存器的使用。
  • 更好地跟踪对全局数据的修改,允许减少加载和存储的数目。
  • 在模块中内联某个函数,即使该函数在另一个模块中定义。

10. /D (预处理器定义)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义

/D 该选项定义源文件的预处理符号,与源代码文件开头的 #define 指令具有相同的效果

11. /x (忽略标准包含路径)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 预处理器 -> 忽略标准包含路径

/x 阻止编译器在 PATH 和 INCLUDE 环境变量中指定的目录中搜索包含文件。

在下列的CL编译命令中,/X参数通知编译器忽略由 PATH 和 INCLUDE 环境变量指定的位置,/I 指定在其中查找包含文件的目录:

CL /X /I \ALT\INCLUDE MAIN.C

12. /P、/EP(生成预处理文件)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 预处理器 -> 生成预处理文件

/P 对c和c++的源文件进行预处理,并将预处理的文件写入到文件中

/EP  对c和c++的源文件进行预处理,并将预处理的文件写入到标准输出设备中

13. /C (在预处理期间保留注释)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 预处理器 -> 保留注释

/C 在预处理期间保留注释,本选项需要 /P /EP选项

14. /Gm (启用最小重新生成)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用最小重新生成

/Gm 选项用于启用最小重新生成,做法是监测C++类定义的变化,只重新编译受影响的源文件

15. /EHsc、/EHa (异常处理模型)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用C++异常

/EHsc  仅捕获 C++ 异常并通知编译器假定声明为 extern "C" 的函数从未引发 C++ 异常

/EHa   同时捕获异步(结构化)和同步 (C++) 异常的异常处理模型

16. /RTC1(/RTCsu)、/RTCs、/RTCu

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 基本运行时检查

/RTC1  包含 /RTCs 和 /RTCu

/RTCs  启用堆栈帧运行时错误检查。主要体现在几个方面:1. 当使用的变量尚未初始化时进行报告   2.检测局部变量(如数组)的溢出和不足   3. 检测堆栈指针损坏,检测调用约定不匹配可能导致堆栈指针损坏。 

/RTCu  当使用的变量尚未初始化时进行报告

17. /MT、/MD、/MTd 、/MDd (运行时库)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 运行时库

/MT是 “multithread, static version ” ,表示采用多线程CRT库的静态lib版本(即LIBCMT.lib)。

特点: 1. 该选项会在编译时将运行时库以静态lib的形式完全嵌入。

2. 该选项生成的可执行文件运行时不需要运行时库dll的参加,会获得轻微的性能提升,但最终生成的二进制代码因链入庞大的运行时库实现而变得非常臃肿。

3. 当某项目以静态链接库的形式嵌入到多个项目,则可能造成运行时库的内存管理有多份,最终将导致致命的”Invalid Address specified to RtlValidateHeap”问题。

/MD是 “multithread- and DLL-specific version” ,表示采用多线程CRT库的动态dll版本,会使应用程序使用运行时库特定版本的多线程DLL。

特点:1. 链接时将按照传统VC链接dll的方式将运行时库MSVCRxx.DLL的导入库MSVCRT.lib链接。

2. 在运行时要求安装了相应版本的VC运行时库(MSVCRxx.DLL)可再发行组件包(当然把这些运行时库dll放在应用程序目录下也是可以的)。

优点:当多个模块都以MD方式运作时,其内部会采用同一个堆,内存管理将被简化,跨模块内存管理问题也能得到缓解。

/MTd是/MT的Debug版本选项,使用的静态库是 LIBCMTD.lib,其它与 /MT 是一样的

/MDd是/MD的Debug版本选项,使用的动态库是 MSVCRxxd.DLL,其它与 /Md 是一样的

18. /Zp (结构成员对齐)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 结构成员对齐

格式:  /Zp [ 1 | 2 | 4 | 8 | 16 ]

当指定此选项时,第一个结构成员后的每个结构成员将存储在成员类型大小或 n 字节边界(其中 n 为 1、2、4、8 或 16)两者中较小的一个边界上。

下表描述了可用的值:

1    针对 1 字节边界将结构打包。 与 /Zp 相同。

2    针对 2 字节边界将结构打包。

4    针对 4 字节边界将结构打包。

8    针对 8 字节边界将结构打包(默认设置)。

16  针对 16 字节边界将结构打包。除非有特定的对齐要求,否则不应使用此选项。

可以使用    #pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )   达到相同的效果。

19. /GS (缓冲区安全检查)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 缓冲区安全检查

该选项默认是启用的,若要弃用,可用 /GS- 参数。该选项用于检测某些覆盖函数返回地址、异常处理程序地址或特定类型的参数的缓冲区溢出。

20. /Gy (启用函数级链接)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用函数级链接

允许编译器以打包函数(COMDATs)的形式对各个函数进行打包, 用于“编辑并继续”的 /ZI 选项会自动设置 /Gy 选项。

21. /Za (禁用语言扩展)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 禁用语言扩展

Visual C++ 编译器提供许多在 ANSI C 或 ANSI C++ 标准中指定的那些功能以外的功能。 这些功能统称为 C 和 C++ 的 Microsoft 扩展。 这些扩展在指定 /Za 选项时不可用。 默认是不禁用的,就是开启Microsoft的扩展。

22. /J(默认char类型是无符号的)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 默认无符号字符

更改默认的 signed char类型为 unsigned char 类型。且向int类型扩展的时候为零扩展。

23. /Zc(一致性)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> Treat wchar_t as Built-in Type / Force Comformance In For Loop Scope

/Zc:wchar_t     依据c++标准,将wchar_t作为内置类型,默认情况下/Zc:wchar_t是打开的,也就是默认情况下 wchar_t 就是内置类型

/Zc:forScope    依据c++标准,针对具有Microsoft扩展的for循环实现标准的C++行为,标准的C++行为是使 for 循环的初始值设定项在 for 循环之后超出范围,默认情况下 /Zc:forScope 是打开的,也就是模拟标准的C++的for行为

24. /GR(启用运行时类型信息)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用运行时类型信息

/GR 添加代码以在运行时检查对象类型, 默认情况下,/GR 处于打开状态。 /GR- 将禁用运行时类型信息。

25. /Yu 、/Yc(创建/使用预编译头文件)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 预编译头-> 创建/使用预编译头

/Yu 指示编译器在当前编译中使用现有预编译头(.pch)文件

/Yc 指示编译器创建表示某一时刻的编译状态的预编译头(.pch)文件,使用此参数时,编译器将对直到 .h 文件(包括该文件)的所有代码进行编译

26. /FA、/FAc、/FAs、/FAcs(汇编输出)和 /Fa(ASM列表位置)

1. 位置:VC项目属性 -> 配置属性 -> C/C++ -> 输出文件-> 汇编输出

/FA      仅输出汇编到文件, 文件默认扩展名是 .asm。

/FAc    输出汇编和相应的机器码到文件,文件默认扩展名是 .cod。

/FAs    输出汇编和相应的源代码到文件,文件默认扩展名是 .asm。

/FAcs     输出汇编、机器码、源代码到文件,文件默认扩展名是 .cod。

2. 位置:VC项目属性 -> 配置属性 -> C/C++ -> 输出文件-> ASM列表位置

/Fa      为编译中的每一个源文件生成source_file.asm  (**可能用得比较多**)

/Fa filename    将filename.asm放到当前目录中,仅在编译单个源文件时有效

/Fa filename.extension    将filename.extension放到当前目录中,仅在编译单个源文件时有效

/Fa directory\     为编译中的每一个源文件生成source_file.asm,并放入directory中。  注意目录后面有一个反斜杠  (默认就是这个方式)

/Fa directory\filename 将filename.asm放到directory目录下,仅在编译单个源文件时有效

/Fa directory\filename.extension  将filename.extension放到directory目录喜爱,仅在编译单个源文件时有效

27. /Gd、/Gr、/Gz(调用约定)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 高级 -> 调用约定

关于调用约定可以参见 http://www.cnblogs.com/Jocent/p/6901675.html  这篇文章

/Gd __cdecl

/Gr __fastcall

/Gz __stdcall

28. /TP、/TC(编译为)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 高级 -> 编译为

默认情况下,CL 假定扩展名为 .c 的文件是 C 源文件,扩展名为 .cpp 或 .cxx 的文件是 C++ 源文件

/TP  编译为C++代码

/TC  编译为C代码

29. /wd (禁用指定的警告)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 高级 -> 禁用指定的警告

/Wd n    在n中指定要禁用的警告类型,例如 /Wd 4326 即为禁用 C4326 警告

30. /Zl (省略默认库名称)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 高级 -> 省略默认库名称

/Zl    这是是小写的L,不是I,注意下。该选项省略即将编译到.obj文件中的默认库文件(比如C运行时库),默认情况下不省略,如果选了该选项,虽可以节省空间,但可能导致链接失败

31. /errorReport (报告内部编译器错误)

位置:VC项目属性 -> 配置属性 -> C/C++ -> 高级 -> 错误报告

/errorReport:prompt  当收到内部编译器错误时,提示发送报告。 在开发环境中编译应用程序时,prompt 是默认值

/errorReport:queue   对错误报告进行排队。 当使用管理员权限登录时,将显示窗口,因此您可以报告自上次登录以来的任何失败(每三天提示您发送失败报告不超过一次)。 在命令提示下编译应用程序时,queue 是默认值

二. 链接参数

1. /OUT (输出文件)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 常规 -> 输出文件

/OUT:[file]  指定链接后输出文件的名字

2. /INCREMENTAL (增量链接)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 常规 -> 启用增量链接

/INCREMENTAL           启用增量链接,增量链接可以使得代码有变化时不用重新产生整个exe或者dll,能够加快链接速度,对最终产生的二进制可执行文件影响不大。如果程序的执行依赖于最终生成的二进制代码中各种变量或函数的地址时,那么使用/INCREMENTAL选项进行链接,可能会使程序产生意想不到的错误,这种错误往往不合逻辑,很难调试。

/INCREMENTAL:NO    不启用增量链接,默认就是该选项。

3. /LIBPATH(附加库目录)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 常规 -> 附加库目录

/LIBPATH:[dir]    指定一个或多个路径,该路径中包含附加的库文件,如果有多个路径,使用分号[ ; ]进行分割

4. /DEF(模块定义文件)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 输入-> 模块定义文件

/DEF 将模块定义文件(动态链接库的导出表)传到链接器,只能为链接器指定一个 .def 文件

5. /MANIFESTUAC(UAC执行级别)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 清单文件 -> UAC执行级别

/MANIFESTUAC:LEVEL=[值]  值可以取下面三种之一  asInvoker (/level=’asInvoker’)  这是默认的、   highestAvailable (/level=’highestAvailable’)  、   requireAdministrator (/level=’requireAdministrator’) 当程序需要管理员权限运行时,选这个

6. /SUBSYSTEM(子系统)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 系统-> 子系统

/SUBSYSTEM 定义程序运行所在的子系统,常见的有 控制台 (/SUBSYSTEM:CONSOLE)、窗口 (/SUBSYSTEM:WINDOWS)

7. /ENTRY(入口点)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 高级-> 入口点

/ENTRY 该选项将某个函数定义为 exe 或者 dll 的起始地址

8. /BASE(基址)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 高级-> 基址

/BASE 设置程序的基址,即程序被加载器加载到内存的那个起始位置上

9. /DYNAMICBASE(随机基址)

位置:VC项目属性 -> 配置属性 -> 链接器 -> 高级-> 随机基址

/DYNAMICBASE 程序的基址是随机的,增强了安全性。这是默认的选项

/DYNAMICBASE:no 程序的基址不是随机的




One Comment

  • Comments are closed.