Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1184729
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: C/C++

2015-12-09 19:39:07

GCC常用参数

GCC常用参数

总的来说,GCC应该是一个编译器。可是,为什么我还要在这里介绍GCC的家族成员呢?其实,整套的GCC环境并不是由GCC构成的,他是由多个包所组成的。这些包的互相作用产生了GCC的开发环境。其中,有一些包是你开发应用程序所必备的基本包。离开这些包你将无法正常使用GCC


GCC的基本包列表。


GCC的基本开发环境,主要由一下几个包构成。Binutils,这个是辅助GCC的工具包,里面包含了连接器,汇编器,动态静态库生成程序,等等。GCC,这个包是GCC本身。当然GCC包中还包括一下几个包,如core,java,ada等,每个包都代表了一种语言。然后,就是win32api,mingw-runtime,这个是在Win32下使用的标准函数包。如果,你使用的是Cygwin或者是在Unix环境下,那么这个包就是GlibC


所以,由上所述。GCC的基本包有:binutils gcc glibc/[win32api,mingw-runtime]有了这些包。你基本能够开始编译应用程序了。


当然,如果说你想要写一个小程序。自然这些包已经够了。但是如果你要写一个较大的工程。那么,这些包也许就不能很好的胜任你的工作了。因为,对于一个大的项目,需要编译的文件不只一个,而且还有依赖关系等等。

所以,GCC中还包括gmake包用于管理项目。当然,还有automake。但是我个人还是不太喜欢automakeautomake其实是帮助你自动的管理你的项目,当然实现这个自动也是比较麻烦的,所以与其用automake管理中小型项目,不如用gmake自己写个脚本。不过,automake通常用于源代码发布的应用,如果在开发时使用会延长开发周期。

Gmake,automake,都是通过编译脚本来批量的编译程序。他们能够更具你所给定的依赖关系,来自动的判断需要重新编译的源代码,然后编译。这点的确可以帮助开发人员减轻不少的人力和开发周期。比如,你用Makefile管理一个项目,那么在你第一次编译程序以后,如果你的源代码没有做过任何编辑,那么下次再调用gmake的程序时,gmake就不会再去一一编译每个文件。而是简单的连接一下主程序,或者什么都不作的退出(这要取决于你写的Makefile脚本)


但是,对于有些开发人员来说,上面这些包还是不能满足他们的要求。因为他们要调试程序。所以,GCC还包括另一个包。那就是GDBgdbGCC开发的,用于跟踪调试的,命令符型调试器。它的功能还是比较强大的。基本,你能在VC下做到的,GDB也可以。不过,GDB的命令还是比较多的。掌握一些基本的调试命令一般就够使用了。


总结

GCC开发环境包括如下几大包。

           

binary

           
           

基本包

           
           

提供基本的汇编器,连接器等

           
           

gcc

           
           

基本包

           
           

各种语言的编译器,包括C,C++,Ada,Java

           
           

Win32api,mingwi-runtime/glibc

           
           

基本包

           
           

系统函数库

           
           

Gmake/automake

           
           

需要包

           
           

管理项目编译的程序

           
           

gdb

           
           

附加包

           
           

调试程序

           


第二节 GCC的常用编译参数


VC,TC等编译器不同,GCC其实是可以很方便的在提示符下编译程序的。GCC在提示符下编译程序,并没有如同VC那样的冗长而晦涩的编译参数。相反,却有着比VC更灵活且简短的参数。

不得不承认,不懂GCC编译参数的人,确实会损失一些GCC的强大功能。所以,我下面简单介绍一下GCC的一些基本编译参数。这里,我以C编译器为例。


编译二进制代码

           

$gcc             -c yours.c -o yours.o

           

使用这段指令,GCC将会把yours.c编译成yours.o的二进制代码。其中,yours.o就类似于VC,TC中的.obj文档。


编译最简单的小程序。

           

$gcc             -o yours yours.c

           

通过这条指令,GCC将会把yours.c源代码编译成名为yours的可执行程序。当然,您也可以将yours.c改成我们刚才介绍的yours.o文件。这样,gcc将使用编译刚才编译好的二进制文档来链接程序。这里,格式的特点是,-o 后面是一串文件列表,第一个参数是所编译程序的文件名,从第二个开始,就是您编译和连接该可执行程序所需要的二进制文档或者源代码。


