Linux手机DIY.库文件专题.知识准备

 Linux手机DIY.库文件专题.知识准备

草木瓜转抄 于 2006-11-9


一、序

  软件移植过程中,Linux操作系统的库文件着实令人头疼,这方面资料
也比较少。通过一段时间搜索查询推敲,写点总结吧,也算是有点成果。不过
这篇内容大多都是抄的,这里对原创作者表示深深的敬意~

二、重要提示

    为了方便更好的理解本文,提供下面链结。
    全系列的文章地址,手机应用开发专栏:http://blog.csdn.net/liwei_cmg
    相关的重要成果的下载地址:http://play.younet.com/view.php?tid=24045

三、Linux的库文件格式

  [以下内容整理自《创建和使用库》一文,作者不详]

  C语言中有一些函数不需要进行编译,也可以在多个文件中使用。
  一般来说,有此函数会执行一定的标准任务,如数据库输入/输出操作或
屏幕控制等。可以事先对这些函数进行编译,然后将它们放置在一些特殊的目
标代码文件中,这些目标代码文件就称为库。
  库文件中的函数可以通过连接程序与应用程序进行连接。这样就不必在每
次开发程序时都对这些通用的函数进行编译了。

  不同类型的应用程序会使用不同的函数库。例如:libdbm库中组包含了对
数据库文件进行访问的dbm函数,需要对数据库进行操作的程序就会与该库进
行连接。数学应用程序使用数学库libm,X-Windows应用程序使用Xlib库,
libX11。另外,所有的程序都将使用标准的C函数库。libc,该库中包含了内
存管理或输入输出操作的基本函数,这些库都存放在/usr/lib这些系统公用
的目录中,系统中的任何用户都可以利用这些库。当然用户也可以建立自己
专用的库函数,供自己或其它指定的人员使用。


  库可以有三种使用的形式:静态、共享和动态。静态库的代码在编译时就
已连接到开发人员开发的应用程序中,而共享库只是在程序开始运行时才载入,
在编译时,只是简单地指定需要使用的库函数。动态库则是共享库的另一种变
化形式。动态库也是在程序运行时载入,但与共享库不同的是,使用的库函数
不是在程序运行开始,而是在程序中的语句需要使用该函数时才载入。动态库
可以在程序运行期间释放动态库所占用的内存,腾出空间供其它程序使用。由
于共享库和动态库并没有在程序中包括库函数的内容,只是包含了对库函数的
引用,因此代码的规模比较小。

  已经开发的大多数库都采取共享库的方式。ELF格式的可执行文件使得共享
库能够比较容易地实现,当然使用旧的a.out模式也可以实现库的共享。Linux
系统中目前可执行文件的标准格式为ELF格式。

  GNU库的使用必须遵守Library GNU Public License(LGPL许可协议)。该
协议与GNU许可协议略有不同,开发人员可以免费使用GNU库进行软件开发,但
必须保证向用户提供所用的库函数的源代码。

  系统中可用的库都存放在/usr/lib和/lib目录中。库文件名由前缀lib和
库名以及后缀组成。根据库的类型不同,后缀名也不一样。共享库的后缀名
由.so和版本号组成,静态库的后缀名为.a。采用旧的a.out格式的共享库的
后缀名为.sa。

  使用gcc编译器就可以将库与自己开发的程序连接起来,例如:libc.so.5
中包含了标准的输入输出函数,当连接程序进行目标代码连接时会自动搜索该
程序并将其连接到生成的可执行文件中。标准的输入输出库中包含了许多基本
的输入输出函数,如printf函数等。也可以连接其它的一些系统函数库,如数
学库等,但与libc.so.5不同,大部分其它的系统库需要在命令行中显式指定
所用的库名。

    在/usr/lib和/lib目录中可以找到绝大多数的共享库。连接时将首先搜索
这两个目录。有一些库也可能存放在特定的目录中,在/etc/ld.conf配置文件
中给出了这些目录的列表。连接程序也会对列出的这些目录进行搜索。在默认
情况下,Linux将首先搜索指定库的共享版本,如果找不到,才会去搜索静态
版本。在对共享库进行更新或安装新库后,必须运行ldconfig命令更新
/etc/ld.conf文件中相应的项(如果使用RPM进行安装,一般会自动进行更新,
不过也不能保证这一点)。

    在gcc编译器中引用可搜索到的目录中的库文件时,需要使用-l选项和库
