查看文章
 
GCC參數篇(1) 作者:陳信宏
2009/03/20 下午 7:29

    GNU C/C++是由自由软体协会(FSF;Free
Software Foundation)所发展和推出的一套功能
完备的 C/C++语言编译器和程式库,C/C++ 语言
以其类似高阶语言的语法和接进机械语言的执行
速度,成为软体发展的重要选择之一; C/C++语
言的可携带性能力本来就很高,这使得发展完成
的程式只需修改小部份或是根本不需修改,就能
轻易的移植到不同的作业系统上;虽然 C/C++本
身有这些先天上的优点,但更重要的是需要有个
良好的编译程式,才能将可执行档编得更快、编
得更小,而且若是在不同的作业系统上都有一套
相同的编译器,那对于程式设计人员有着莫大的
帮助和方便,因为不会有在那个OS下要用那个编
译程式的困扰;多年来,GNU C/C++ 一直尽职的
扮演这个角色。
    如同 Linux一般,GNU CC非由一人或一公司
所撰写,除了Richard Stallman先生外,全世界
的使用者也供献了许多心力,有人加入新的关念
和技巧,有人改善旧有的结构,更有人把她移植
到不同的机型和作业系统上,在夜以继日时时刻
刻的改进之下,GNU CC汇集了各方的优点加以融
合,并朝未来进步之中;在 Linux中就是以她作
为发展工具,在重编核心之时便是她担任重责大
任,而且在 DOS中也有GNU CC-- DJGPP。然而她
并未提供如 Turbo C的整合发展环境,想要认识
她的使用者难免会有吃力的感觉,面对如此的仰
之弥高,最直接的方法便是从控制功能的参数认
识起,如此一来不但不会鑽之弥坚,而且还能渐
入佳境,因此我们就先从参数谈起。

GNU C/C++ 的一些相关资料
========================
    gcc 是 GNU C/C++的 C语言编译程式的名称
,在接下来的文章之中,笔者将以大写的 GCC来
代表 GNU C/C++,而以小写的 gcc来代表编译程
式,gcc 的语法如下:
gcc [option|filemane]...
其中filemane是将要编译的档名,option是将要
认识的参数部份。
    当要编译 C++语言时,g++ 为使用的编译程
式,在此 g++是一个完全的编译器--而不只是个
前置处理器,直接产生物件码,这样的 C++执行
起来才更有效率,其语法如下:
g++ [option|filemane]...
其中参数部份除非有指明是专属于 gcc或是 g++
外,其馀两者皆可使用。
    在一般的情况下,GCC 的编译过程有下列四
个步骤:preprocessing,compilation,assembly
和 linking,而整体参数(overall options) 的
作用是指定在那一阶段停止,其它类型的参数主
要是调整这四个步骤中某一步骤的动作。
    由于许多参数之后都允许加上其它控制的子
参数,因此对于参数间的合併使用有较严格的限
定--两个参数不可併成一个,如 -dr这个参数便
和 -d -r在作用上有着极大的不同。对于不同类
型的参数,在排列上不需依任何顺序。而相同类
型的参数,也没有只能使用一个的限制。对于某
些参数如-f或是-W,其后的子参数可能是一个字
串,如 -fforce-mem或是-Wformat,这类型的组
合大部份都有posetive和negative两种型态,如
-ffoo的negative型为-fno-foo,在接下来的讨
论之中,若是这两种型态皆存在者,笔者会一同
列出。

整体参数(Overall Options)
=========================
    整体参数的目的在于控制编译的进行,即编
译到那个阶段便停止,因此我们先来看看各种字
尾和档桉间的关係:

'FILE.c' 需作前置处理(preprocess)的 C语言
          原始程式

'FILE.i' 不需作前置处理的 C语言原始程式

'FILE.m' Objective-C 的原始程式,且必需和
          程式库 'libobjc.a'连结才能植执行

'FILE.h' C 语言标头档(header file)

'FILE.cc'
'FILE.cxx'
'FILE.C' 需作前置处理的 C++语言原始程式

'FILE.ii' 不需作前置处理的 C++语言原始程式