编译时将自己的头文件目录设为默认头文件目录

           

$gcc             -I”Your_Include_Files_Document_Path” -c yours.c -o             yours.o

           

这条指令中的-I参数将会把Your_Include_Files_Document_Path添加到你默认的头文件目录中。这样您将可以使用 #include 来导入头文件。


编译时使用自己的静态库存放目录

           

$gcc             -L”Your_Lib_Files_Document_Path” -o yours yours.o

           

这条指令将会让GCC在连接时除了在默认Lib存放目录中搜索指定的静态库以外,还会在Your_Lib_Files_Document_Path中搜索。


编译时使用静态连接库

           

$gcc             -lyour_lib -o yours yours.o

           

这条指令将会让GCC在连接时把 libyour_lib.a中您所用到的函数连接到可执行程序中。此处注意,GCC所使用的静态连接库是lib*.a格式的。在连接时,只且仅需要提供*的内容就可以了。


编译时使用优化

           

$gcc             -O2 -c yours.c -o yours.o

           

使用优化方式编译程序,其中除了-O2以外,还有-O3 -O1等等。他们代表不同的优化等级。最常用的,是-O2优化。当然,还有针对特殊CPU的优化,这里就不介绍了。


编译时显示所有错误和警告信息

           

$gcc             -Wall -c yours.c -o yours.o

           

GCC在默认情况下,将对一些如变量申请未使用这样的问题或者申请了没有给予初始值的问题忽略。但是,如果使用了-Wall参数,编辑器将列出所有的警告信息。这样,您就可以知道您的代码中有多少可能会在其他操作系统下出错的地方了。(用这个指令看看你的代码有多少地方写的不怎么合适。)


编译连接时,加入调试代码

           

$gcc             -g -o yours yours.c

           

正如同VCdebug编译模式一样,GCC也有debug模式。添加了-g 参数编译的可执行程序比普通程序略为大一些,其中添加了一些调试代码。这些代码将被gdb所支持。


连接时缩小代码体积

           

$gcc             -s -o yours yours.o

           

这个参数,似乎我没有在Unix环境下看到过。也不知道具体什么作用。因为有人说Visual-MinGW生成的代码小,于是研究了一下她的编译参数,发现release模式的编译参数就加了这一项。貌似编译后的代码的确缩小了很多。


获得帮助

           

$gcc             --help

           

这条指令从意思上就能看出,获得gcc的帮助信息。如果您有什么特殊需要,也许这个指令能帮上点小忙。


LOCAL_CFLAGS 一些常见选项列举

msoft-float

不应该是让浮点执行更快吧,应该是ARM不支持浮点操作,而通过软件模拟的办法,让ARM支持浮点,遇到浮点指令,就转换成一个整数操作的指令序列


hard-float 是直接生成浮点运算的指令(如果有的话);hard-float 要硬件支持。

soft-float 是用库模拟浮点运算(如果有的话)。



 

常见gcc编译参数一:编译过程的4个阶段:预处理,编译,汇编,链接;
1:最常用的方式
gcc hello.c -o hello
2:预处理后停止编译
gcc -E hello.c -o hello.i(.i通常为已经预处理过的C原始程序)
3:将hello.i编译为目标代码,可以使用-c参数来完成
gcc -c hello.i -o hello.o
也可以使用-x参数让gcc从指定的步骤开始.
4:将生成的目标文件链接成可执行文件
gcc hello.o -o hello
5:多个源文件时
gcc f1.c f2.c -o file
二:gcc参数的警告提示功能
1:-pedantic 使用了ANSI/ISO C语言扩展语法的地方将产生相应的警告信息
2:-Wall   产生尽可能多的警告信息,建议始终带上
3:-Werror  将所有的警告当成错误进行处理
三:库依赖
函数库实际上就是一些头文件和库文件的集合.
-I选项向gcc的头文件搜索路径中添加新的目录
-L选项向gcc的库文件搜索路径中添加新的目录
-l指定链接的库文件名,如 -ldavid 表示指示gcc去连接库文件libdavid.so
-static强制使用静态链接库
动态库文件(.so)和静态库文件(.a)的区别在于程序执行时所需的代码是运行时动态加载的,还是编译时静态加载的.gcc优先使用动态库
四:其他
-On 控制优化代码的生成,n是一个代表优先级别的整数;n取0~3;-O相当于-O1;
-O1 减小代码的长度和执行时间,一般包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops);
-O2 在O1基础上,进行一些额外调整,如处理器指令跳转;
-O3 在O2基础上,循环展开一些其他和处理器特性相关的优化工作;
-pipe:管道,它可以用来同时连接两个程序,其中一个程序的输出将直接作为另一个程序的输入,这样就可以避免使用临时文件,提高编译速度,但编译时消耗更多的内存.
-Dmacro 定义指定的宏,使它能够通过源码中的#ifdef进行检验

