c++库文件头文件链接原理(全)

本文详细介绍了程序运行库文件的链接原理,包括静态库和动态库的区别、库和头文件的关系、库命名规范、可执行文件依赖查看、g++编译时的库搜索路径以及动态库升级问题。静态库在编译时合并到可执行文件,增加体积但方便移植;动态库在运行时加载,减少体积但需管理动态链接路径。动态库搜索路径涉及环境变量和配置文件,升级时需谨慎操作。头文件搜索顺序包括当前目录、指定目录、环境变量及内定目录。
摘要由CSDN通过智能技术生成

关于程序运行库文件链接原理

库和头文件的关系

平时我们写程序都必须 include 很多头文件,因为可以避免重复造轮子,软件大厦可不是单靠一个人就能完成的。但是你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了!

库有两种,一种是 静态链接库,一种是 动态链接库,不管是哪一种库,要使用它们,都要在程序中包含相应的 include 头文件。我们先来回顾一下程序编译的过程。如下图:

img

  • 静态库
   静态库的代码在编译过程中已经被载入可执行程序,因此生成的可执行程序体积较大。静态用.a为后缀,  例如: libhello.a
  • 动态库
   共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此生成的可执行程序代码体积较小。
  • 静态链接
什么是静态链接呢?即在链接阶段,将源文件中用到的库函数与汇编生成的目标文件.o合并生成可执行文件。该可执行文件可能会比较大。这种链接方式的好处是:方便程序移植,因为可执行程序与库函数再无关系,放在如何环境当中都可以执行。

缺点是:文件太大,一个全静态方式生成的简单print文件都有857K。而动态链接生成的一样的可执行文件却只要8.4K
  • 动态链接

我们知道静态链接的话,文件会很大,往往实现很小的一个功能就需要占用很大的空间,而且每次库文件升级的话,都要重新编译源文件,很不方便。具体下面如下:

img

对于静态编译的程序1和程序2,都应用库staticMath。在内存中就又两份相同的staticMath目标文件,很浪费空间,一旦程序数量过多就很可能会内存不足。

这么大的内存才只能运行这几个程序,实在不甘心。

这样就又了动态库发挥威力的地方了。我们来看看动态链接的结果:

img

库命名规范

在 linux 下,库文件一般放在/usr/lib和/lib下, 
静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号

查看可执行文件依赖

ldd查看程序依赖的.so文件

例如 # ldd /bin/lnlibc.so.6 
        => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 
        => /lib/ld- linux.so.2 (0×40000000) 
   可以看到 ln 命令依赖于 libc 库和 ld-linux 库 

使用nm工具,查看静态库和动态库中有那些函数名;

  (T类表示函数是当前库中定义的,U类表示函数是被调用的,在其它库中定义的,W类是当前库中定义,被其它库中的函数覆盖)。
  有时候可能需要查看一个库中到底有哪些函数,nm工具可以打印出库中的涉及到的所有符号,这里的库既可以是静态的也可以是动态的。

g++

Linux下进行程序设计时,关于库的使用:
一、gcc/g++命令中关于库的参数:
    -shared: 该选项指定生成动态连接库;
    -fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
    -L:指定链接库的路径,-L. 表示要连接的库在当前目录中
    -ltest:指定链接库的名称为test,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
    -Wl,-rpath: 记录以来so文件的路径信息。
    LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
     当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,
     不过如果没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了。 
调用动态库的时候,有几个问题会经常碰到:
    1、有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“

静态库搜索顺序

二、静态库链接时搜索路径的顺序:

    1. ld会去找gcc/g++命令中的参数-L;
    1. 再找gcc的环境变量LIBRARY_PATH,它指定程序静态链接库文件搜索路径;
      export LIBRARY_PATH=$LIBRARY_PATH:data/home/billchen/lib
    1. 再找默认库目录 /lib /usr/lib /usr/local/lib,这是当初compile gcc时写在程序内的。

动态库搜索路径

三、动态链接时、执行时搜索路径顺序:

  • 1.编译目标代码时指定的动态库搜索路径;
    1. 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib
    1. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
    1. 默认的动态库搜索路径/lib;
    1. 默认的动态库搜索路径/usr/lib。

环境变量

 LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
 LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径 

动态库升级问题:

   在动态链接库升级时,
   不能使用cp newlib.so oldlib.so,这样有可能会使程序core掉;
   而应该使用:
   rm oldlib.so 然后 cp newlib.so oldlib.so
   或者
    mv oldlib.so oldlib.so_bak 然后 cp newlib.so oldlib.so

参考链接

参考链接

头文件搜索顺序

搜索顺序

①先搜索当前目录 ②然后搜索*-I*指定的目录 ③再搜索*gcc*的环境变量*CPLUS_INCLUDE_PATH*(*C*程序使用的是*C_INCLUDE_PATH*) ④最后搜索*gcc*的内定目录 /usr/include /usr/local/include /usr/lib/gcc/x86_64-redhat-Linux/4.1.1/include
  • ①先搜索当前目录
  • ②然后搜索*-I*指定的目录
  • ③再搜索*gcc*的环境变量*CPLUS_INCLUDE_PATH*C程序使用的是*C_INCLUDE_PATH*
  • ④最后搜索gcc的内定目录
/usr/include

/usr/local/include

/usr/lib/gcc/x86_64-redhat-Linux/4.1.1/include

参考

编译原理是计算机科学中的一门重要课程,主要研究的是将高级语言编写的程序转化为计算机能够理解和执行的机器语言的过程。而C/C++是一种广泛应用的高级编程语言,其编译原理与其他编程语言相似。 C/C++的编译原理包括了多个步骤。首先,预处理器对源代码进行处理,包括宏展开、头文件包含以及条件编译等。接下来,编译器将转化预处理后的代码为汇编代码。然后,汇编器将汇编代码转化为可重定位的机器代码。最后,链接器将可重定位的机器码和文件等结合,生成最终的可执行文件。 在编译过程中,编译器进行语法分析和语义分析。语法分析主要是通过词法分析、语法分析和语法制导翻译等步骤,将源代码转化为语法树。语义分析是对语法树进行分析,检查语法的正确性,并进行类型检查等。 在编译过程中,还进行优化。优化主要分为前端优化和后端优化。前端优化是在源代码转化为中间表示形式之前进行的优化,包括常量折叠、公共子表达式删除等。后端优化是在中间表示形式转化为目标代码之前进行的优化,包括指令调度、寄存器分配等。 总的来说,C/C++的编译原理是一个复杂的过程,涉及到词法分析、语法分析、语义分析、优化等多个步骤。通过这一过程,将高级语言编写的程序转化为计算机能够执行的机器语言,从而实现程序的正确执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值