'FILE.s' 组合语言档

'FILE.S' 需作前置处理的组合语言档

接下来我们来看整体参数:

-x LANGUAGE
GCC 会以档桉字尾来判定是何种语言来作编译,
而本参数的作用为指定后续的档桉之语言种类,
不管其字尾为何,LANGUAGE的可能内容为
c   objective-c   c++   c-header
cpp-output        c++-cpp-output
assembler         assembler-with-cpp
这些指定的语言会一直作用到下一个-x参数

-x none
不指定任何语言,以输入档桉的字尾为准

当只希望作某阶段的编译时,用-x可指定编译的
起点,下述的参数可以指定编译终点:

-E
此参数指定只作完perprocess便停止,不作接下
来compiler等动作,并输出到标准输出(stdout)
去,对于不需前置处理的档桉本参数无效。

-S
只进行到compiler便停止,因此输出为一组合语
言档,在内定的输出档名为输入档名去除.c或.i
等字尾之后加上.s而成。

-c
只 compile或assemble输入档桉,而不作连结,
因此输出为一目的档(object file), 内定的档
名为去除.c、.i或是.s等之后加上.o而成。

-o FILE
不管在那一阶段结束动作,都可用此参数将内定
的输出档名改成"FILE";若是没用此参数,最后
产生的可执行档档名内定为 "a.out",在各阶段
结束的输出内定档名请看上列参数。

-v
将正在执行的编译阶段及编连程式的版本输出至
标准错误输出(standard error output)。

-pipe
在不同阶段之编译时,使用管线(pipe)取代暂存
档,在某些系统上的组译程式(assembler) 由于
不能由管线读取资料,而使得这参数无效,但对
GNU assembler 而言此参数当然可用。

和C之方言(C Dialect)有关的参数
==============================
    所谓的「方言」或是「标准语言」在此是以
制定的标准而言,因此ANSI C便是「标准语言」
,而相对的较旧(在制定之前的 C)或是较新者(
如C++)便成了「方言」,这样的分类是因为依实
际的情况而定,没半点优劣的意思。
    对于 C++语言而言,虽然 gcc能以档名字尾
为判断而作正确的编连,但有时仍需指定物件程
式库libg++为连结所需程式库,因此如果要编连
C++语言,建议使用 g++(某些系统上为 c++)来
作,因为 g++会将语言内定为 C++、将libg++内
定为标准程式库,而且对于字尾并不符合标准字
尾的档桉也能作编连。
    接下来我们来看方言参数:

-ansi
指定为ANSI C语言,本参数会将不符合ANSI C标
准的字视为语法错误,因此本参数会关闭 GCC中
许多有用的关键字,如 asm、inline和typeof,
以及用来辨认系统的巨集名称如unix和 vax,而
且 $将不可用来作为识别字的一部份;__asm__
、__extension__、__inline__ 和__typeof__这
四个字不管有无本参数都可继续使用,不过它们
通常是放在标头档中,而 __unix__ 和 __vax__
也是相同情况;当指定本参数时,alloca,abort
exit、_exit 和 ffs将不会视为内建函数。
当设定本参数时,将会定义__STRICT_ANCI__ 这
个巨集,许多标头档利用这个巨集定义与否来宣
告相关的其它巨集或函数,这个目的只是为了符
合ANSI的标准。
对于非ANSI的程式,本参数并不会使编译终结或
发出任何警告,因此通常需加入 -pedantic,有
关这个参数将在警告参数中说明。

-fon-asm
不将 asm、inline和typeof识为保留字,因此这
些字可当成识别字(identifiers), 如欲达到这
些功能,可用__asm__,__inline__和__typeof__
来代替;而 -ansi包含本参数的功能。

-fno-builtin
对于某些不是以双底线(__)开头的函数,不视为
内建函数,这些函数为--abort、abs、alloca、
cos、exit、fabs、ffs、labs、memcmp、memcpy
、sin、sqrt、strcmp、strcpy和strlen。
通常 GCC对这些函数有特定的处理方式--利用一
段小而且更有效率的码来取代,例如呼叫alloca
通常会变成直接调整堆叠的单一指令,而memcpy
则是一inline的複製迴圈,这使得程式变小又变
快,由于程式码已经改变,因此无法对这类函数
定除错中断点,而且也不能以连结别的程式库的
方式来改变这些函数的行为。

