1. 程式人生 > >GCC 編譯使用動態連結庫和靜態連結庫--及先後順序----及環境變數設定總結

GCC 編譯使用動態連結庫和靜態連結庫--及先後順序----及環境變數設定總結

1 庫的分類

根據連結時期的不同,庫又有靜態庫和動態庫之分。

靜態庫是在連結階段被連結的(好像是廢話,但事實就是這樣),所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。

有別於靜態庫,動態庫的連結是在程式執行的時候被連結的。所以,即使程式編譯完,庫仍須保留在系統上,以供程式執行時呼叫。(TODO:連結動態庫時連結階段到底做了什麼)

2 靜態庫和動態庫的比較

連結靜態庫其實從某種意義上來說也是一種貼上複製,只不過它操作的物件是目的碼而不是原始碼而已。因為靜態庫被連結後庫就直接嵌入可執行檔案中了,這樣就帶來了兩個問題。

首先就是系統空間被浪費了。這是顯而易見的,想象一下,如果多個程式連結了同一個庫,則每一個生成的可執行檔案就都會有一個庫的副本,必然會浪費系統空間。

再者,人非聖賢,即使是精心除錯的庫,也難免會有錯。一旦發現了庫中有bug,挽救起來就比較麻煩了。必須一一把連結該庫的程式找出來,然後重新編譯。

而動態庫的出現正彌補了靜態庫的以上弊端。因為動態庫是在程式執行時被連結的,所以磁碟上只須保留一份副本,因此節約了磁碟空間。如果發現了bug或要升級也很簡單,只要用新的庫把原來的替換掉就行了。

那麼,是不是靜態庫就一無是處了呢?

答曰:非也非也。不是有句話麼:存在即是合理。靜態庫既然沒有湮沒在滔滔的歷史長河中,就必然有它的用武之地。想象一下這樣的情況:如果你用libpcap庫編了一個程式,要給被人執行,而他的系統上沒有裝pcap庫,該怎麼解決呢?最簡單的辦法就是編譯該程式時把所有要連結的庫都連結它們的靜態庫,這樣,就可以在別人的系統上直接執行該程式了。

所謂有得必有失,正因為動態庫在程式執行時被連結,故程式的執行速度和連結靜態庫的版本相比必然會打折扣。然而瑕不掩瑜,動態庫的不足相對於它帶來的好處在現今硬體下簡直是微不足道的,所以連結程式在連結時一般是優先連結動態庫的,除非用-static引數指定連結靜態庫。

動態連結庫

1. 建立動態連結庫

  1. #include<stdio.h>
  2. void hello()  
  3. {  
  4.         printf("hello world/n");  
  5. }  
 

用命令gcc -shared hello.c -o libhello.so編譯為動態庫。可以看到,當前目錄下多了一個檔案libhello.so。

2. 再編輯一個測試檔案test.c,內容如下

  1. #include<stdio.h>
  2. int main()  
  3. {  
  4.         printf("call hello()");  
  5.         hello();  
  6. }  
 

編譯 gcc test.c -lhello

-l 選項告訴編譯器要使用hello這個庫。奇怪的地方是動態庫的名字是libhello.so,這裡卻使用hello.

但這樣還不行,編譯會出錯。

In function `main':

test.c:(.text+0x1d): undefined reference to `hello'

collect2: ld returned 1 exit status

這是因為hello這個庫在我們自己的路徑中,編譯器找不到。

需要使用-L選項,告訴hello庫的位置

gcc test.c -lhello -L. -o test

-L .告訴編譯器在當前目錄中查詢庫檔案

3. 編譯成功後執行./test, 仍然出錯

說找不到庫

有兩種方法:

一、可以把當前路徑加入 /etc/ld.so.conf中然後執行ldconfig,或者以當前路徑為引數執行ldconfig(要有root許可權才行)。

二、把當前路徑加入環境變數LD_LIBRARY_PATH中

當然,如果你覺得不會引起混亂的話,可以直接把該庫拷入/lib,/usr/lib/等位置(無可避免,這樣做也要有許可權),這樣連結器和載入器就都可以準確的找到該庫了。

我們採用第二種方法:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

這樣,再執行就成功了。

下面再講講靜態連結庫

仍使用剛才的hello.c和test.c。

1. gcc -c hello.c 注意這裡沒有使用-shared選項

