GNUg++常⽤编译选项⽤法
本⽂讨论GNU编译器集合(GCC)中的C++编译器(g++)的典型⽤法,主要是指命令⾏选项的构造。GCC的C++编译器正常安装后,可以使⽤g++或c++命令执⾏。
GCC Option Refresher
本节回顾GCC的C编译器的基本使⽤⽅法。
g++编译器的选项可以是单字符,⽐如-o,也可以多字符,⽐如-ansi。所以你不可以把多个单字符选项合写到⼀起,这和许多其他GNU 和UNIX下的程序不同。例如,多字符选项-pg不表⽰2个单字符选项-p -g。选项-pg表⽰在最终的2进制⽂件⾥⽣成额外的代码,⽤来输出GNU code profiler的信息gprof;⽽选项-p -g则表⽰在⽬标2进制⽂件⾥⽣成额外的代码,⽤来产⽣prof code profiler需要的信息(-p),并在⽬标⾥加⼊调试信息(-g)。
既然g++把多字符的选项进⾏了区分,你就可以随意安排各个选项的顺序了。⽐如:
g++ -pg -fno-strength-reduce -g myprog.c -o myprog
和
g++ myprog.c -o myprog -g -fno-strength-reduce -pg
是⼀样的。
⼀般情况下,这些选项的顺序是⽆所谓的。但是在有些情况下,顺序会变得重要,⽐如你多次使⽤同⼀类的选项。举个例⼦,-I选项指定了搜索include⽂件的⽬录,如果你⽤-I指定了多个⽬录,gcc会按照你指定⽬录的顺序搜索需要的⽂件。
⽤g++编译单个源⽂件很简单,只要把⽂件名当参数传给g++就⾏了。
$ g++
$ ls -l
-rwxr-xr-x 1 wvh users 13644 Oct 5 16:17 a.out
-rw-r--r-- 1 wvh users 220 Oct 5 16:
默认情况下,UNIX和LINUX操作系统⽣成的⽬标⽂件是当前⽬录下的a.out,只要输⼊./a.out就可以执⾏。在Cygwin系统下,你得到的是a.exe,通过输⼊./a或者./a.exe都可以执⾏。
要定义g++的输出⽂件名,使⽤-o选项如下所⽰:
$ g++ -o runme
$ ls -l
-rw-r--r-- 1 wvh users 220 Oct 5 16:
-rwxr-xr-x 1 wvh users 13644 Oct 5 16:28 runme
如果编译多个源⽂件,只要在命令⾏⾥列出它们就⾏了,如下所⽰,最终产⽣的输出⽂件是showdate:
$ g++ –o showdate
如果你想先编译这些源⽂件,最后再把它们链接成⼀个2进制⽂件,可以⽤-c选项,那么g++就只产⽣object⽂件,如下所⽰:
$ g++ -
$ g++ -
$ g++ showdate.o helper.o –o showdate
$ ls -l
total 124
-rw-r--r-- 1 wvh users 210 Oct 5 12:
-rw-r--r-- 1 wvh users 45 Oct 5 12:29 helper.h
-rw-r--r-- 1 wvh users 1104 Oct 5 13:50 helper.o
-rwxr-xr-x 1 wvh users 13891 Oct 5 13:51 showdate
-rw-r--r-- 1 wvh users 208 Oct 5 12:
-rw-r--r-- 1 wvh users 1008 Oct 5 13:50 showdate.o
注意
所有的GCC编译器都是通过⽂件的后缀名来判断⽂件类型的,然后选择应该进⾏的操作(⽐如,后缀
名为.o的⽂件只需要进⾏链接),⽂件类型到操作的映射记录在GCC的specs⽂件⾥。在GCC版本4以前,specs⽂件是标准⽂本⽂件,可以⽤任何⽂本编辑器修改;但是GCC版本4以后specs⽂件是内建⽂件,必须要进⾏解压才能修改。
很显然,当你的项⽬⽂件稍微多点,使⽤命令⾏来编译就不可接受了,特别是还要加上搜索⽬录、优化选项和其他g++选项。解决的⽅案就是make,不过本⽂并不讨论它。
C++源⽂件扩展名
前⾯说过所有GCC编译器都通过⽂件后缀名来决定采⽤的操作。下表列出了g++认识的⽂件类型和相应的操作。
Suffix Operation
.C C++ source code to preprocess.
.cc C++ source code to preprocess. This is the standard extension for C++ source files.gnu编译器
.cpp C++ source code to preprocess.
.cxx C++ source code to preprocess
.ii C++ source code not to preprocess.
如果⼀个⽂件的后缀名未知,那么就当成object⽂件进⾏链接。这并不是说你只能使⽤上表列出的⽂件名后缀来区分源代码⽂件和其他⽂件,你可以⽤-x lang选项指定⼀个或多个输⼊⽂件的代码类型,不使⽤标准的⽂件名后缀规则。lang参数指定代码的类型;对于C++,输⼊⽂件可以是c++(标准的C++源⽂件)或c++-cpp-output(已经被预处理过的C++源⽂件,不需再进⾏预处理)。
注意
当GCC编译器遇到上表列出的⽂件后缀,它会当成C++⽂件。但是,有些GCC编译器(⽐如gcc)不能处理C++程序⾥很复杂的依赖关系,⽐如复杂的类库,于是编译失败。所以你应该⽤g++(或c++)来编译C++程序。
GCC的C++编译器的命令⾏选项
许多命令⾏选项对于GCC编译器家族都是通⽤的,下表只列出g++专有的命令⾏参数。
Option
Description
-fabi-version=n
指定编译代码需要符合的C++ ABI(application binary interface)版本。对于GCC版本3.4及更⾼,默认的ABI版本是2。
-fcheck-new
保证new操作返回的指针为⾮空。
-fconserve-space
把全局变量的初始化操作延迟到运⾏的时候,common segment⾥的全局变量不初始化,这样减少可执⾏⽂件的⼤⼩。
-fdollars-in-identifiers
允许标识符⾥出现$符号(默认)。
-fms-extensions
使g++忽略Microsoft Foundation Classes (MFC)中⾮标准⽤法的警告信息。
-fno-access-control
禁⽌访问检查
-fno-const-strings
强制g++把字符串常量的类型定义成char *,⽽不管ISO C++标准是否要求是const char *。
-fno-elide-constructors
强制g++总是调⽤copy构造函数,即使在⽤临时对象初始化另⼀个同类型对象的时候。
-fno-enforce-eh-specs
禁⽌在运⾏时检查异常处理违例。
-ffor-scope
对于for语句初始化部分申明的变量,限制其作⽤域是for循环以内。你也可以⽤-fno-for-scope选项强制其作⽤域为下⼀个‘}’之前,虽然这和ISO标准冲突,但是旧版本g++和许多其他传统的C++编译器都是这样做的。
-fms-extensions
禁⽌对Microsoft Foundation Classes代码的不必要的警告。
-fno-gnu-keywords
禁⽌把typeof作为⼀个关键字,这样就可以⽤它作为标识符使⽤,你仍可以使⽤__typeof__关键字来代替它。该选项被包含在了-ansi选项⾥⾯。
-fno-implement-inlines
Saves space by not creating out-of-line copies of inline functions controlled by #pragma statements. Using this option will generate linker errors if the such functions are not inlined everywhere they are called
-fno-implicit-inline-templates
不创建隐含的模板实例以节省空间。(详见-fno-implicit-templates)
-fno-implicit-templates
只创建外联(⾮内联)模板的显式实例以节省空间。
-fno-nonansi-builtins
禁⽌使⽤⾮ANSI/ISO标准的内置属性,包括ffs、alloca、_exit、index、bzero、conjf及其他相关的函数。
-fno-operator-names
禁⽌使⽤and、bitand、bitor、compl、not、or和xor关键字作为对应操作符的同义词。
-fno-optional-diags
禁⽌⾮标准的内部语法诊断,⽐如类中特殊的名字应该在何时使⽤各种不同的形式。
-fno-rtti
禁⽌给类的虚函数产⽣运⾏时类型信息(RTTI)
-fno-threadsafe-statics
使g++不产⽣⽤于线程安全检查的代码,这样能减少代码量,如果不需要线程安全的话。
-fno-weak
使g++不使⽤弱符合⽀持,即使链接器⽀持它。这个选择⽤于g++测试的时候,其他时候请不要使⽤。
-fpermissive
把代码的语法错误作为警告,并继续编译进程。
-frepo
允许模板实例化在连接时⾃动进⾏。该选项包含了-fno-implicit-templates选项。
-fstats
编译完成后显⽰前端的统计信息。该选项⼀般只有g++开发⼈员使⽤。
-ftemplate-depth-n
保证模板实例化的递归深度不超过整数n。
-fuse-cxa-atexit
注册静态对象的析构函数时,使⽤__cxa_atexit⽽不是atexit。
-fvisibility=value
(GCC 4.02或以后)使g++不导出ELF(Executable and Linking Format,Linux和Solaris等系统上默认的2进制⽂件格式)中⽤hidden标识的object模块内或库内的符号。该选项能减少⽬标⽂件⼤⼩,加快符号表的查,从⽽改善运⾏性能。但是,该选项也会因为不同的visibility等级⽽导致模块间抛出异常发⽣问题,详见后⾯的““Visibility Attributes and Pragmas for GCC C++ Libraries”⼀节。如果没有使⽤该选项,那么默认的visibility值是default,即导出所有⽬标⽂件和库⾥的符号。
-nostdinc++
禁⽌在C++的标准⽬录⾥搜索头⽂件。
g++编译器的其他⼀些C++选项处理优化、警告和代码⽣成的任务,我们在其他章节⾥讨论。下表总结了专对C++的警告选项。
Option
Description
-Wabi
当编译器⽣成的代码和标准C++ ABI不兼容的时候发出警告。对于GCC版本3.4和更⾼,默认的ABI版本是2。
-Wctor-dtor-privacy
当⼀个类的所有构造函数和析构函数都是私有时发出警告。
-Weffc++
当出现不符合《Effective C++》(Scott Meyers,Addison-Wesley,2005,ISBN: 0-321-33487-6)风格的代码时给出警告
-Wno-deprecated
使⽤已过时C++属性和⽤法时不给出警告。
-Wno-non-template-friend
当⾮模板的友元函数定义在模板⾥时不给出警告。In the C++ language template specification, a frien
d must declare or define a nontemplate function if the name of the friend is an unqualified identifier.
-Wno-pmf-conversions
当把⼀个指向类成员函数的指针隐式转化成⼀般指针的时候不给出警告。
-Wnon-virtual-dtor
当⼀个类需要虚析构函数⽽⼜没有申明虚析构函数的时候给出警告。该选项被包含在-Wall选项⾥。
-Wold-style-cast
当在C++源代码⾥使⽤了传统C语⾔风格的类型转换⽅式时,给出警告。
-Woverloaded-virtual
当⼦类的函数申明覆盖基类虚函数的时候给出警告。
-Wreorder
当类成员变量的初始化顺序和申明顺序不⼀致的时候给出警告。g++编译器会⾃动记录所有变量的正确初始化顺序。该选项被包含在-Wall选项⾥。
-Wsign-promo
当⼀个重载操作把⼀个有符号数值转换成⽆符号数值的时候给出警告。在版本3.4及以前,g++对⽆符号类型进⾏了保护,但是这和
C++标准不⼀致。
-Wstrict-null-sentinel
当⽤⼀个⽆类型的NULL作为哨兵的时候发出警告。哨兵是指⼀个⽆效的输⼊值,通常代表输⼊的结束。此问题的原因是⽆类型的NULL 在不同的编译器实现⾥有不同的⼤⼩,所以必须先转化成固定的类型。
ABI Differences in g++ Versions
C++ ABI是⼀套API标准,定义了C++库提供的数据类型、类、⽅法、头⽂件等的接⼝和规范。对库和⽬标⽂件来说,物理组织、参数传递⽅式和命名⽅式是很重要的,所以需要⼀个统⼀的接⼝,使编译出来的C++程序与提供的库的接⼝⼀致。这种⼀致性对语⾔特有的⼀些属性更加重要,⽐如抛出异常和捕捉异常的时候。
版本3.4以前的g++使⽤ABI版本1,之后使⽤ABI版本2。不同ABI版本之间的程序和库不能混⽤。如果你不确定⾃⼰g++的ABI版本,可以⽤g++ --version命令检查g++的版本,或⽤⼀个伪编译命令显⽰ABI标识符,命令⾏如下:
g++ -E -dM -
如果显⽰102,那么就是版本1;如果显⽰1002,就是版本2。如果你必须⽤到以前版本ABI的库,那么给g++加上选项-fabi-
version=n,其中n就是你要兼容的ABI版本。这样做只能算作权宜之计,把所有旧的代码和库更新到当前版本才是最佳解决⽅案。
GNU C++ Implementation Details and Extensions
本⽂虽然不讨论怎样写好C++程序,但是当你⽤GCC的C++编译器编译你的C++程序的时候,你可以从GCC的扩展中得到许多好处,包括编译器⾃⾝的优势和g++使⽤的标准C++库libstdc++的优势。本节提炼出最为重要的⼀些扩展特性,并讨论它们在C++规范和编译器⾏为⽅⾯的⼀些差异。
Attribute Definitions Specific to g++
作为对visibility属性(详见于“Visibility Attributes and Pragmas for GCC C++ Libraries”)的补充,g++提供了2个额外的属性,即init_priority(priority)和java_interface属性。
The init_priority Attribute
该属性允许⽤户控制某个名字空间⾥的对象的初始化顺序。通常,对象的初始化顺序是它们在某个代码单元⾥的定义顺序。init_priority 只有⼀个整型参数,值为101到65535,越⼩表⽰优先级越⼤。⽐如,在下⾯的伪码⾥,类MyClass将⽐类YourClass先初始化:
class MyClass
{
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论