-trigraphs
支援ANSI C trigraphs,本参数包含在-ansi中.

-traditional
会使 GCC以「传统」的方式来编译程式,所谓传
统是指在ANSI C之前,其方式如下:
○所有在函数内宣告的extern变数具有整体作用
○新的保留字'typeof'、'inline'、'signed'、
'const' 和'volatile'不具作用
○允许指标和整数作比较。
○'unsigned short'和 'unsigned char'皆转换
成'unsigned int'。
○不认定超出范围的浮点数指标为错误
○对于 constants型态的字串,会存放在可写入
的区域,可在程式中更改其内容。
○不再定义'__STDC__',然而'__GNUC__'仍将定
义,这使得在标头档中能以这两个巨集名称存
在与否来分辨是用 GNU C、traditional GNU
C 、other ANSI C或是other old C 编译程式
来作编译。

-traditional-cpp
以传统的 C前置处理器方式来编译程式。
○以 newline字元为一字串的结束记号。
○将'\x'和'\a'两escape sequences转换成'x'
和 'a'字元。
○允许'this'在 C++程式中使用。
以上这三项方式包含在-traditional参数中。

-fcond-mismatch
允许 conditional expressions之第二和第三个
参数为mismatched types。

-funsigned-char
-fno-signed-char
将'char'设为unsigned;不同的主机和系统对于
'char'的基本设定并不相同,有些为signed、其
它则相反,程式中的'char'变数会因不同系统而
有差异,本参数主要目的便是作强制设定;本参
数之同义词为-fno-signed-char。

-fsigned-char
-fno-unsigned-char
将'char'设为signed。

-fsigned-bitfields
-funsigned-bitfields
-fno-signed-bitfields
-fno-unsigned-bitfields
这四个参数主要目的为设定 bitfields之符号值
,在内定上 bitfields是为signed--这可从基本
资料如 'int'是为signed看出;在-traditional
下所有的bitfields全为unsigned。

-fwritable-strings
对于 constants型态的字串,会存放在可写入之
区域,可在程式中更改其内容;-traditional包
含本项功能。

-fallow-single-precision
就算是使用-traditional的情况下,也不要将单
精密度的运算子强制成双精密度;传统的 K&R编
译程式会不论运算子之型态而将运算式改成双精
密度,然而编译时单精密度比双精密度快多了,
因此若是需用-traditional又不需要double的运
算,便可用本参数;对于ANSI C和 GNU C而言本
参数无效。

C++ 方言参数
============
    以下是用来控制编译 C++时的一些参数,虽
然这些参数只对 C++有作用,然而若是使用于其
它语言,将会被忽略而不会产生任何错误。

-fall-virtual
除了物件建构者(constructor) 和 new、delete
外,将其它出现的成员函数(member functions)
视为 virtual函数;这并非意谓每次都是透过内
部的 virtual函数表来呼叫这些成员函数,而是
若compiler判断能直接呼叫 virtual时,这些成
员函数同样也是直接呼叫。

-fdollars-in-identifiers
允许 $这个符号在识别字串(identifiers) 中使
用,传统的 C允许 $在识别字串中,但ANSI C和
C++禁止此种用法;本参数有相反词。

-felide-constructors
在允许的情况下省略建构函数,在下列的程式片
段中本参数会使得呼叫 foo()时直接初始化 y:
      A foo();
      A y = foo();
未使用本参数时 GCC之过程如下(一)呼叫物件A
的建构函数来初始化 y (二)将 foo()的结果存
到暂存区 (三)将暂存区的值代换给 y;这个过
程是ANSI C++的标准。

-fenum-int-equiv
允许 int型态完全的转换至enum。

