天天看點

在linux下編寫動态連結庫的步驟

類似 Windows 系統中的動态連結庫, Linux 中也有相應的共享庫用以支援代碼的複用。 Windows 中為 *.dll ,而 Linux 中為 *.so ,我來詳細的告訴你如何在 linux 下編寫動态庫 , 以及如何使用它 .

在 linux 下編寫動态連結庫的步驟 :

1.      編寫庫的頭檔案和源檔案 .

2.      把所有涉及到的源檔案用如下方式編譯 為目标檔案 :

g++/gcc -g -c -fPIC -o library1.o library1.cpp

g++/gcc -g -c -fPIC -o library2.o library2.cpp

      ......

......

(注釋: -fPIC 指通過這個選項來生成與位置無關的代 碼,可以在任何位址被連接配接和裝載, -c 指隻編譯而不連接配接原程式)

3.      把所有的目标檔案連結為動态庫 :

g++/gcc -g -shared -Wl,-soname,lib***.so -o lib***.so.1.0.0 library1.o library2.o ....  -lc

    (注釋: -lc 選項,表示使用 c 語言庫,一般都要用到)

4.      建立一個庫名連結

ln -s lib***.so.1.0.0 lib***.so

現在你就可以引用庫了 . 下面我分别給出簡單例子告訴你如何動态和靜态使用動态庫 :

假如你的應用程式源代碼叫 testlib.cpp

采用 / 如下方式編譯 :

      g++ -g -o testlib testlib.cpp -ldl

    (注釋: -ldl 選項,表示生成的對象子產品需要使用共享 庫)

這個例子告訴你如何動态的調用 .so 庫

testlib.cpp

#include <dlfcn.h>

#include <iostream.h>

#include ...

int main()

{

       void *handle=NULL;

       //define a pointer which will point to the function in the lib you want to use.

       YourFuntionType (*pFunc)(YourFunctionPerameterList........);

       //open the lib you want to use.

       handle=dlopen("/../../../yourlib.so",RTLD_LAZY);

       if(handle==NULL)

       {

              cout<<"failed loading library!"<<endl;

              return -1;

       }

       dlerror();

       //try to load the function in lib

       pFunc=(YourFuntionType(*)(YourFunctionPerameterList))dlsym(handle,"YourFuntionName");

       if(dlerror()!=NULL)

       {

              cout<<"Loading function in lib error!"<<endl;

              return -1;

       }

       //now you can use the funtion like this

       (*pFunc)(YourFuntionPerameterList);

       return 0;

}  

(注釋: dlopen()

              第一個參 數:指定共享庫的名稱,将會在下面位置查找指定的共享庫。

-環境變量 LD_LIBRARY_PATH 列出的用分号間隔的所有目錄。

-檔案 /etc/ld.so.cache 中找到的庫的清單,用 ldconfig 維護。

-目錄 usr/lib 。

-目錄 /lib 。

-目前目 錄。(這裡就是這種情況)

第二個參數: 指定如何打開共享庫。

- RTLD_NOW :将共享庫中的所有函數加載到記憶體

- RTLD_LAZY :             會推後共享庫中的函數的加載操作,直到調用 dlsym() 時方加載某函數

dlsym()

          調用 dlsym 時,利用 dlopen() 傳回的共享庫的 phandle 以及函數名稱作為參數,傳回要加載函數 的入口位址。

       dlerror()

    該函數用于檢查調用共享庫的相關函數出現的錯誤。

特别需要注意的幾點問題 :

1.      當你想用 c++ 寫動态庫的時候 , 記住千萬别忘了在頭檔案裡面加上如下内容 , 否則生成的庫在動态調用的時候會出問題 !!!!!!!

  #ifdef __cplusplus

       extern "C" {

#endif

....

....

    #ifdef __cplusplus

}

#endif 

2.      當你的庫中包括與 omniORB3 相關的東西的時候 , 一定要在 makefile 中加上 -D__x86__ -D__OSVERSION=4

/ 這個例子告訴你如何靜态調用 .so 庫

首先你得確定你的應用程式能夠找到你的 .so 庫 , 這可以有幾種方法來實作 .

方法一 :

1. 你可以把 YourLib.so.1.0.0 和 YourLib.so 放到 /usr/lib 中 , 然後執行指令 :ldconfig, 這樣你就可以在你的應用程式中直接調用你庫中的函數了 , 當然你 得把庫的頭檔案包含到你的應用程式中

2. 編譯你的應用程式

g++/gcc -g -o yourapp yourapp.cpp –lYourLib

方法二 :

1. 你也可以采用在系統中設定環境變量的辦法來實作 .  在 root 目錄下 :

vi .bash_profile

然後添加 LD_LIBRARY=/../YourDirIncludingYourLib

然後注消一次 , 環境變量就生效了 , 這樣你就可以在你的應用程式中直接調用庫中的函數了 , 同樣你得有頭檔案 .

2. 編譯你的應用程式

g++/gcc -g -o yourapp yourapp.cpp –lYourLib

方法三 :

你可以直接采用在編譯連結的時候告訴系統你的庫在什麼地方

       g++/gcc -g -o yourapp yourapp.cpp -L/YourDirIncludingYourLib –lYourLib

/

假如你的庫中有個函數 :int eat(.....)

那麼采用如下方式調用它

yourapp.cpp

#include "YourLib.h"

int main()

{

       eat();

return 0;

}

是不是很 easy? 對了在靜态調用的時候好像不存在上面的 " 注意 1" 的問題 , 不過鑒于保險起見 , 最好還是按照标準的方式寫 c++ 頭檔案吧 , 這絕對是個好習慣 .

面 通過一個簡單的例子開始介紹Linux标準對象。

我們的标準對象檔案含有一個函數,不需要聲明export導出符号,隻需要編譯器設定即可。 如下:

設建立一個tools.h檔案以及tools.c檔案

#include "stdio.h"

#include "stdlib.h"

void draw();

void write();

void sign();

void show();

#include "tools.h"

void draw()

{

    printf("draw some graphics./n");

}

void write()

{

    printf("write some characters./n");

}

void sign()

{

    printf("sign your name./n");

}

void show()

{

    printf("A picture by xufeng./n");

    draw();

    write();

    printf("A picture is finished./n");

}

按照如下編譯:

$ gcc -fPIC -shared -o libmytools.so tools.c

執行生成一個libmytools.so檔案,按照Linux标準對象的命名慣例,應該在庫名稱之前加上"lib"字首, 盡管不是必須的。編譯開關-fPIC代表函數符号可以重定向,-shared代表編譯結果是一個标準對象。

不同于Win32DLL,Linux标準對象中的所有函數都是直接導出的,都可以被調用程式 所通路。下面我們編寫調用程式:

#include "tools.h"

main()

{

    show();

    printf("success!/n");

}

按照如下gcc編譯:

$ gcc -o test test.c ./libmytools.so

編譯生成test可執行檔案。如上編譯條件的最後一條需要是所調用的标準對象檔案名,注意必 須含有路徑。如果隻是使用libmyso.so,則必須確定這個檔案在可通路的PATH下面。本例所使用的檔案名"./libmytools.so"是當 前路徑下的,使用了相對路徑。

繼續閱讀