Linux的.a、.so和.o文件 對比 window下的dll,lib,exe文件

 連續幾天終於將一個又一個問題解決了,這裏說其中一個問題linux

  描述問題:使用多線程pthread的時候,(我用的IDE,CODEBOLCKS)編譯後發現直接彈出窗口,程序尚未被Build。。巴拉巴拉,而後陷入了這個循環。提示有一句pthead_create未定義。c++

  發現:pthread要用到動態連接庫(libpthread.a)才能使用。程序員

  解決辦法:後來在setting->complies and link->link setting裏面加入了系統中這個文件的地址。windows

  詳細查了一下,.a與.so的區別,其實就是靜態連接庫與動態連接庫。有一篇博文,很詳細,附上連接:http://blog.csdn.net/nieyinyin/article/details/6890557緩存

  Linux下的.so是基於Linux下的動態連接,其功能和做用相似與windows下.dll文件。多線程

  下面是關於.so的介紹:eclipse

1、引言函數

  一般狀況下,對函數庫的連接是放在編譯時期(compile time)完成的。全部相關的對象文件(object file)與牽涉到的函數庫(library)被連接合成一個可執行文件(executable file)。程序在運行時,與函數庫再無瓜葛,由於全部須要的函數已拷貝到本身門下。因此這些函數庫被成爲靜態庫(static libaray),一般文件名爲「libxxx.a」的形式。測試


  其實,咱們也能夠把對一些庫函數的連接載入推遲到程序運行的時期(runtime)。這就是如雷貫耳的動態連接庫(dynamic link library)技術。ui

2、動態連接庫的特色與優點

  首先讓咱們來看一下,把庫函數推遲到程序運行時期載入的好處:

  1. 能夠實現進程之間的資源共享。

  什麼概念呢?就是說,某個程序的在運行中要調用某個動態連接庫函數的時候,操做系統首先會查看全部正在運行的程序,看在內存裏是否已有此庫函數的拷 貝了。若是有,則讓其共享那一個拷貝;只有沒有才連接載入。這樣的模式雖然會帶來一些「動態連接」額外的開銷,卻大大的節省了系統的內存資源。C的標準庫 就是動態連接庫,也就是說系統中全部運行的程序共享着同一個C標準庫的代碼段。

  2. 將一些程序升級變得簡單。用戶只須要升級動態連接庫,而無需從新編譯連接其餘原有的代碼就能夠完成整個程序的升級。Windows 就是一個很好的例子。

  3. 甚至能夠真正坐到連接載入徹底由程序員在程序代碼中控制。

  程序員在編寫程序的時候,能夠明確的指明何時或者什麼狀況下,連接載入哪一個動態連接庫函數。你能夠有一個至關大的軟件,但每次運行的時候,因爲 不一樣的操做需求,只有一小部分程序被載入內存。全部的函數本着「有需求才調入」的原則,因而大大節省了系統資源。好比如今的軟件一般都能打開若干種不一樣類 型的文件,這些讀寫操做一般都用動態連接庫來實現。在一次運行當中,通常只有一種類型的文件將會被打開。因此直到程序知道文件的類型之後再載入相應的讀寫 函數,而不是一開始就將全部的讀寫函數都載入,而後才發覺在整個程序中根本沒有用到它們。

3、動態連接庫的建立

  因爲動態連接庫函數的共享特性,它們不會被拷貝到可執行文件中。在編譯的時候,編譯器只會作一些函數名之類的檢查。在程序運行的時候,被調用的動態 連接庫函數被安置在內存的某個地方,全部調用它的程序將指向這個代碼段。所以,這些代碼必須實用相對地址,而不是絕對地址。在編譯的時候,咱們須要告訴編 譯器,這些對象文件是用來作動態連接庫的,因此要用地址不無關代碼(Position Independent Code (PIC))。

  對gcc編譯器,只需添加上 -fPIC 標籤,如:

  gcc -fPIC -c file1.c
  gcc -fPIC -c file2.c
  gcc -shared libxxx.so file1.o file2.o

  注意到最後一行,-shared 標籤告訴編譯器這是要創建動態連接庫。這與靜態連接庫的創建很不同,後者用的是 ar 命令。也注意到,動態連接庫的名字形式爲 「libxxx.so」 後綴名爲 「.so」