-fexternal-templates
对于template函数将只在其定义的所在产生一份
copy,因而对template宣告能获得较小的程式码
,然而要达到这个效果,除了本参数外,还要定
义#pragma implementation或是#progma inter-
face;本参数会将所有的template视为外部函数
(external),因此可用 typedef来安排在在im-
plementation file 中出现的instantiations;
对于本身并无template的source,无需顾虑相关
程式是否有template,皆不需本参数作编译,这
样只是会加大物件程式码的大小而以;本参数亦
有加上 no-之相反词。

-fmemoize-lookups
-fsave-memoized
利用heuristics方法来加速编译,然而本方法未
成为内定的编译方式是因为本法只能针对一个输
入档桉,对其它档桉之速度反而变慢。

-fno-strict-prototype
在 C++中对函数的雏型宣告(prototype declar)
有严格的规定,例如 "int foo()"之宣告在 C中
是可以的,它代表 foo()并无输入值,但在 C++
中得要宣告成 "int foo(void)",本参数便是允
许在 C++中作 C般的宣告。

-fnonnull-objects
设定references之物件为非null型态。

-fthis-is-varible
允许程式中使用this,这是为了和过去的程式相
容的参数。

-nostdinc++
不要在内定的 C++标准目录下搜寻标头档,然而
其它标准目录还是依旧会寻找,本参数通常用于
建立 C++程式库libg++时。

-traditional
本参数对 C++的作用如同 -fthis-is-varible参
数(对C和C++的共同影响请参阅「C的方言参数」
中之-traditional项)。

    除上所述之外,专对 C++之最佳化、警告和
程式码生成参数也一并在下讨论:

-fno-default-inline
在 class中忽略inline之作用。

-Wenum-clash
-Woverloased-virtual
-Wtemplate-debugging
对于这些情况,只对 C++程式提出警告(相关内
容请看「警告参数」节)。

+eN
限定已定义之virtual函数如何使用(相关内容请
看「程式码生成参数」节)。

除错参数
========
    对于编译后的可执行档之除错方式,通常的
方是是在编译之时便在特定部份放入除错码,有
除错码的程式在大小和执行速度上都会略逊一般
程式一筹,但相对的却也提供额外的讯息让 gdb
等除错程式进行对原始码及变数的追踪等工作,
除错码的规格有许多种,而 gdb也有自己独特的
部份,因此在不同的系统和不同的除错器下,便
需不同的参数才能顺利工作。

-g
产生作业系统认可格式(native format)的除错
码(可能为stabs、COFF、XCOFF或是 DWARF之一)
,以便 GDB除错。大多数的系统使用 stabs格式
;本参数除了会产生标准格式码外,还会产生额
外的除错码,这些额外的部份只有 GDB能辨识,
目的是为了提供更多讯息,因此若是要以别的除
错程式来除错,便需使用 -gstabs+、-gstabs、
-gxcoff+、-gxcoff、-gdwarf+或是-gdwarf,这
些参数的作用请看下列依次的说明。

-ggdb
除了产生 native format的除错码外,还再包含
GDB专用的扩充部份。

-gstabs
产生 stabs格式除错码,但不包含 GDB的扩充部
份,这是在大多数 BSD系统上 DBX所使用的格式
,然而在MIPS和 Alpha系统上却会产生 DBX所不
能辨识的内嵌(embedded) stabs除错码。

-gstabs+
产生包含 GDB扩充部份的 stabs格式除错码,然
而这样别的除错程式便无法用来除错。

-gcoff
产生COFF格式的除错码;COFF格式是System V至
Release 4 之前的 SDB所用之格式。

-gxcoff
产生 XCOFF格式之除错码;这个格式为DBX在IBM
RS/6000 系统上所使用。

-gxcoff+
产生包含 GDB扩充部份的 XCOFF格式除错码。

-gdwarf
产生 DWARF格式的除错码;这个格式是System V
Release 4 上 SDB所用之格式。

-gdwarf+
产生包含 GDB扩充部份的 DWARF格式除错码。

