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

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

文章目录

  • 关于程序运行库文件链接原理
    • 库和头文件的关系
    • 库命名规范
    • 查看可执行文件依赖
    • g++
    • 静态库搜索顺序
    • 动态库搜索路径
    • 环境变量
    • 动态库升级问题:
    • 头文件搜索顺序

库和头文件的关系

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

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

c++库文件头文件链接原理(全)_第1张图片

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

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

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

c++库文件头文件链接原理(全)_第2张图片

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

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

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

c++库文件头文件链接原理(全)_第3张图片

库命名规范

在 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++)