4、動態連接庫的使用

a.隱式調用 (靜態庫與此相同的方式)

  使用動態連接庫,首先須要在編譯期間讓編譯器檢查一些語法與定義。

  這與靜態庫的實用基本同樣,用的是 -Lpath 和 -lxxx 標籤。如:

  gcc file1.o file2.o -Lpath -lxxx -o program.exe

  編譯器會先在path文件夾下搜索libxxx.so文件,若是沒有找到,繼續搜索libxxx.a(靜態庫)。

  在程序運行期間,也須要告訴系統去哪裏找你的動態連接庫文件。在UNIX下是經過定義名爲 LD_LIBRARY_PATH 的環境變量來實現的。只需將path賦值給此變量便可。csh 命令爲:

  setenv LD_LIBRARY_PATH   your/full/path/to/dll

  一切安排穩當後,你能夠用 ldd 命令檢查是否鏈接正常。

  ldd program.exe

動態連接庫*.so的編譯與使用

b.顯示調用:

  這種方式更加靈活。在代碼中須要調用的地方使用 #include <dlfcn.h>這個頭文件中的如下函數來調用:

 

void  *dlopen(const char *, int); void *dlsym(void *, const char *); int dlclose(void *); char *dlerror(void);

 

在說明Linux的.a、.so和.o文件關係以前,先來看看windows下obj,lib,dll,exe的關係

 

windows下obj,lib,dll,exe的關係

    lib是和dll對應的。lib是靜態連接庫的庫文件,dll是動態連接庫的庫文件。
    所謂靜態就是link的時候把裏面須要的東西抽取出來安排到你的exe文件中,之後運行你的exe的時候再也不須要lib。
    所謂動態就是exe運行的時候依賴於dll裏面提供的功能,沒有這個dll,你的exe沒法運行。
   
    lib,dll,exe都算是最終的目標文件,是最終產物。而c/c++屬於源代碼。源代碼和最終目標文件中過渡的就是中間代碼obj,實際上之因此須要中間代碼,是你不可能一次獲得目標文件。好比說一個exe須要不少的cpp文件生成。而編譯器一次只能編譯一個cpp文件。這樣編譯器編譯好一個cpp之後會將其編譯成obj,當全部必需要的cpp都編譯成obj之後,再統一link成所須要的exe,應該說缺乏任意一個obj都會致使exe的連接失敗。
   
    1.obj裏存的是編譯後的代碼跟數據,而且有名稱,因此在鏈接時有時會出現未解決的外部符號的問題。當連成exe後便不存在名稱的概念了,只有地址。lib就是一堆obj的組合。
    2.理論上能夠鏈接obj文件來引用其餘工程(能夠認爲一個obj文件等價於編譯生成它的cpp文件,能夠引用obj來替換cpp,也能夠添加cpp來替換obj ),但實際中一般用lib來實現工程間相互引用。
    3.編譯器會默認連接一些經常使用的庫,其它的須要你本身指定。
   
