Linux下g++编译c++程序过程说明


参考:https://blog.csdn.net/Three_dog/article/details/103688043

事前准备

在这里插入图片描述
文件夹中创建main.cpp,hellow.cpp,hellow.h文件,文件中的代码如下:

//hellow.h
#ifndef _HELLOW_H_ 
#define _HELLOW_H_ 

class Hellow
{
public:
    Hellow();
    void hi();
    ~Hellow();
};
#endif  //Hellow

//hellow.cpp
#include "hellow.h"
#include <iostream>
using namespace std;

Hellow::Hellow()
{

}

void Hellow::hi()
{
    cout << "hello" << endl;
}

Hellow::~Hellow()
{

}

#include "hellow.h"

using namespace std;

int main()

{

  Hellow h;
  h.hi();

  return 0;

}

一.g++ 编译代码的过程示例

g++编译器的主要工作流程:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 汇编程序 (assembler) → 目标代码 (object code) → 链接器 (Linker) → 可执行程序 (executables)。

  1. 可以使用g++ -E 让g++ 在预处理之后停止编译过程,生成 *.ii(.c文件生成的是*.i) 文件。因为上面写的main.cpp中没有任何预编译指令,所以预编译生成与源文件几乎没有差别。这里预编译一下hellow.cppmain.cpp文件

    g++ -E hellow.cpp hellow.h -o hellow.ii
    g++ -E main.cpp -o main.ii
    

    在这里插入图片描述
    在这里插入图片描述
    编译完成后,#include引入的内容 被全部复制进预编译文件中,除此之外,如果文件中有使用宏定义也会被替换处理。预编译过程最主要的工作,就是宏命令的替换,#include命令的工作就是单纯的导入,这里其实并不限制导入的类型,甚至可以导入.cpp、.txt等等。

  2. g++ 编译阶段:C++ 语法错误的检查,就是在这个阶段进行。在检查无误后,g++ 把代码翻译成汇编语言。可以使用-S 选项进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

    g++ -S main.ii -o main.s
    g++ -S hellow.ii -o hellow.s
    

    在这里插入图片描述
    在这里插入图片描述

  3. g++ 汇编阶段:生成目标代码 *.o

    g++ main.cpp -c -o main.o
    g++ hellow.cpp -c -o hellow.o
    

    在这里插入图片描述

  4. 链接生成可执行文件

    g++ main.o hellow.o -o main
    

    在这里插入图片描述

  5. run

    ./main
    

    在这里插入图片描述

二.使用g++生成静态链接库和动态链接库

生成静态链接库

使用ar命令进行“归档”(.a的实质是将文件进行打包)

ar crsv libhellow.a hellow.o 
  • r 替换归档文件中已有的文件或加入新文件 (必要)
  • c 不在必须创建库的时候给出警告
  • s 创建归档索引
  • v 输出详细信息
    在这里插入图片描述

生成动态链接库

使用g++ -shared 命令指定编译生成的是一个动态库

g++ hellow.cpp -fPIC -shared -o libhellow.so.0.1
  • -shared:告诉编译器生成一个动态链接库
  • -o:指示实际生成的动态链接库(这里是libtest.so.0.1)
  • -fPIC
    fPIC的全称是 Position Independent Code, 用于生成位置无关代码(看不懂没关系,总之加上这个参数,别的代码在引用这个库的时候才更方便,反之,稍不注意就会有各种乱七八糟的报错)。
    使用-fPIC选项生成的动态库,是位置无关的。这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。通常的方法是获取指令指针的值,加上一个偏移得到全局变量/函数的地址。
    关于PIC参数的详细解读:点此链接
    在gcc中,如果指定-shared不指定-fPIC会报错,无法生成非PIC的动态库,不过clang可以。

在这里插入图片描述
库中函数和变量的地址是相对地址,不是绝对地址,真实地址在调用动态库的程序加载时形成。
动态库的名称有别名(soname),真名(realname)和链接名(linker name)。

  • 真名是动态库的真实名称,一般总是在别名的基础上加上一个小的版本号,发布版本构成

  • 别名由一个前缀lib,然后是库的名字加上.so构成,例如:libQt5Core.5.7.1

  • 链接名,即程序链接时使用的库的名字,例如:-lQt5Core
    在动态链接库安装的时候总是复制库文件到某个目录,然后用软连接生成别名,在库文件进行更新的时候仅仅更新软连接即可。

  • 生成的库文件总是以libXXX开头,这是一个约定,因为在编译器通过-l参数寻找库时,比如-lpthread会自动去寻找libpthread.so和libpthread.a。
    如果生成的库并没有以lib开头,编译的时候仍然可以连接到,不过只能以显示加在编译命令参数里的方式链接。例如:

    g++ main.o hellow.so
    

三.静态编译与动态编译程序

静态编译程序

g++ main.o libhellow.a -o main

在这里插入图片描述

编译完成后可以运行a.out查看效果,通过ldd命令查看运行a.out所需依赖,可以看到静态编译的程序并不依赖libtest库。
在这里插入图片描述

动态编译程序

g++ main.o ./libhellow.so.0.1 -o main

在这里插入图片描述
在这里插入图片描述

四.动态链接库的添加方式

  1. 编译程序时直接指定动态链接库所在目录

    g++ main.o ./libhellow.so.0.1 -o main
    

    在这里插入图片描述

    或者

    g++ main.o /home/nflg/a/libhellow.so.0.1 -o main
    

    在这里插入图片描述

  2. 通过-L指定动态链接库所在文件夹

    g++ main.o -lhellow -L. -o main
    

    在这里插入图片描述

  3. 通过LIBRARY_PATH添加动态链接库

    LIBRARY_PATH=/home/nflg/a/ g++ main.o -lhellow -o main
    

    在这里插入图片描述

  4. 直接将动态链接库添加到、/usr/lib文件夹中
    在这里插入图片描述

五.动态链接库以及头文件搜索顺序

动态链接库

运行时库的查找顺序:

  1. 编译目标代码时指定的动态库搜索路径(-rpath);
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 默认的动态库搜索路径/lib;
  5. 默认的动态库搜索路径/usr/lib.

头文件

  1. 先搜索当前目录
  2. 然后搜索-I指定的目录
  3. 再搜索gcc的环境变量CPLUS_INCLUDE_PATH(C程序使用的是C_INCLUDE_PATH)
  4. 最后搜索gcc的内定目录
    /usr/include
    /usr/local/include
    /usr/lib/gcc/x86_64-redhat-linux/4.1.1/include
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AoDeLuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值