2. 把目標檔案歸檔    ar -r libhello.a hello.o

    程式 ar 配合引數 -r 建立一個新庫 libhello.a 並將命令列中列出的物件檔案插入。採用這種方法,如果庫不存在的話,引數 -r 將建立一個新的庫,而如果庫存在的話,將用新的模組替換原來的模組。

3. 在程式中連結靜態庫

           gcc test.c -lhello -L. -static -o hello.static 

或者   gcc test.c libhello.a -L. -o hello.static

生成的hello.static就不再依賴libhello.a了

兩個有用的命令

file程式是用來判斷檔案型別的,在file命令下,所有檔案都會原形畢露的。

順便說一個技巧。有時在 windows下用瀏覽器下載tar.gz或tar.bz2檔案,字尾名會變成奇怪的tar.tar,到Linux有些新手就不知怎麼解壓了。但 Linux下的檔案型別並不受檔案字尾名的影響,所以我們可以先用命令file xxx.tar.tar看一下檔案型別,然後用tar加適當的引數解壓。

另外,還可以藉助程式ldd實用程式來判斷。

ldd是用來列印目標程式(由命令列引數指定)所連結的所有動態庫的資訊的,如果目標程式沒有連結動態庫,則列印“not a dynamic executable”,ldd的用法請參考manpage。


1,如何生成靜態庫 靜態庫只是一堆object物件的集合,使用ar命令可以將.o檔案打包成.a靜態庫。 假設gcc已經生成了a.o, b.o, c.o,使用下面的命令即可生成libmylib.a #ar rcs libmylib.a a.o b.o c.o 2,如何生成動態庫 動態庫的生成由gcc直接生成。 假設a.c, b.c兩個檔案,通過下面的命令可生成libmylib.so #gcc a.c b.c -o libmylib.so --shared 3,如何使用庫 gcc中關於庫的引數有: -L  指定搜尋庫的目錄       如指定當前目錄 gcc -L . -l    指定要連結的庫的名稱       加入庫的名稱是libmylib.a,則gcc -l mylib,即去頭去尾。 --static  組織在連結時使用動態庫 --shared 生成動態庫 --static-libgcc  連結靜態libgcc庫 --shared-libgcc 連結動態libgcc庫 可見對動態庫和靜態庫的使用方法是一樣的,同一個庫如果同時存在動態庫和靜態庫,優先連結動態庫,除非使用--static強制使用靜態庫。

gcc -lXXX 如何選擇靜態庫還是動態庫?

庫標準路徑下存在libABC.a和libABC.so使用gcc -lABC如何選擇連線靜態連線庫或者動態連線庫?通過--hare --static選項? 如果在同一路徑下面,並且兩種庫同名,這樣會選擇動態庫。

gcc 混合連線動態庫和靜態庫

gcc 同時連線 靜態庫和動態庫現在有 libmy.a & libmy.so兩個庫,其中的函式供main.cc呼叫要在可執行檔案中同時連線這兩個庫gcc -g -lstdc++ -g -L. -lmy -l ./libmy.a -o test.exe main.cc // 報找不到libmy.a,可是在當前目錄下已經有這個檔案了gcc -g -lstdc++ -g -L. -l libmy.so -l ./libmy.a -o test.exe main.cc // 報找不到libmy.so,在當前目錄下也有這個檔案用了 -static 選線,則報動態庫中的函式沒定義請問大家有什麼招不?感激 採納率:46% 10級 2013.04.25 我記得靜態庫混合動態庫要加特殊指令的,你可以試試這樣:gcc -g -lstdc++ -g -WI,-Bdynamic -L. -lmy -WI,-Bstatic -L. -lmy -o test.exe main.cc

gcc優先連結動態庫,找不到,才連結靜態庫……

轉載 gcc連結時 -l 引數可否連線動態庫?



g++編譯時, 用-labc 選項後, 編譯器會自動按照命名規則去搜索 libabc.a 庫檔案, 但如果我想使用動態連結庫連結應如何指定引數?
優先連結共享庫。共享庫找不到,才連結靜態庫。
可是如果我在 -l 選項後新增共享庫, 則連結時報告庫檔案不存在, 共享庫和靜態庫的命名規則是否一樣?
例如我有一個名為 libabc.so, 我應採用什麼格式的選項才可以在gcc命令中找到它?
使用 -l 選項指定靜態庫和動態庫的格式都是一樣的,如果庫檔名為libabc.so,那麼就用 -labc 即可。
連結時會去搜索這個庫檔案,如果不是系統庫,那麼你需要告訴連結器它的路徑。有兩種方法:一種是在引數中用 -L 選項指定庫檔案搜尋路徑,可以並列多個。例如:gcc -L /home/ddd -L/home/ddd/lib。 另一種方法是在環境變數中設定LD_LIBRARY_PATH 包含有你的動態庫檔案所在的路徑。這個環境變數用在Sorlarise和Linux,如果你是在HP-UX下,是SHLIB_PATH。