lib和DLL的區別

    (1)lib是編譯時須要的,dll是運行時須要的。若是要完成源代碼的編譯,有lib就夠了。若是也使動態鏈接的程序運行起來,有dll就夠了。在開發和調試階段,固然最好都有。
    (2) 通常的動態庫程序有lib文件和dll文件。lib文件是必須在編譯期就鏈接到應用程序中的,而dll文件是運行期纔會被調用的。若是有dll文件,那麼對應的lib文件通常是一些索引信息,具體的實如今dll文件中。若是隻有lib文件,那麼這個lib文件是靜態編譯出來的,索引和實現都在其中。 靜態編譯的lib文件有好處:給用戶安裝時就不須要再掛動態庫了。但也有缺點,就是致使應用程序比較大,並且失去了動態庫的靈活性,在版本升級時,同時要發佈新的應用程序才行。
    (3)在動態庫的狀況下,有兩個文件,一個是引入庫(.LIB)文件(實際上也算是一個靜態庫,只是在連接時只能把函數在DLL的入口連接到exe中,而不像真正靜態連接庫那樣將函數體真正連接到exe中 ,經過lib進行的動態連接實際上也使用了靜態連接來實現 ),一個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件連接到所須要使用的DLL文件,庫中的函數和數據並不複製到可執行文件中,所以在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當一個或多個應用程序運行是再把程序代碼和被調用的函數代碼連接起來,從而節省了內存資源。從上面的說明能夠看出,DLL和.LIB文件必須隨應用程序一塊兒發行,不然應用程序將會產生錯誤。

DLL內的函數分爲兩種:
    (1)DLL導出函數,可供應用程序調用;
    (2)DLL內部函數,只能在DLL程序使用,應用程序沒法調用它們

建立靜態連接庫和建立動態連接庫

    VC6中建立[Win32 Dynamic-Link Library]工程即可以建立出一個空的DLL工程.

    VC6中建立[Win32 Static Library]工程即可以建立出一個空的LIB工程(靜態連接庫工程,僅生成一個lib文件).

添加lib文件的經常使用辦法有二個:
    一、把*.lib放在VC的Lib目錄中
    二、修改project setting的Link->Input中的Addtional library path,加入你的目錄dll:是可實際運行的二進制代碼,有定位代碼的!

    三、也能夠在object/library中直接寫上lib文件路徑.(這裏其實是能夠寫上任意obj文件或者lib文件的).

 

 

 

linux .o,.a,.so
        .o,是目標文件,至關於windows中的.obj文件 

  .so 爲共享庫,是shared object,用於動態鏈接的,至關於windows下的dll 

  .a爲靜態庫,是好多個.o合在一塊兒,用於靜態鏈接 

 

靜態函數庫
特色:其實是簡單的普通目標文件的集合,在程序執行前就加入到目標程序中。
優勢:能夠用之前某些程序兼容;描述簡單;容許程序員把程序link起來而不用從新編譯代碼,節省了從新編譯代碼的時間(該優點目前已不明顯);開發者能夠對源代碼保密;理論上使用ELF格式的靜態庫函數生成的代碼能夠比使用共享或動態函數庫的程序運行速度快(大概1%-5%)
生成:使用ar程序(archiver的縮寫)。ar rcs my_lib.a f1.o f2.o是把目標代碼f1.o和f2.o加入到my_lib.a這個函數庫文件中(若是my_lib.a不存在則建立)
使用:用gcc生成可執行代碼時,使用-l參數指定要加入的庫函數。也能夠用ld命令的-l和-L參數。
 
共享函數庫
    共享函數庫在可執行程序啓動的時候加載,全部程序從新運行時均可自動加載共享函數庫中的函數。.so文件感受很複雜,光是命名規則就已經看得我很暈了~整理一下,共享庫須要:soname、real name,另外編譯的時候名字也有說法。依次解釋下:
soname:必須的格式:lib+函數庫名+.so+版本號信息(可是記住,很是底層的C庫函數都不是以lib開頭命名的)。例子:/usr/lib/libreadline.so.3
real name:顧名思義是真正的名字啦,有主版本號和發行版本號。可是沒找到實例……
編譯器編譯的時候須要的函數庫的名字就是不包含版本號信息的soname,例如上面的例子把最後的.3去掉就能夠了。
位置:共享函數庫文件必須放在特定目錄,對於開放源碼來講,GNU標準建議全部的函數庫文件都放在/usr/local/lib目錄下,並且建議命令、可執行程序都放在/usr/local/bin目錄下。不過這個只是習慣啦,能夠改變,具體的位置信息能夠看/etc/ld.so.conf裏面的配置信息。固然,也能夠修改這個文件,加入本身的一些特殊的路徑要求。
建立:在網上找到了gcc方式和easyeclipse環境下兩種建立方式。
gcc方式:
    首先建立object文件,這個文件將加入經過gcc –fPIC 參數命令加入到共享函數庫裏面,標準格式:gcc -shared -Wl,-soname,your_soname -o library_name file_list library_list(說實話這個標準格式看起來好複雜,我找了個實例,可是好像和那個標準格式稍有不一樣:gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so)
