分享

用GCC编译链接程序--编译链接器GCC常用功能

 panic moon 2012-03-09

一,GCC编译器简介

 

     GCC是Linux平台下常用的编译链接器。编译链接的过程分为:

     源代码-->预处理文件(.i)-->编译后的汇编代码(.s)-->汇编后的二进制文件(.o)-->链接后的二进制物件(无后缀)。

     处理程序分别是 :cpp、ccl、as、ld。

     使用 -v选项,可以看到各个阶段关联的处理程序。

 

     使用gcc -E 指示gcc对源代码进行预处理,结果直接输出到终端。

     使用gcc -S 指示gcc编译成为汇编语言

     使用gcc -c  指示gcc直至形成二进制文件(不进行链接)

     使用gcc      指示gcc链接形成二进制物件(多个二进制模块链接形成大的模块或者可执行程序)

 

     因此你需要的目标文件的种类是 -E、-S、-c或者不带这些参数确定的,

     源文件可以是中间文件的一种。-o参数控制的仅仅是输出文件的名称。

 

     但是gcc默认会根据源文件的后缀去判断应该调用处理程序的那些。例如源文件的后缀是.c,则gcc -E使用的是cpp,gcc -c则使用cpp、ccl、as。如果源文件的后缀是.o,则gcc -E 是无法进行的,会报错:linker input file unused because linking not done。这是gcc发现这个应该进行链接,但是选项指示不使用linker程序,因而报这种错误信息。如果源文件是二进制的文件,但是保存的源文件后缀 却是.c,则gcc会当作这是.c文件,如果采用gcc不带参数,则gcc会很多错,因为它把这个文件当作源代码处理的。

 

     注意:这里,源文件指的是gcc的输入文件,源代码指的是程序源代码文件。

 

     以下是使用gcc 不带-E、-S、-c这些参数时,将会进行的处理与输入文件后缀(类型)的对应关系。

     使用-save-temps可以保存编译各个阶段的临时文件。

 

<![endif]-->

后缀
种类说明
源文件相应的后续处理
预处理
编译
汇编
链接
.c
C 语言 程序
.C/.cc/.cxx
C++ 语言 源程序
.h
源程序所包含的头文件
--
--
--
--
.i
经过预处理的 C 源程序

 

.ii
经过预处理的 C++ 源程序

 

.s
汇编语言源程序

 

 

.S
汇编语言源程序

 

.o
目标文件

 

 

 

.a
由目标文件构成的档案文件

 

 

 

 

二,GCC常用编译选项

 

    格式为:

    gcc [option | filename] .......

 

    gcc的命令可以分为如下几类:

 

     1,全局选项  -c,-S,-E ,-o

     2,目录选项  -Ipath,-Lpath

     3,链接选项  -shared,-llibrary -Wl option

     4,警告选项  -Wall, -Wextra,-Wconversion,-Wshardow,-Wcast-qual

     5,调试选项  -g ,-ggdb

     6,优化选项  -O, -O0,-O1,-O2,-O3

     7,其它选项  -fPIC

  
   部分选项简介:
     -Wl,option      : 传递 option 给链接程序
        -Wl,-Bstatic  : 明确限定链接静态库 ( 链接程序将不再接受动态链接库,直到再次指定 -Bdynamic)
        -Wl,-Bdynamic : 明确限定链接动态库

 

    -fPIC   : 生成动态链接用位置无关代码 (Position-independent code)
    -shared : 生成动态链接目标文件
    -L      : 指定链接阶段链接库所在路径
    -l      : 指定要链接的库(原库名去除前缀 lib 和后缀 .a/.so 的剩余部分)

 

 

a)目录选项

     目录选项是为编译器指定搜索头文件和库文件所在目录的,

     编译时,头文件的搜索顺序为:

        -Ipath指定--------->环境变量C_INCLUDE_PATH或者CPLUS_INCLUDE_PATH--------->/usr/local/include和/usr/include

 

     库文件搜索顺序:

        -Lpath指定-------->环境变量LIBRARY_PATH----------->/usr/local/lib和/usr/lib。

     可以利用搜索顺序使得当前目录下的程序编译时链接静态c++库libstdc++.a:

 

    ln -s ` g++ -print-file-name = libstdc++.a` (注意是反引号,不是单引号,意义是运行反引号里边的命令)

    这样便建立了一个到g++使用的静态库libstdc++.a的符号链接。

 

    g++   -o hello -L. hello.cpp 该命令会使得g++搜索当前目录的链接库,搜索到了libstdc++.a,因而采用静态链接。

   

    使用ldd查看编译结果,可以看到没有对c++动态链接库的依赖:

 

    #ldd  hello
        linux-gate.so.1 =>  (0x00a58000)
        libm.so.6 => /lib/libm.so.6 (0x006d7000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00858000)
        libc.so.6 => /lib/libc.so.6 (0x00591000)
        /lib/ld-linux.so.2 (0x00573000)
  
  b)调试信息选项
   -g [Format][LEVEL]   : 设定生成的调试信息的格式和级别。
         -g
        编译器指示操作系统生成本地格式(如stabs、COFF、XCOFF、DRAWF-2)
     -ggdb
     生成的调试信息且其中尽可能包含所有额外的GDB扩展
   
    FORMAT: 指定调试信息的格式,如 ‘stabs+’, ‘stabs’, ‘xcoff+’, ‘xcoff’, or ‘vms’
    LEVEL:
        0:不生成调试信息
        1:最小调试信息,用于跟踪程序的部分内容:函数、外部变量,不能跟踪局部变量和行 号。
        2:默认的debug信息生成级别。可跟踪局部变量和行号。但不包含宏。
        3:包含额外的debug信息,包括宏的信息。             
   
   建议使用: 调试使用-ggdb,发布使用GNU package发布默认的-g。
   
   注意事项
    因为GCC允许 –g 和 –O选项同时存在,在这种情况使用GDB调试会产生奇怪的结果
   (如: 某 些变量不存在了,某些语句没有被执行,处理流程发生了变化等等),
    在开发调试过程中尽量关闭 优化选项。
 
   c)优化选项:
           -On,n为0~3之间的数值,表示优化级别。