0
allen@xps:~/Downloads/N-GenIC$ mpiexec -np 8  ./N-GenIC  ics.param
/usr/local/bin/hydra_pmi_proxy: error while loading shared libraries: libcr.so.0: cannot open shared object file: No such file or directory
allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5

已經嘗試過ldconfigLD_LIBRARY_PATH="/usr/lib" && export LD_LIBRARY_PATH但是都沒用

現在通過google找到了一種解決方法,就是sudo apt-get install libcr-dev,執行之後程式就正常運行了. 但是查詢共享庫libcr.so.0的結果還是

allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5

不知道這中間發生了什麼? 請解釋一下

預設排序時間排序

2 個回答

0

執行locate前先sudo updatedb一下。。

0

你試試把LIBRARY_PATH也設為那個目錄,然後重新make一下。

export LIBRARY_PATH=/usr/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH

Linux設定和檢視環境變數的方法

linux 檢視環境變數與設定環境變數在使用過程中很常見,本文整理了一些常用的與環境變數相關的命令,感興趣的朋友可以參考下希望對你有所幫助
1. 顯示環境變數HOME 
$ echo $HOME 
/home/redbooks 

2. 設定一個新的環境變數hello 
$ export HELLO="Hello!" 
$ echo $HELLO 
Hello! 

3. 使用env命令顯示所有的環境變數 
$ env 
HOSTNAME=redbooks.safe.org 
PVM_RSH=/usr/bin/rsh 
Shell=/bin/bash 
TERM=xterm 
HISTSIZE=1000 
... 

4. 使用set命令顯示所有本地定義的Shell變數 
$ set 
BASH=/bin/bash 
BASH_VERSINFO=([0]="2"[1]="05b"[2]="0"[3]="1"[4]="release"[5]="i386-redhat-linux-gnu") 
BASH_VERSION='2.05b.0(1)-release' 
COLORS=/etc/DIR_COLORS.xterm 
COLUMNS=80 
DIRSTACK=() 
DISPLAY=:0.0 
... 

5. 使用unset命令來清除環境變數 
set可以設定某個環境變數的值。清除環境變數的值用unset命令。如果未指定值,則該變數值將被設為NULL。示例如下: 
$ export TEST="Test..." #增加一個環境變數TEST 
$ env|grep TEST #此命令有輸入,證明環境變數TEST已經存在了 
TEST=Test... 
$ unset $TEST #刪除環境變數TEST 
$ env|grep TEST #此命令沒有輸出,證明環境變數TEST已經存在了 

6. 使用readonly命令設定只讀變數 
如果使用了readonly命令的話,變數就不可以被修改或清除了。示例如下: 
$ export TEST="Test..." #增加一個環境變數TEST 
$ readonly TEST #將環境變數TEST設為只讀 
$ unset TEST #會發現此變數不能被刪除 
-bash: unset: TEST: cannot unset: readonly variable 
$ TEST="New" #會發現此也變數不能被修改 
-bash: TEST: readonly variable 
環境變數的設定位於/etc/profile檔案 
如果需要增加新的環境變數可以新增下屬行 
export path=$path:/path1:/path2:/pahtN 
----------------------------------------------------------------------------------------------------------------------- 
1.Linux的變數種類 
按變數的生存週期來劃分,Linux變數可分為兩類: 
1.1 永久的:需要修改配置檔案,變數永久生效。 
1.2 臨時的:使用export命令宣告即可,變數在關閉shell時失效。 