-g3   获得有关调试程序的详细信息

-S   要求编译程序生成来自源代码的汇编程序输出
-v   启动所有报警
-w   禁止所有报警
五:常见错误类型
1:syntex error,语法错误
2:can't find include file,头文件错误
3:ld:lm:No such file or directory,找不到所需的函数库
4:Undefined symbol未定义符号:源代码文件未被包含或编译。

GCC编译器参数(zz)

 

除了最简单的运行gcc/g++ filename(这样只能运行最简单的小程序)外,GCC都需要用各种选项来实现其强大的功能。

下面是GCC的一些常用选项描述:

生成特定格式的文件:
-E          只激活预处理,但不生成文件,需要把它重定向到一个输出文件里面。例子: 
             gcc -E hello.c > pianoapan.txt 
  gcc -E hello.c | more
-C         在预处理的时候,不删除注释信息,一般和-E使用,有时候用这个分析程序很方便。 
-S         只激活预处理和编译,就是指把文件编译成为汇编代码。 
  例子: gcc -S hello.c 
-c          只激活预处理,编译,和汇编,也就是他只把程序做成obj文件 
  例子: gcc -c hello.c 
-o          指定目标文件名称,例子:
  gcc -o hello hello.c

包含头文件和库: 
-include file 
  包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,就可以用它设定,功能就相当于在代码中使 用#include,例子用法: 
  gcc hello.c -include /root/pianopan.h 
-Idir
  指定所需头文件的位置,在使用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如果没有找到,他回到缺省的 头文件目录找,如果使用-I制定了目录,他会先在所指定的目录查找,然后再按常规的顺序依次查找。
-I-                 参数“-Idir”的功能,所以一般在-Idir之后使用。 
-Ldir 
  指定编译时,库的搜索路径。第三方或自己提供的库,可以用它制定目录,否则编译器将只在标准库的目录找。这个dir就是目录的名称。 
-llibrary 
  制定编译的时候使用的库(指定了路径当然还得指定库名),常用的lib库有lpthread(线程库),lm(数学库),lz(zlib库)及 lcrypto(linux下的MD5加密库)等,当然可以添加自己或第三方的库文件。例子:
  gcc -lncurses hello.c               使用ncurses库编译程序。

优化选项:
-O0/1/2/3/s               介绍如下:
-O0                  不进行优化处理。
-O/O1 GCC将执行减少代码尺寸和执行时间的优化,对于那些会严重影响编译时间的优化选项,这个级别的优化并不会执行。
-O2                  在这一级别GCC将会提供所有支持的优化,但这其中并不包括以空间换时间的优化手段,例如编译器不会使用循环展开和函数内联。和-O相比,该选项进一步加 快了编译时间和生成代码的性能。
-O3                  除了-O2提供的优化选项外,还指定了-finline-functions,-funswitch-loops和-fgcse-afer-reload 选项,目的只有一个就是全力执行代码优化,但是用"-O3 -fno-inline-functions"既可以使用-O3的功能又关闭函数内嵌功能。
-Os                  这个选项是专门用来优化代码尺寸的,-Os打开了所有-O2级别中不会显著增长代码尺寸的优化选项 在用GDB调试优化后的程序时,运行时的指令和你所编写指令就有不一样,也就会出现你所想象不到的结果。对付这种情况时,需要在编译程序时关闭编译优化。   