在easyeclipse環境下生成.so文件:
        1.選擇新建工程,創建一個c++工程
        2.在工程類型選項裏選擇 Shared Library,而後填入工程名字PXXX點擊完成便可。
        3.編寫程序,而後編譯就會在debug或者release裏生成一個libPXXX.so文件,若是不要lib的起頭標記點擊project菜單的Properties選項,而後在彈出的界面的右邊點擊Build artifact頁面,將Output prefix選項的內容清空便可。
        4.若是是C++程序,注意在接口函數的前面加上extern "C"標記,在頭文件加上以下標記:
#ifdef   __cplusplus 
#extern   "C"{ 
#endif 
  
頭文件主體 
  
#ifdef   __cplusplus 

#endif 
     若是不加以上標記,通過編譯後,so裏的函數名並不是你編寫程序時設定的函數名,在開發環境左側的工程文件列表中點開debug項裏的PXXX.o能夠看到so文件裏的函數名都是在你設定的函數名後面加了一個__Fi標記,好比你用的設定的函數名稱是Func(), 而so裏的函數名則爲Func__Fi()或者其餘的名稱。
安裝:拷貝共享庫文件到指定的標準的目錄,而後運行ldconfig。若是沒有權限這樣作,那麼就只好經過修改環境變量來實現這些函數庫的使用了。方法再也不說了,很複雜。
查看:能夠經過運行ldd來看某個程序使用的共享函數庫。例如ldd /bin/ls。查看.so文件使用nm命令,如nm libXXX.so。(注意,nm對於靜態的函數庫和共享的函數庫都起做用)
關於覆蓋:若是想用本身的函數覆蓋某個庫中的一些函數,同時保留該庫中其餘的函數的話,能夠在/etc/ld.so.preload中加入要替換的庫(.o結尾的文件),這些preloading的庫函數將有優先加載的權利。
關於更新:每次新增長動態加載的函數庫、刪除某個函數庫或者修改某個函數庫的路徑時,都要從新運行ldconfig來更新緩存文件/etc/ld.so.cache,此文件保存已排好序的動態連接庫名字列表

(在Linux下,共享庫的加載是由/lib/ld.so完成的,ld.so加載共享庫時,會從ld.so.cache查找)

 

 

 

 

咱們一般把一些公用函數製做成函數庫,供其它程序使用。函數庫分爲靜態庫和動態庫兩
種。靜態庫在程序編譯時會被鏈接到目標代碼中,程序運行時將再也不須要該靜態庫。動態
庫在程序編譯時並不會被鏈接到目標代碼中,而是在程序運行是才被載入,所以在程序運
行時還須要動態庫存在。本文主要經過舉例來講明在Linux中如何建立靜態庫和動態庫,以
及使用它們。

在建立函數庫前,咱們先來準備舉例用的源程序,並將函數庫的源程序編譯成.o文件。


第1步:編輯獲得舉例的程序--hello.h、hello.c和main.c;

hello.c(見程序2)是函數庫的源程序,其中包含公用函數hello,該函數將在屏幕上輸出"
Hello XXX!"。hello.h(見程序1)爲該函數庫的頭文件。main.c(見程序3)爲測試庫文件的
主程序,在主程序中調用了公用函數hello。

程序1: hello.h

#ifndef HELLO_H
#define HELLO_H

void hello(const char *name);

#endif //HELLO_H

 

程序2: hello.c

#include <stdio.h>