-gLEVEL
-ggdbLEVEL
-gstabsLEVEL
-gcoffLEVEL
-gxcoffLEVEL
-gdwarfLEVEL
产生不同格式的除错码,并依 LEVEL的数值决定
除错码的多寡,内定数值为 2。
LEVEL 1 产生最少量的除错码,通常置于非主要
除错部份,在这些除错码中包含函数和外部变数
(external variables)的描述,但无行编号和区
域变数(local variables)。
LEVEL 3 包含比 LEVEL 2更多额外资讯,如所有
此程式中定义的巨集。

-p
产生分析程式prof所能确认的特殊码,在编译和
连结时都需使用本参数才能达到目的。

-pg
产生分析程式 gprof所能确认的特殊码,在编译
和连结时都需使用本参数才能达到目的。

-a
产生basic blocks的基本讯息,如每个blocks执
行的时间、启始位址和包含的函数名称;如果-g
一起使用时,行编号和第一个 block的档名也会
一併记录,这些资料内定会附加到bb.out中,可
用tcov或是 gprof作分析。

-dLETTERS
本参数是对"编译程式"作 debug,方式为当编译
进行到 LETTERS所指定的步骤时,将特定资讯倾
印到指定的档桉去,相信读者看到此可能会觉得
奇怪,为何要对编译程式除错呢?照说 GCC应该
是不太可能会出错的,事实上别忘了 GCC是网路
上大家同心撰写出来的,新增改进部份的测试方
式为令其编译一程式并观查其结果,这时本参数
便派上用场了,有时也会发生 patch后再编译旧
程式时竟然出现过去没有的错误,若确定旧程式
没问题,可用本参数一步一步追踪编译的结果;
以下是 LETTERS的部份;
M 当前置处理完毕后dump出所有的巨集定义
N 当前置处理完毕后dump出所有的巨集名称
D 当前置处理完毕后dump出所有的巨集定义至一
般输出,因此可重新将结果导至档桉
y 在语法分析(parsing) 时将除错讯息dump至标
准错误输出
r 在 RLT产生后将内容dump至FILE.rtl
x 只产生 RLT码后便停止,本项通常和上一项 r
一起使用
j 第一轮跳跃最佳化作完便dump至FILE.jump
s 完成 CSE后dump至FILE.cse
L 当迴圈最佳化(loop optimization)完成后便
dump至FILE.loop
t 第二轮 CSE完成后dump至FILE.cse2
f flow analysis 完成后dump至FILE.flow
c 指令连结完成后dump至FILE.combine
S 第一轮指令排程语法分析完成后后dump至
FILE.sched
l 区域暂存器变数定位完成后dump至FILE.lreg
g 全体暂存器变数定位完成后dump至FILE.greg
R 第二轮指令排程语法分析完成后dump至
FILE.sched2
J 最后一轮最佳化完成后dump至FILE.jump2
d delayed branch 排程完成后dump至FILE.dbr
k 暂存器变数转换到堆叠后dump至FILE.stack
a 完成上列所有dump
m 编译完毕后印出记忆体使用状况至std error
p 将assember的输出加上有使用之alternative
和 pattern的注释

-fpretend-float
当进行cross-compiler时,将目标主机的浮点运
算器假设为和目前主机相同,以便编译出的程式
在目标主机上能执行无误;所谓cross-compiler
为在某一型主机或是OS上(如Unix)编译出另一OS
(如 DOS)执行档的过程,如此在软体移植上更为
方便,相关的详细内容会另文再叙。

-save-temps
将编译时的产生的中间暂存档储存起来,例如使
用"-c -save-temps"来编译 foo.c时将会产生
foo.i 和 foo.s。

-print-libgcc-file-name
只是印出'libgcc.a'此档的绝对名称,在本参数
下 GCC并不作任何事--只是列出libgcc.a这个字
串;当使用 -nostdlib参数却同时想和libgcc.a
连结时便可依下列方式使用本参数:
gcc -nostdlib FILES... 'gcc -print-libgcc-
    file-name'

结语
====
    以上所介绍的为部份 GCC参数的用法,希望
能让读者对整个编译流程有助益,下次我们继续
探讨其馀的部份。

类别:默认分类||添加到搜藏 |分享到i贴吧|浏览(353)|评论 (0)
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu