linux下库的介绍与使用

1. linux中的库

       库用于将相似函数打包在一个单元中。然后这些单元就可为其他开发人员所共享,并因此有了模块化编程这种说法。在linux下常见的库文件,就是*.so文件。Linux中绝大多数.so文件都存放在/lib、/usr/lib/(见Linux目录结构),对于64位和32位共存的系统,32位的动态库可能会放在/lib32.


2.动态库和静态库

        Linux支持两种类型的库,每一种库都有各自的优缺点。静态库是在编译阶段随用户程序一块进行编译。动态库则不同,它是在加载应用程序时被加载的,而且它与应用程序是在运行时绑定的。

        (1)静态链接——可执行程序包含了其所需的全部库函数;所有库函数都连接到程序中。 这类程序是完整的,其运行不需要外部库的支持。 静态链接程序的优点之一是其安装之前不需要做环境准备工作 。
        (2)动态链接——可执行程序要小得多;这类程序运行时需要外部共享 函数库的支持,因此好像并不完整。除了程序体小之外,动态链接允许程序包指定必须的库,而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库,这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因,当前多数程序采用动态链接技术。


       在linux中的库有静态库和动态库两种,其中动态库又分为动态链接库和动态加载库两种。

 

       


3.动态链接库和动态加载库

        GNU/Linux中共享库的使用主要有两种方式,一种方式和.a的静态库类似由编译器来控制,其实质和二进制程序一样都是由系统中的载入器(ld-linux.so)载入;另一种是写在代码中,由我们自己的代码来控制.

        (1)动态链接库

          您可以动态地将程序和共享库链接并让 Linux 在执行时加载库(如果它已经在内存中了,则无需再加载)。

        (2)动态加载库

         使用动态加载的过程,这样程序可以有选择地调用库中的函数。使用动态加载过程,程序可以先加载一个特定的库(已加载则不必),然后调用该库中的某一特定函数。这是构建支持插件的应用程序的一个普遍的方法。这种方法需要使用linux提供的动态加载DL API来控制加载库以及使用库中的函数。DL提供的API如下表所示:

表 1. Dl API
函数 描述
dlopen 使对象文件可被程序访问
dlsym 获取执行了 dlopen 函数的对象文件中的符号的地址
dlerror 返回上一次出现错误的字符串错误
dlclose 关闭目标文件
如下是使用DL API的例程:

#include <stdio.h>
#include <dlfcn.h>
#include <string.h>

#define MAX_STRING      80


void invoke_method( char *lib, char *method, float argument )
{
  void *dl_handle;
  float (*func)(float);
  char *error;

  /* Open the shared object */
  dl_handle = dlopen( lib, RTLD_LAZY );
  if (!dl_handle) {
    printf( "!!! %s\n", dlerror() );
    return;
  }

  /* Resolve the symbol (method) from the object */
  func = dlsym( dl_handle, method );
  error = dlerror();
  if (error != NULL) {
    printf( "!!! %s\n", error );
    return;
  }

  /* Call the resolved method and print the result */
  printf("  %f\n", (*func)(argument) );

  /* Close the object */
  dlclose( dl_handle );

  return;
}


int main( int argc, char *argv[] )
{
  char line[MAX_STRING+1];
  char lib[MAX_STRING+1];
  char method[MAX_STRING+1];
  float argument;

  while (1) {

    printf("> ");

    line[0]=0;
    fgets( line, MAX_STRING, stdin);

    if (!strncmp(line, "bye", 3)) break;

    sscanf( line, "%s %s %f", lib, method, &argument);

    invoke_method( lib, method, argument );

  }

}

4.静态链接库的定义和使用方式

(1)静态链接库的定义

通过编译的预处理、编译阶段生成的目标文件就可以作为静态链接库。

(2)静态链接库的使用

有两种方式,一种是g++ -o main main.cpp ./libullib.a,直接将libullib.a库链接到二进制程序main中;另一种是g++ -o main main.cpp -L./ -lullib,这种和动态链接库的使用方式一样,但是生成静态链接库和动态链接库的方式是不一样的。


5.共享库的定义和使用方式,

(1)共享库的定义

生成共享库和生成静态库类似,只是加上了 -shared 和 -fPIC,将输出命名改为.so,这样生成的执行程序即为共享库。

g++ -shared -fPIC -o libx.so libx.cpp

(2)共享库的使用

两种方式,一种是g++ -o main main.cpp -L./ -lx,通过gcc/g++的-l和-L引入。一种是程序中显示控制。


6.linux中库的查找顺序

(1)Linux gcc编译以及链接时对依赖的库的查找顺序

GCC编译、链接生成可执行文件时,对依赖库的搜索路径顺序如下(注意不会递归性地在其子目录下搜索):

1.gcc编译、链接命令中的-L选项
2.gcc的环境变量的LIBRARY_PATH(多个路径用冒号分割)
3.gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib
(2)执行二进制文件时的对依赖的共享库的查找顺序

链接生成二进制可执行文件后,在运行程序加载动态库文件时,搜索的路径顺序如下:

1.编译目标代码时指定的动态库搜索路径:用选项-Wl,rpath和include指定的动态库的搜索路径,比如gcc -Wl,-rpath,include -L. -ldltest hello.c,在执行文件时会搜索路径`./include`
2.环境变量LD_LIBRARY_PATH(多个路径用冒号分割)
3.由ldconfig工具构建的/etc/ld.so.cache缓存文件中查找
4.gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib等


7.共享库的加载

        对于依赖共享库的可执行文件在真正执行前,实际上它的很多外部符号还处于无效状态,还未与实际的so文件联系起来,因此还有一个动态链接过程。操作系统会首先加载动态链接器ld.so(/lib/ld-linux.so.2),加载完这个so后,系统就会把控制权交给它,然后它会进行一些初始化操作,根据当前环境参数对可执行文件进行动态链接工作。动态链接器会寻找所需要的.so文件并进行装载,然后进行符号查找及重定位。如果找不到所需要的符号定义就会产生“undefined symbol”错误。


8.库文件生成,修改工具ar

      ar命令可以用来创建、修改库,也可以从库中提出单个模块。库是一单独的文件,里面包含了按照特定的结构组织起来的其它的一些文件(称做此库文件的member)。原始文件的内容、模式、时间戳、属主、组等属性都保留在库文件中。

      ar工具的详细使用可以参见http://blog.csdn.net/xuhongning/article/details/6365200


学习资料来源于:

http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/

http://blog.csdn.net/xuhongning/article/details/6365200

https://typecodes.com/cseries/gcclderrlibrarypath.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值