宏定义:
                   -DMACRO                         以字符串“1”(默认值)定义 MACRO 宏。
                   -DMACRO=DEFN              以字符串“DEFN”定义MACRO 宏,注意中间不能有空格。
                   -UMACRO                         取消对 MACRO 宏的定义。

语言选项 (LANGUAGE OPTIONS): 
-ansi

支持符合ANSI标准的C程序。

 

-frtti    开启RTTI的支持(dynamic_cast和typeid需要用到),和vs c++不同,这在gcc中 是默认选项。使用"-fno-rtti"将其禁用。

-fno-builtin

       不接受不是两 个下划线开头的内建函数(built-in function).目前受影响的函数有_exitabortabsallocacosexitfabs,labsmemcmpmemcpysinsqrtstrcmpstrcpy,strlen有 时候上面的这些函数在一些地方被built-in后,会产生运算结果和预想的 不一样甚至是错误的,比如abs(),会导致-10*abs(x-1)== 10*abs(x-1)的怪异情况,原因是运算被优化而得 到错误的结果

警告选项:

 

-W               编译器的警告设置参数,拥有众多的选项,下面举一些常用的例子:
     -Woption 让编译器给出option指定的编译警告,常用的一些如下:
                   unused-function: 遇到仅声明过但尚未定义的静态函数时发出警告。
                   unused-parameter: 从未用过的函数参数的警告。
                   unused-variable: 在本地声明但从未用过的变量的警告。
                   unused-value: 经计算但从未用过的值得警告。
                   return-type: 对函数返回类型不当的警告。
                   uninitialized:在初始化之前就使用自动变量。
                   float-equal:   比较两个浮点数是否相等。
    -Wall       给出“几乎”所有的编译器警告,注意是“几乎”。下面是一些-Wall没有输出的警告类型:
                   sign-compare:将有符号类型和无符号类型数据进行比较时发出警告。
                   unreachable-code:如果发现从未执行的代码时给出警告。
                   inline:如果某函数不能按要求内嵌(inline),则无论是函数声明为inline或者是指定了-finline-functions 选项,编译都将发出警告。      
    -Werror               把所有的警告都视为错误处理。
    -Wno-option               如果我们不想输出某些警告信息,可以使用此参数形式,比如:
                   -Wno-unused-function
                   -Wno-unused-variable
                   -Wno-unused-parameter
                   -Wno-uninitialized

调试和可执行文件形式:
-g                 指示编译器,在编译的时产生调试信息。 
-ggdb           此选项将尽可能的生成gdb的可以使用的调试信息(比-g生成的信息更多些)。
-pg               此选项在运行后生成一个分析文件gmon.out分析每一个模块的运行时间等信息,可以用“gprof execname gmon.out”命令打开。
-static           此选项将禁止使用动态库,编译得到的程序会比较大,但可以自由运行。 
-share          此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库。

上面的是一些常用的参数以及对应的选项,如有更细致的需求,可以参考man page。

附加:使用GCC生成静态链接库或动态链接库
         首先需要目标文件(*.o),用gcc/g++ -c生成,如:gcc -c test1.c test2.c test3.c
1. 生成静态链接库
         使用ar命令: ar -crv libtest.a test1.o test2.o test3.o 即可产生test.a文件。
         可以用命令 nm test.a 来看里面的目标文件和导出函数(带 T 标记)。
         使用的时候加上:-L(路径) -ltest。注意这里不是llibtest.a或llibtest,-l 参数会自动添加lib和.a到首尾,然后去-L指定的目录加载.a文件。
2.生成动态链接库
         用动态库的好处是:更新了动态库之后链结它的程序不用重新编译,但需要运行时链接。
         使用 gcc -o libtest.so -shared -fPIC      test1.o test2.o test3.o
         -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的,所以动态载入时是通过代码拷贝的方式来满足不同进程需要,而不能达到真 正代码段共享的目的。
         可以用命令 nm test.so 来看里面的目标文件和导出函数(带 T 标记)。

         还有一个需要注意的地方,在不同的硬件架构和位宽平台上的.a文件和.so文件 不能互用,需要重新生成不同平台的.o文件,然后再生成相应的.a文件和.so文件。否则编译会出现“skipping incompatible ****.a/so”之类的错误。


阅读(926) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~