void hello(const char *name)
{
printf("Hello %s!\n", name);
}

程序3: main.c

#include "hello.h"

int main()
{
hello("everyone");
return 0;
}

第2步:將hello.c編譯成.o文件;

不管靜態庫,仍是動態庫,都是由.o文件建立的。所以,咱們必須將源程序hello.c經過g
cc先編譯成.o文件。

在系統提示符下鍵入如下命令獲得hello.o文件。

# gcc -c hello.c

#

咱們運行ls命令看看是否生存了hello.o文件。

# ls

hello.c hello.h hello.o main.c

#


在ls命令結果中,咱們看到了hello.o文件,本步操做完成。

下面咱們先來看看如何建立靜態庫,以及使用它。

第3步:由.o文件建立靜態庫;

靜態庫文件名的命名規範是以lib爲前綴,緊接着跟靜態庫名,擴展名爲.a。例如:咱們將
建立的靜態庫名爲myhello,則靜態庫文件名就是libmyhello.a。在建立和使用靜態庫時,
須要注意這點。建立靜態庫用ar命令。

在系統提示符下鍵入如下命令將建立靜態庫文件libmyhello.a。

# ar -cr libmyhello.a hello.o

#

咱們一樣運行ls命令查看結果:

# ls

hello.c hello.h hello.o libmyhello.a main.c

#

ls命令結果中有libmyhello.a。

第4步:在程序中使用靜態庫;

靜態庫製做完了,如何使用它內部的函數呢?只須要在使用到這些公用函數的源程序中包
含這些公用函數的原型聲明,而後在用gcc命令生成目標文件時指明靜態庫名,gcc將會從
靜態庫中將公用函數鏈接到目標文件中。注意,gcc會在靜態庫名前加上前綴lib,而後追
加擴展名.a獲得的靜態庫文件名來查找靜態庫文件。

在程序3:main.c中,咱們包含了靜態庫的頭文件hello.h,而後在主程序main中直接調用公
用函數hello。下面先生成目標程序hello,而後運行hello程序看看結果如何。

法一 # gcc -o hello main.c -L. –lmyhello,或gcc  main.c -L. –lmyhello -o hello自定義的庫時,main.c還可放在-L.和 –lmyhello之間,可是不能放在它倆以後,不然會提示myhello沒定義,可是是系統的庫時,如g++ -o main(-L/usr/lib) -lpthread main.cpp就不出錯。

法二 #gcc main.c libmyhello.a -o hello或gcc  -o hello main.c libmyhello.a

法三:先生成main.o:gcc -c main.c ,再生成可執行文件:gcc -o hello main.o libmyhello.a或gccmain.o libmyhello.a -o hello ,動態庫鏈接時也能夠這樣作。

 

# ./hello

Hello everyone!

#

咱們刪除靜態庫文件試試公用函數hello是否真的鏈接到目標文件 hello中了。

# rm libmyhello.a