2.設定變數的三種方法 
2.1 在/etc/profile檔案中新增變數【對所有使用者生效(永久的)】 
用VI在檔案/etc/profile檔案中增加變數,該變數將會對Linux下所有使用者有效,並且是“永久的”。 
例如:編輯/etc/profile檔案,新增CLASSPATH變數 
# vi /etc/profile 
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib 
注:修改檔案後要想馬上生效還要執行# source /etc/profile不然只能在下次重進此使用者時生效。 
2.2 在使用者目錄下的.bash_profile檔案中增加變數【對單一使用者生效(永久的)】 
用VI在使用者目錄下的.bash_profile檔案中增加變數,改變數僅會對當前使用者有效,並且是“永久的”。 
例如:編輯guok使用者目錄(/home/guok)下的.bash_profile 
$ vi /home/guok/.bash.profile 
新增如下內容: 
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib 
注:修改檔案後要想馬上生效還要執行$ source /home/guok/.bash_profile不然只能在下次重進此使用者時生效。 
2.3 直接執行export命令定義變數【只對當前shell(BASH)有效(臨時的)】 
在shell的命令列下直接使用[export 變數名=變數值] 定義變數,該變數只在當前的shell(BASH)或其子shell(BASH)下是有效的,shell關閉了,變數也就失效了,再開啟新shell時就沒有這個變數,需要使用的話還需要重新定義。 

3.環境變數的檢視 
3.1 使用echo命令檢視單個環境變數。例如: 
echo $PATH 
3.2 使用env檢視所有環境變數。例如: 
env 
3.3 使用set檢視所有本地定義的環境變數。 
unset可以刪除指定的環境變數。 

4.常用的環境變數 
PATH 決定了shell將到哪些目錄中尋找命令或程式 
HOME 當前使用者主目錄 
HISTSIZE 歷史記錄數 
LOGNAME 當前使用者的登入名 
HOSTNAME 指主機的名稱 
SHELL 當前使用者Shell型別 
LANGUGE  語言相關的環境變數,多語言可以修改此環境變數 
MAIL 當前使用者的郵件存放目錄 
PS1 基本提示符,對於root使用者是#,對於普通使用者是$ 

相關推薦

GCC編譯過程與動態連結靜態連結(未整理)

來源:https://www.cnblogs.com/qingjiaowoxiaoxioashou/p/6410588.html 根據連結時期的不同,庫又有靜態庫和動態庫之分。靜態庫是在連結階段被連結的,所以生成的可執行檔案就不受庫的影響,即使庫被刪除,程式依然可以成功執行。而動態庫是在程式執行的時

GCC 編譯使用動態連結靜態連結--先後順序----環境變數設定總結

1 庫的分類 根據連結時期的不同,庫又有靜態庫和動態庫之分。 靜態庫是在連結階段被連結的(好像是廢話,但事實就是這樣),所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。 有別於靜態庫,動態庫的連結是在程式執行的時候被連結的。所以,即使

GCC 編譯使用動態連結靜態連結

1 庫的分類 根據連結時期的不同,庫又有靜態庫和動態庫之分。 靜態庫是在連結階段被連結的(好像是廢話,但事實就是這樣),所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。 有別於靜態庫,動態庫的連結是在程式執行的時候被連結的。所以,即使程式編譯完,

GCC 編譯使用動態連結靜態連結的方法

1 庫的分類 根據連結時期的不同,庫又有靜態庫和動態庫之分。 靜態庫是在連結階段被連結的(好像是廢話,但事實就是這樣),所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。 有別於靜態庫,動態庫的連結是在程式執行的時候被連結的。所以,即使程式

靜態連結編譯與使用 linux下的動態連結靜態連結到底是個什麼鬼?(一)靜態連結編譯與使用

linux下的動態連結庫和靜態連結庫到底是個什麼鬼?(一)靜態連結庫的編譯與使用       知識不等於技術,這句話真的是越工作的時間長越深有體會,學習到的知識只有不斷的實踐,才成真正在自已的心裡紮下根,成為自身的一部分,所以無論如何,我希望我的部落格可以

g++ 編譯動態連結靜態連結

現在我有hello1.cpp和hello2.cpp兩個檔案,現在我要生成動態連結庫libhello.so和靜態連結庫libhello.a。以下為步驟: 1.生成動態連結庫: g++ -m32 hello1.cpp hello2.cpp -fPIC -shared -o ..

動態連結靜態連結的相互包含問題實現

動態連結庫和靜態連結庫的基本概念請參考 1.《深入理解計算機系統》第七章連結 2.《程式設計師的自我修養》第4章 靜態連結和第7章 動態連結 3. http://blog.jobbole.com/86852/ 目的 為了封裝程式碼,簡化介面,我們要把已有應用程式碼封裝為

對於動態連結靜態連結的一些理解

以下內容只討論win中的動態連結和靜態連結。首先,一個程式從編譯的執行的全過程:預編譯->編譯->彙編->連結其中,到了彙編這一步生成.obj檔案,也就是說,對於一個單獨的.c檔案,只要可以找到他的標頭檔案,到了這一步都不會報錯!然後,這些彙編生成的obj檔

