Linux手機DIY.庫檔案專題.知識準備

來源:互聯網
上載者:User

 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下靜態/動態庫的建立和使用。
  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.