rm: remove regular file `libmyhello.a'? y

# ./hello

Hello everyone!

#

程序照常運行,靜態庫中的公用函數已經鏈接到目標文件中了。

咱們繼續看看如何在Linux中建立動態庫。咱們仍是從.o文件開始。

第5步:由.o文件建立動態庫文件;

動態庫文件名命名規範和靜態庫文件名命名規範相似,也是在動態庫名增長前綴lib,但其
文件擴展名爲.so。例如:咱們將建立的動態庫名爲myhello,則動態庫文件名就是libmyh
ello.so。用gcc來建立動態庫。

在系統提示符下鍵入如下命令獲得動態庫文件libmyhello.so。

 

# gcc -shared -fPIC -o libmyhello.so hello.o (-o不可少)

#

咱們照樣使用ls命令看看動態庫文件是否生成。

# ls

hello.c hello.h hello.o libmyhello.so main.c

#

第6步:在程序中使用動態庫;

在程序中使用動態庫和使用靜態庫徹底同樣,也是在使用到這些公用函數的源程序中包含
這些公用函數的原型聲明,而後在用gcc命令生成目標文件時指明動態庫名進行編譯。咱們
先運行gcc命令生成目標文件,再運行它看看結果。

# gcc -o hello main.c -L. -lmyhello

 

(或 #gcc main.c libmyhello.so -o hello 不會出錯(沒有libmyhello.so的話,會出錯),可是接下來./hello 會提示出錯,由於雖然鏈接時用的是當前目錄的動態庫,可是運行時,是到/usr/lib中找庫文件的,將文件libmyhello.so複製到目錄/usr/lib中就OK了)

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory

#

哦!出錯了。快看看錯誤提示,原來是找不到動態庫文件libmyhello.so。程序在運行時,
會在/usr/lib和/lib等目錄中查找須要的動態庫文件。若找到,則載入動態庫,不然將提
示相似上述錯誤而終止程序運行。咱們將文件libmyhello.so複製到目錄/usr/lib中,再試
試。

# mv libmyhello.so /usr/lib

# ./hello

Hello everyone!

#

成功了。這也進一步說明了動態庫在程序運行時是須要的。

咱們回過頭看看,發現使用靜態庫和使用動態庫編譯成目標程序使用的gcc命令徹底同樣,
那當靜態庫和動態庫同名時,gcc命令會使用哪一個庫文件呢?抱着對問題必究到底的心情,
來試試看。

先刪除除.c和.h外的全部文件,恢復成咱們剛剛編輯完舉例程序狀態。

# rm -f hello hello.o /usr/lib/libmyhello.so

# ls

hello.c hello.h main.c

#

在來建立靜態庫文件libmyhello.a和動態庫文件libmyhello.so。

在生成動態庫時,須要使用-fPIC,這樣才能生成位置無關的代碼,達到代碼段和數據段共享的目的

# gcc -c -fpic hello.c  //編譯hello.c時也須要加上-fpic選項,不然rodata' can not be used when making a shared object; recompile with -fPIC

# ar -cr libmyhello.a hello.o (或-cvr )

# gcc -shared -fPIC -o libmyhello.so hello.o

# ls

hello.c hello.h hello.o libmyhello.a libmyhello.so main.c

#

經過上述最後一條ls命令,能夠發現靜態庫文件libmyhello.a和動態庫文件libmyhello.s
o都已經生成,並都在當前目錄中。而後,咱們運行gcc命令來使用函數庫myhello生成目標
文件hello,並運行程序 hello。

# gcc -o hello main.c -L. –lmyhello (動態庫和靜態庫同時存在時,優先使用動態庫, 固然,直接#gcc main.c libmyhello.a -o hello的話,就是指定爲靜態庫了)

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory

#

從程序hello運行的結果中很容易知道,當靜態庫和動態庫同名時,gcc命令將優先使用動態庫,默認去連/usr/lib和/lib等目錄中的動態庫,將文件libmyhello.so複製到目錄/usr/lib中便可。

Note:
編譯參數解析
最主要的是GCC命令行的一個選項:
-shared 該選項指定生成動態鏈接庫(讓鏈接器生成T類型的導出符號表,有時候也生成弱鏈接W類型的導出符號),不用該標誌外部程序沒法鏈接。至關於一個可執行文件


-fPIC 做用於編譯階段,告訴編譯器產生與位置無關代碼(Position-Independent Code)。那麼在產生的代碼中,沒有絕對地址,所有使用相對地址,故而代碼能夠被加載器加載到內存的任意位置,均可以正確的執行。這正是共享庫所要求的,共享庫被加載時,在內存的位置不是固定的。

若是不加fPIC,則編譯出來的代碼在加載時須要根據加載到的位置進行重定位(由於它裏面的代碼並非位置無關代碼),若是被多個應用程序共同使用,那麼它們必須每一個程序維護一份so的代碼副本了.(由於so被每一個程序加載的位置都不一樣,顯然這些重定位後的代碼也不一樣,固然不能共享)。

不用此選項的話編譯後的代碼是位置相關的,因此動態載入時是經過代碼拷貝的方式來知足不一樣進程的須要,而不能達到真正代碼段共享的目的。

-L. 表示要鏈接的庫在當前目錄中;(多個庫:在編譯命令行中,將使用的靜態庫文件放在源文件後面就能夠了。好比:gcc -L/usr/lib myprop.c libtest.a libX11.a libpthread.a -o myprop
其中-L/usr/lib指定庫文件的查找路徑。編譯器默認在當前目錄下先查找指定的庫文件,如前面的「法二 #gccmain.c libmyhello.a-o hello」)


-lmyhello 編譯器查找動態鏈接庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so或.a來肯定庫的名稱libmyhello.so或libmyhello.a。
LD_LIBRARY_PATH這個環境變量指示動態鏈接器能夠裝載動態庫的路徑。
固然若是有root權限的話,能夠修改/etc/ld.so.conf文件,而後調用 /sbin/ldconfig來達到一樣的目的,不過若是沒有root權限,那麼只能採用輸出LD_LIBRARY_PATH的方法了。

調用動態庫的時候有幾個問題會常常碰到,有時,明明已經將庫的頭文件所在目錄 經過 「-I」 include進來了,庫所在文件經過 「-L」參數引導,並指定了「-l」的庫名,但經過ldd命令察看時,就是死活找不到你指定連接的so文件,這時你要做的就是經過修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件來指定動態庫的目錄。一般這樣作就能夠解決庫沒法連接的問題了。

 

 

靜態庫連接時搜索路徑順序:

1. ld(GNU linker)會去找GCC命令中的參數-L

   編譯過程是分爲四個階段:預處理(也稱預編譯,Preprocessing)、編譯(Compilation)、彙編 (Assembly)和鏈接(link)  【連接】
2. 再找gcc的環境變量LIBRARY_PATH
3. 再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程序內的

動態連接時、執行時搜索路徑順序:

1. 編譯目標代碼時指定的動態庫搜索路徑
2. 環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑
3. 配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
4. 默認的動態庫搜索路徑/lib
5. 默認的動態庫搜索路徑/usr/lib

有關環境變量:
LIBRARY_PATH環境變量:指定程序靜態連接庫文件搜索路徑
LD_LIBRARY_PATH環境變量:指定程序動態連接庫文件搜索路徑

 


另:

從上述可知,如何找到生成的動態庫有3種方式:

(1)把庫拷貝到/usr/lib和/lib目錄下。

(2)在LD_LIBRARY_PATH環境變量中加上庫所在路徑。

例如動態庫libhello.so在/home/example/lib目錄下:

export LD_LIBRARY_PATH=LD_LIBRARY_PATH:/home/example/lib

(3) 修改/etc/ld.so.conf文件,把庫所在的路徑加到文件末尾(直接寫在文件末尾,不要在路徑前加include),並執行ldconfig刷新(ldconfig 命令的用途,主要是在默認搜尋目錄(/lib和/usr/lib)以及動態庫配置文件/etc/ld.so.conf內所列的目錄下,搜索出可共享的動態連接庫(格式如前介紹,lib*.so*),進而建立出動態裝入程序(ld.so)所需的鏈接和緩存文件.緩存文件默認爲/etc/ld.so.cache,此文件保存已排好序的動態連接庫名字列表.)。這樣,加入的目錄下的全部庫文件均可見。

附:像下面這樣指定路徑去鏈接系統的靜態庫,會報錯說要鏈接的庫找不到:

g++ -o main main.cpp -L/usr/lib libpthread.a 

必須這樣g++ -o main main.cpp -L/usr/lib -lpthread才正確 。

自定義的庫考到/usr/lib 下時,

g++ -o main main.cpp -L/usr/lib libpthread.a libthread.a libclass.a會出錯,可是這樣g++ -o main main.cpp -L/usr/lib -lpthread -lthread -lclass就正確了。

相關文章
相關標籤/搜索