名。在gcc命令行上输入-lm可以在程序中连接标准算术库,-l将首先使用
libname.so进行搜索,这里是libm.so。下面的例子将使用算术库创建bookrecs
程序,请注意这里的-lm选项。
$ gcc main.c io.c -o bookrecs -lm

    系统中还有一些其它可用的库,常用的是libncurses.a库,包含了一些简
单的鼠标移动例程。在命令行中使用-lncurses选项引用libncurses.so库。下
面的例子同时调用了数学和光标库。
$ gcc mian.c io.c -o bookrecs -lm -lncurses

    在引用其它目录中的库时,需要使用-ldir选项指定该目录。该选项指定
了搜索库函数时其它路径。在下面的例子中,用户在连接时使用了mydir目录
中的myio.so库文件。
$ gcc main.c -o bookrecs -lmydir -lmyio

  Linux下文件的类型是不依赖于后缀名的,但一般来讲:
  .o  为目标文件,类似于windows中的.obj文件
   .so 为共享库文件,用于动态连接,类似于dll文件
  .a  为静态库,是多个.o文件合在一起,用于静态连接
   .la 为libtool自动生成的一些共享库,可用vi编辑查看,主要记录了一
些配置信息。
   
四、创建和使用Linux库文件

  [以下内容整理自《Linux静态/动态链接库的创建和使用》一文,
  http://blog.csdn.net/hcj2002/]
  
  和Windows系统一样Linux也有静态/动态链接库,下面介绍创建和使用
方法:
  
  假设有下面几个文件:
  头文件String.h,声明相关函数原形,内容如下:
  Strlen.c:函数Strlen的实现,获取给定字符串的长度,内容如下:
  Strlnen.c:函数StrNlen的实现,获取给定字符串的长度,如果输入字
符串的长度大于指定的最大长度,则返回最大长度,否者返回字符串的实际
长度,内容如下:
  生成静态库:
  
  利用GCC生成对应目标文件:
  gcc –c Strlen.c Strnlen.c
  如果对应的文件没有错误,gcc会对文件进行编译生成Strlen.o和Strnlen.o
两个目标文件(相当于windows下的obj文件)。然后用ar创建一个名字为libstr.a
的库文件,并把Strlen.o 和Strnlen.o的内容插入到对应的库文件中。相关命
令如下:
  ar –rc libstr.a Strlen.o Strnlen.o
  命令执行成功以后,对应的静态库libstr.a已经成功生成。
  
  /***********************************
  Filename : String.h
  Description :
  Author   : HCJ
  Date     : 2006-5-7
  ************************************/
  
  
  int Strlen(char *pStr);
  int StrNlen(char *pStr, unsigned long ulMaxLen);
  
  
  
  /**************************************
  Filename    : get string length
  Description  :
  Author      : HCJ
  Date        : 2006/5/7
  **************************************/
  #include<stdio.h>
  #include<assert.h>
  
  int Strlen(char *pStr)
  {
      unsigned long ulLength;
      assert(NULL != pStr);
  
      ulLength = 0;
      while(*pStr++)
      {
          ulLength++;
      }
  
      return ulLength;
  }
  
  
  **********************************************
  Fileneme: mystrnlen.c
  Description: get input string length,if string large
               max length input return max length,
               else real length
  Author: HCJ
  Date  : 2006-5-7
  **********************************************/
  
  #include<stdio.h>
  #include<assert.h>
  
  int StrNlen(char *pStr, unsigned long ulMaxLen)
  {
      unsigned long ulLength;
  
      assert(NULL != pStr);
  
      if(ulMaxLen <= 0)
      {
          printf("Wrong Max Length!/n");
          return -1;
      }
  
      ulLength = 0;
      while(*pStr++ &&  ulLength < ulMaxLen)
      {
          ulLength++;
      }
  
      return ulLength;
  }

  
  生成动态链接库:
   gcc  -fpic -shared -o libstr.so  Strlen.c Strnlen.c
  -fpic 使输出的对象模块是按照可重定位地址方式生成的。
  -shared指定把对应的源文件生成对应的动态链接库文件libstr.so
文件。
  
  对应的链接库已经生成,下面看一下如何使用对应的链接库。
  静态库的使用:
  假设有下面的文件要使用对应的的静态库:
  编译生成对应的目标文件:
  gcc -c -I/home/hcj/xxxxxxxx main.c
  生成可执行文件:
  gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.a
  其中-I/home/hcj/xxxxxxxx和-L/home/hcj/xxxxxxxx是通过-I和-L指
定对应的头文件和库文件的路径。libstr.a是对应的静态库的名称。这样
对应的静态库已经编译到对应的可执行程序中。执行对应的可执行文件便
可以对应得函数调用的结果。
  
  /*****************************************
  FileName: main.c
  Description: test static/dynamic library
  Author: HCJ
  Date  : 2005-5-7
  ******************************************/
  #include<stdio.h>
  #include <String.h>   //静态库对应函数的头文件
  
  int main(int argc, char* argv[])
  {
      char str[] = {"hello world"};
      unsigned long ulLength = 0;
  
      printf("The string is : %s/n", str);
      ulLength = Strlen(str);
      printf("The string length is : %d(use Strlen)/n", ulLength);
      ulLength = StrNlen(str, 10);
      printf("The string length is : %d(use StrNlen)/n", ulLength);
  
      return 0;
  }
  
  动态库的分为隐式调用和显式调用两种调用方法:
  隐式调用的使用使用方法和静态库的调用差不多,具体方法如下:
  gcc -c -I/home/hcj/xxxxxxxx main.c
  gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.so  //这里是*.so
  
  在这种调用方式中,需要维护动态链接库的配置文件/etc/ld.so.conf
来让动态链接库为系统所使用,通常将动态链接库所在目录名追加到动态链
接库配置文件中。否则在执行相关的可执行文件的时候就会出现载入动态链
接库失败的现象。在编译所引用的动态库时,可以在gcc采用 –l或-L选项或
直接引用所需的动态链接库方式进行编译。在Linux里面,可以采用ldd命令
来检查程序依赖共享库。
  
  显式调用:
  
  /*****************************************
  FileName: main2.c
  Description: test static/dynamic library
  Author: HCJ
  Date  : 2005-5-7
  ******************************************/
  #include<stdio.h>
  #include<dlfcn.h>
  
  int main(int argc, char* argv[])
  {
      //define function pointor
      int (*pStrlenFun)(char* pStr);     //声明对应的函数的函数指针
      int (*pStrnlenFun)(char* pStr, int ulMaxLen);
  
      char str[] = {"hello world"};
      unsigned long ulLength = 0;
  
      void *pdlHandle;
      char *pszErr;
  
      pdlHandle = dlopen("./libstr.so", RTLD_LAZY);  //加载链接库/libstr.so
      if(!pdlHandle)
      {
          printf("Failed load library/n");
      }
      pszErr = dlerror();
      if(pszErr != NULL)
      {
          printf("%s/n", pszErr);
          return 0;
      }
  
      //get function from lib
      pStrlenFun = dlsym(pdlHandle, "Strlen"); //获取函数的地址
      pszErr = dlerror();
      if(pszErr != NULL)
      {
          printf("%s/n", pszErr);
          return 0;
      }
  
      pStrnlenFun = dlsym(pdlHandle, "StrNlen");
      pszErr = dlerror();
      if(pszErr != NULL)
      {
          printf("%s/n", pszErr);
          return 0;
      }
  
      printf("The string is : %s/n", str);
      ulLength = pStrlenFun(str);   //调用相关的函数
      printf("The string length is : %d(use Strlen)/n", ulLength);
      ulLength = pStrnlenFun(str, 10);
      printf("The string length is : %d(use StrNlen)/n", ulLength);
   dlclose(pdlHandle);
      return 0;
  }
  
  gcc -o mian2 -ldl main2.c
  用gcc编译对应的源文件生成可执行文件,-ldl选项,表示生成的对象模
块需要使用共享库。执行对应得文件同样可以得到正确的结果。
  相关函数的说明如下:
  (1)dlopen()
  第一个参数:指定共享库的名称,将会在下面位置查找指定的共享库。
  -环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录。
  -文件/etc/ld.so.cache中找到的库的列表,用ldconfig维护。
  -目录usr/lib。
  -目录/lib。
  -当前目录。
  第二个参数:指定如何打开共享库。
  -RTLD_NOW:将共享库中的所有函数加载到内存
  -RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时
方加载某函数
  (2)dlsym()
  调用dlsym时,利用dlopen()返回的共享库的phandle以及函数名称作为
参数,返回要加载函数的入口地址。
  (3)dlerror()
  该函数用于检查调用共享库的相关函数出现的错误。
  这样我们就用简单的例子说明了在Linux下静态/动态库的创建和使用。
  

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值