方案
对目标文 件的影响
对编译过程 的影响
优化级别选用的方案
○: 使用; △: 部分使用; ×: 不使用)
执行 速度
代码 大小
编译 速度
内存 使用
-O0 或者默认  (default)
-O1 或者 - O
-O2
-O3
合并公共表达式(源代码级别优 化)
加快
减少
减慢
增加
×
函数内联(源代码级别优 化)
加快
增加
减慢
增加
×
循环展开
(空间换时间优 化)
加快
增加
减慢
增加
×
×
×
度优化
加快
不增
减慢
增加
×
×
   
     推荐:调试使用-O0,发布使用与GNU package发布优化级别相同的-O2。    
   
  d)警告选项:

      推荐使用:
         -Wall -W -Wconversion -Wshadow -Wcast-qual

         -Wall 开启多个常用的错误警告选项。它结合了很多可以单独使用的警告选项。
             - Wformat (included in -Wall)   
                        这个选项在 -Wall 中包含了。这个选项对于诸如 printf scanf 这些函数中的不正确的字符串 格式的使用提出警告,
                        在这种情况下,指定的字符串格式与对应函数的参数的类型不 匹配。
                        例如: printf(“my name is %s/n”, name, name);
          
           -Wimplicit (included in -Wall)
                      这个选项在 -Wall 中包含了。这个选项对使用没有声明的任何函数进行警告。
                常见的没有声明就引用的函数的典型原因是没有包含头文件  

          -Wreturn-type (included in -Wall)
                        
                这个选项在 -Wall 中包含了。这个函数对没有返回值,但是没有声明返回值是 void 的函数提出警告。
                        example :  int func() {   }
       
          -W or -Wextra  
                         
                       这个开启一些而外的 -Wall 没有包含的警告标识。例如在有符号数和无符号数之间进行比 较、
                       指针和证书 0 进行除了! = 的比较运算等。
                       example :    void func( void * pointer ){  if (pointer <= 0 ) … }

         -Wconversion  

               这个选项对可能引发不可预料的结果的隐式类型转换提出警告。                    
                       例如:    unsigned int length = - 1 ;

         -Wshadow  

                    这个选项对于某个范围内已经被声明的变量的重新声明提出警告。
                     例如:    { int xxx = 1 ; { int xxx= 2 ; … } … }
   
         -Wcast-qual  
                    
                   这个选项对于强制转化的删除一个类型限定符的指针提出警告,例如 const 类型限定符。
                   例如:    void func( const char * xxx) {  char * yyy = xxx ; … } 

 

    e)编译链接、创建库文件的过程:

 

    使用源代码文件test.c、main.c作为说明例子,其中main.c用到了test.c中的函数:

 

    test.c: 

         int max(int a,int b) {

           return a>b?a:b;

          }

   main.c:

        int main(){

           printf("max(1,2)=%d/n",max(1,2));

           return 0;

         }

 

    1,创建动态库 :

         1)gcc -fPIC -c -o test.o test.c     

          -fPIC表示产生位置无关代码(position independence code),

           -c表示产生的是二进制文件,不进行链接,

           -o表示产生的文件名。

         2)gcc -shared -o libtest.so test.o

            使用1)中编译的二进制文件,产生动态库

    2,使用动态库

       gcc -o main mian.c -L. -ltest

       使用链接的库文件在前目录,名字为test。

 

    3,创建静态库

        1)gcc -c -o test.o test.c

           -c表示产生的是二进制文件,不进行链接,

           -o表示产生的文件名。

        2)ar rcs libtest.a test.o

            使用1)的二进制文件,产生静态库(文档文件)

 

    4,使用静态库

      gcc -o main main.c -L. -ltest

       使用链接的库文件在当前目录,名字为test。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多