VS2012中使用OpenCV-3.0.0的動態連結靜態連結

一、 新建工程 1、選單選擇“檔案——新建——專案” 2、左側選擇“已安裝——模板——Visual C++——Win32”,右側選擇“Win32專案” 3、確定後,依次點選“下一步”, 4、點選“完成”,自動生成專案

C++ 動態連結靜態連結

typedef int (*DllFunc)(int, int); int _tmain(int argc, _TCHAR* argv[]) { DllFunc dllFunc; HINSTANCE hInstLib = LoadLibrary(L"DllTest.dll"); if (hInstLi

動態連結串列靜態連結串列的區別

靜態連結串列是用陣列實現的,是順序的儲存結構,在實體地址上是連續的,而且需要預先分配大小。動態連結串列是用申請記憶體函式(C是malloc,C++是new)動態申請記憶體的,所以在連結串列的長度上沒

【C語言】動態連結串列靜態連結串列的建立

動態連結串列和靜態連結串列 #include<stdio.h> #include<stdlib.h> #include<malloc.h> struct wep{

QtEmbedded-4.8.6-arm 編譯選擇從 動態變化到靜態 時,生成的Makefile連結路徑下如果有動態靜態,優先選擇動態編譯應用

問題:QtEmbedded-4.8.6-arm 編譯選擇從 動態庫到靜態庫 時,發現的一個疑惑:,生成的Makefile連結庫路徑下如果有動態庫和靜態庫,優先選擇動態庫編譯應用 具體現象: 我最初是使用動態庫的 QtEmbedded-4.8.6-arm (編譯器選擇時,是 ./co

gcc動態靜態連結順序

so檔案:動態庫 a檔案: 靜態庫 exe檔案:可執行程式(linux下以檔案屬性來標示是否是可執行檔案,與字尾名無關) gcc中連結順序問題,總結出以下幾點: 1,動態庫中可以包含另一個靜態庫,通過引數 -lxxx 把靜態庫libxxx.a加入so檔案中,這樣so檔案中 &nbs

linux下g++ 編譯動態靜態連結標頭檔案問題

原來編譯的時候都是用的很隨意,沒用系統的總結一下,這幾天在編譯的時候遇到一些下問題,於是就總結一下,省得過幾天又給忘了。 1.動態庫和靜態庫簡介 靜態庫在程式連結的時候會自動的連結到程式裡,所以一旦編譯完成,靜態庫就不需要了,靜態庫以.a結尾。  動態庫在編譯時不會被連線到目的碼中,而是在程式執行

自己在linux上編譯連結動態靜態的學習筆記

在平常的專案中,我們都是使用公司要求的makefile、makedebug一類的檔案,因此,在編譯、連結、生成和連結動態庫與靜態庫的時候,我們只是簡單的使用一些已經設定的變數,只是簡單的修改、新增一些檔名,或許這次我們編譯通過了,但是,在某一個時候,可能出現了一個問題,無論

GCC 編譯動態 so檔案時,靜態連結libmysqlclient.a 與動態連結引數一起使用問題。

直接放結論, 下面是編譯一個使用了mysql C API 的 mysql.so 檔案(我們的業務中,它是zbx加裁的modules so檔案) gcc -fPIC -shared -o mysql.so mysql.c \ -I/usr/include

【轉】gcc 編譯使用動態鏈接靜態鏈接

避免 因此 -s 階段 cap etc 可執行 選項 而已 1 庫的分類 根據鏈接時期的不同,庫又有靜態庫和動態庫之分。 靜態庫是在鏈接階段被鏈接的(好像是廢話,但事實就是這樣),所以生成的可執行文件就不受庫的影響了,即使庫被刪除了,程序依然可以成功運行。 有別於靜態庫,動

Linux下動態靜態連結

一、檢視連結了哪些指令 ldd 程式名字 二、在應用程式需要連線外部庫的情況下,linux預設對庫的連線是使用動態庫,在找不到動態庫的情況下再選擇靜態庫。使用方式為: gcc test.cpp -L. -ltestlib 如果當前目錄有兩個庫libtestlib.

GCC編譯過程與動態鏈接靜態鏈接

elf格式 方式 通過 ifd lan 匯編語言 cpp wid 本質 1. 庫的介紹 庫是寫好的現有的,成熟的,可以復用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。 本質上來說庫是一種可執行代碼的二進制形式,