GCC编译器

参考GCC
源代码到可执行文件的步骤
  • 预处理:主要是处理那些源文件和头文件中以 # 开头的命令(后缀 .i
  • 编译:把预处理完的文件进行一系列分析和优化后,生成汇编代码文件(后缀 .s
  • 汇编:将汇编代码转换成可执行的机器指令(目标文件)(后缀 .o
  • 链接:目标文件已经是二进制文件了,与可执行文件的组织形式类似,只是有些函数和全局变量的地址还没找到,程序不能执行。链接就是找到目标地址,将所有的目标文件组织成一个可执行文件(后缀 .out
GCC(编译器)
  • 查看 gcc 的版本

    gcc --version
    
  • 编译源代码(一步完成)

    gcc demo.c -o demo # 将源代码 demo.c 直接编译生成可执行文件 demo
    # -o选项是 生成文件的文件名
    
  • 64位系统下,按照32位环境编译

    gcc demo.c -o demo -m32
    
  • gcc/g++指令选项功能
    -E预处理指定的源文件,不进行编译
    -S编译指定的源文件,但是不进行汇编
    -c编译、汇编指定的源文件,但是不进行链接
    -o指定生成文件的文件名
    -llibrary其中 library 表示要搜索的库文件的名称。该选项用于手动指定链接环节中程序可以调用的库文件
    -ansi对于C语言程序来说,其等价于 -std=c90;对于C++程序来说,其等价于 -std=c++98
    -std=手动指定编程语言所遵循的标准
  • -l 选项:手动添加链接库

    链接库是一个具有许多目标文件的集合,它们在一个文件中以方便处理

    gcc demo.c -o demo -lm
    # 举例:数学库的文件名是 libm.a
    # 前缀 lib 和 后缀 .a 是标准的,m 是基本名称
    # -l选项后紧跟着的是库的基本名称
    
  • 一次处理多个文件

    # 假设有两个源代码 demo1.c demo2.c,可以一起编译
    gcc demo1.c demo2.c -o main  # 调用的时候 一定要有头文件
    # 或者说有更多的源代码 要一起编译
    gcc *.c -o main
    
  • 使用静态链接和动态链接

    注意: 动态链接和静态链接相比,静态链接生成的可执行文件的体积更大

    • 库文件:包含有功能实用的目标文件
    • 静态链接库:采用静态链接方式实现链接操作的库文件
      • 在程序文件中哪里用到了库文件中的功能模块,GCC编译器就会将该模板代码直接复制到程序文件的适当位置,最终生成可执行文件。
      • 优点:生成的可执行文件不再需要任何静态库文件的支持,就可以独立运行(可移植性强)
      • 缺点:如果程序文件中多次调用库中的同一功能模块,则该模块代码就会被复制多次,生成的可执行文件会包含多段完全相同的代码,造成代码的冗余
    • 动态链接库:采用动态链接方式实现链接操作的库文件
      • 程序文件中哪里需要库文件,GCC编译器 不会 直接把该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件
      • 优点:由于可执行文件中记录的是 功能模块的地址,真正的实现代码会在程序运行时被载入内存,即便功能模块被调用多次,使用的都是同一份代码(动态链接库又被称为共享链接库)
      • 缺点:生成的可执行文件无法独立运行,必须借助响应的库文件(可移植性差)
  • 静态链接库

    • 我们实现通过源代码实现了一个功能(包含很多源代码),但是我们仅希望别人使用我们实现的功能,不想它们看到具体实现的源码,很简单,就是把它们加工一个 静态链接库

    • 静态链接库的创建

      源文件加工厂静态链接库,满足以下2个条件:

      1、源文件中只提供可以重复使用的代码,例如函数、设计好的类等,不包含main函数

      2、源文件在实现具备模块功能的同时,还要提供访问它的接口,也就是包含各个功能模块声明部分的头文件

      # 假设有 add.c、sub.c 和 div.c 
      # 1、将所有的源文件,编译成相应的目标文件:
      gcc -c add.c sub.c div.c
      
      # 2、使用 ar 压缩命令,将生成的目标文件打包成静态链接库
      ar rcs 静态链接库名称 目标文件1 目标文件2 ....
      # 静态链接库的命名规则:libxxx.a  --- xxx可以自己定义
      # Linux 系统下,静态链接库的后缀名为 .a
      # Windows 系统下,静态链接库的后缀名为 .lib
      
    • 静态链接库的使用

      就是在程序的链接阶段,将静态链接库和其它目标文件一起执行链接操作,从而生成可执行文件

      # 1、先将 main.c 文件编译成目标文件
      gcc -c main.c
      
      # 2、链接操作
      gcc -static main.o libxxx.a -o main
      # 其中 -static 选项强制GCC编译器使用静态链接库
      
      # 3、如果GCC编译器提示无法找到 静态编译库,则使用下面的链接操作
      gcc main.o -static -L /root/demo/ -lxxxx -o main
      # -L 选项用于向GCC编译器指明静态链接库的存储位置
      # -l 选项用于指明所需静态链接库的名称,xxx就是静态链接库的名称
      
  • 动态链接库

    GCC编译器生成可执行文件时,默认情况下会优先使用动态链接库实现链接操作,除非当前系统环境中没有程序文件所需要的动态链接库,GCC编译器才会选择相应的静态链接库。如果两种都没有,则链接失败。

    • 动态链接库的创建

      • 直接使用源文件创建动态链接库

        # 假设有 add.c、sub.c 和 div.c 
        gcc -fpic -shared add.c sub.c div.c -o libmymath.so
        # -shared选项用于生成动态链接库
        # -fpic选项是,令GCC编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用 相对地址。这样,无论将来链接库被加载到内存的什么位置,都可以正常使用
        # Linux 系统下,静态链接库的后缀名为 .so
        # Windows 系统下,静态链接库的后缀名为 .ddl
        
      • 两步得到动态链接库

        # 假设有 add.c、sub.c 和 div.c 
        # 1、将源文件编译成目标文件
        gcc -c -fpic add.c sub.c div.c
        # -fpic选项是,令GCC编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用 相对地址。这样,无论将来链接库被加载到内存的什么位置,都可以正常使用
        
        # 2、利用目标文件,生成动态链接库
        gcc -shared add.o sub.o div.o -o libmymath.so
        # -shared选项用于生成动态链接库
        # Linux 系统下,静态链接库的后缀名为 .so
        # Windows 系统下,静态链接库的后缀名为 .ddl
        
    • 动态链接库的使用

      因为前面将 add.csub.cdiv.c 打包到了 libmymath.so 动态链接库中,此时该项目只剩下了 main.c 源程序文件,因此执行此项目,就变成了将 main.clibmymath.so 进行链接,生成可执行文件。

      注意:test.h 头文件并不直接参与编译,因为在程序的预处理阶段,已经对项目中需要用到的头文件进行了处理。

      # 1、直接生成可执行文件
      gcc main.c libmymath.so -o main
      # 生成的 main 通常无法直接执行,在执行过程中无法找到 libmymath.so 动态链接库。
      
      # 2、通过 lld main 指令,可以查看当前文件在执行时需要用到的所有动态链接库,以及各个库文件的存储位置
      lld main
      

      运行由动态链接库生成的可执行文件时,必须确保程序在运行时,可以找到这个动态链接库,常用的解决方案有:

      • 将链接库文件移动到标准库目录下

        比如:/usr/lib/usr/lib64/lib/lib64

      • 在终端输入 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效)

      • 修改 ~/.bashrc~/.bash_profile 文件,即在文件的最后一行添加

        export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库的绝对存储路径。保存之后,执行 source .bashrc 指令(此方式只对当前登录用户有效)

  • GCC找不到库文件怎么办

    • 找不到静态链接库

      # 1、第一种写法
      gcc -static main.c libmymath.a -o main
      
      # 2、第二种写法
      gcc -static main.c -lmymath -o main
      

      当以第一种写法完成链接操作时,GCC编译器只会在当前目录中,查找 libmymath.a 静态链接库;反之,如果使用 -l 选项(第二种写法)指明了要查找的静态库的文件名,则GCC编译器会按照如下顺序,依次到指定目录中查找所需的库文件:

      • 如果 gcc 指令使用了 -L 选项指定了查找路径,则GCC编译器会优先选择去该路径下查找所需要的库文件;
      • 再到 Linux 系统中 LIBRARY_PATH 环境变量指定的路径中搜索需要的库文件;
      • 最后再到GCC编译器默认的搜索路径(比如 /lib/lib64/usr/lib/usr/lib64/usr/local/lib/usr/local/lib64)中查找

      注意:

      如果读者使用第一种方法完成链接操作,但GCC编译器提示找不到所需库文件,表明所用库文件并未存储在当前路径下,解决方案就是手动找到库文件并将其移至当前路径,然后重新执行链接操作

      反之,如果读者使用的是第二种方法,也遇到了GCC编译器提示未找到所需库文件,表明库文件的存储路径不对,解决方案有以下3种:

      • 手动找到该库文件,并在 gcc指令中 用 -L 选项明确指明其存储路径。比如 libmymath.a 静态库文件存储在 /usr目录下,则完成链接操作的 gcc指令为:

        gcc -static main.c -L /usr -lmymath -o main
        
      • 将库文件的存储路径添加到 LIBRARY_PATH 环境变量中,在最后一行添加命令export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,xxx表示库文件的存储路径

      • 将库文件移动到GCC编译器默认的搜索路径中

    • 找不到动态链接库

      运行由动态链接库生成的可执行文件时,必须确保程序在运行时,可以找到这个动态链接库,常用的解决方案有:

      • 将链接库文件移动到标准库目录下

        比如:/usr/lib/usr/lib64/lib/lib64

      • 在终端输入 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效)

      • 修改 ~/.bashrc~/.bash_profile 文件,即在文件的最后一行添加

        export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库的绝对存储路径。保存之后,执行 source .bashrc 指令(此方式只对当前登录用户有效)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值