日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

在Linux中创建静态库.a和动态库.so

發(fā)布時(shí)間:2023/12/19 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在Linux中创建静态库.a和动态库.so 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html

?

在Linux中創(chuàng)建靜態(tài)庫.a和動(dòng)態(tài)庫.so

我們通常把一些公用函數(shù)制作成函數(shù)庫,供其它程序使用。

函數(shù)庫分為靜態(tài)庫和動(dòng)態(tài)庫兩種。

?

1. 靜態(tài)函數(shù)庫

?

??? 這類庫的名字一般是libxxx.a;利用靜態(tài)函數(shù)庫編譯成的文件比較大,因?yàn)檎麄€(gè) 函數(shù)庫的所有數(shù)據(jù)都會(huì)被整合進(jìn)目標(biāo)代碼中,他的優(yōu)點(diǎn)就顯而易見了,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫支持,因?yàn)樗惺褂玫暮瘮?shù)都已經(jīng)被編譯進(jìn)去了。當(dāng)然這也會(huì)成為他的缺點(diǎn),因?yàn)槿绻o態(tài)函數(shù)庫改變了,那么你的程序必須重新編譯。

?

2. 動(dòng)態(tài)函數(shù)庫

?

??? 這類庫的名字一般是libxxx.so;相對(duì)于靜態(tài)函數(shù)庫,動(dòng)態(tài)函數(shù)庫在編譯的時(shí)候 并沒有被編譯進(jìn)目標(biāo)代碼中,你的程序執(zhí)行到相關(guān)函數(shù)時(shí)才調(diào)用該函數(shù)庫里的相應(yīng)函數(shù),因此動(dòng)態(tài)函數(shù)庫所產(chǎn)生的可執(zhí)行文件比較小。由于函數(shù)庫沒有被整合進(jìn)你的程序,而是程序運(yùn)行時(shí)動(dòng)態(tài)的申請(qǐng)并調(diào)用,所以程序的運(yùn)行環(huán)境中必須提供相應(yīng)的庫。動(dòng)態(tài)函數(shù)庫的改變并不影響你的程序,所以動(dòng)態(tài)函數(shù)庫的升級(jí)比較方便。?
linux系統(tǒng)有幾個(gè)重要的目錄存放相應(yīng)的函數(shù)庫,如/lib /usr/lib

?

靜態(tài)庫在程序編譯時(shí)會(huì)被連接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要該靜態(tài)庫。

動(dòng)態(tài)庫在程序編譯時(shí)并不會(huì)被連接到目標(biāo)代碼中,而是在程序運(yùn)行是才被載入,因此在程序運(yùn)行時(shí)還需要?jiǎng)討B(tài)庫存在

本文主要通過舉例來說明在Linux中如何創(chuàng)建靜態(tài)庫和動(dòng)態(tài)庫,以及使用它們。

在創(chuàng)建函數(shù)庫前,我們先來準(zhǔn)備舉例用的源程序,并將函數(shù)庫的源程序編譯成.o文件。

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

hello.h(見程序1)為該函數(shù)庫的頭文件。

hello.c(見程序2)是函數(shù)庫的源程序,其中包含公用函數(shù)hello,該函數(shù)將在屏幕上輸出"Hello XXX!"。

main.c(見程序3)為測(cè)試庫文件的主程序,在主程序中調(diào)用了公用函數(shù)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文件;

無論靜態(tài)庫,還是動(dòng)態(tài)庫,都是由.o文件創(chuàng)建的。因此,我們必須將源程序hello.c通過gcc先編譯成.o文件。

在系統(tǒng)提示符下鍵入以下命令得到hello.o文件。

# gcc -c hello.c

#

(注1:本文不介紹各命令使用和其參數(shù)功能,若希望詳細(xì)了解它們,請(qǐng)參考其他文檔。)

(注2:首字符"#"是系統(tǒng)提示符,不需要鍵入,下文相同。)

我們運(yùn)行l(wèi)s命令看看是否生存了hello.o文件。

# ls

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

#

(注3:首字符不是"#"為系統(tǒng)運(yùn)行結(jié)果,下文相同。)

在ls命令結(jié)果中,我們看到了hello.o文件,本步操作完成。

下面我們先來看看如何創(chuàng)建靜態(tài)庫,以及使用它。


?

第3步:由.o文件創(chuàng)建靜態(tài)庫;

靜態(tài)庫文件名的命名規(guī)范是以lib為前綴,緊接著跟靜態(tài)庫名,擴(kuò)展名為.a。例如:我們將創(chuàng)建的靜態(tài)庫名為myhello,則靜態(tài)庫文件名就是libmyhello.a。在創(chuàng)建和使用靜態(tài)庫時(shí),需要注意這點(diǎn)。創(chuàng)建靜態(tài)庫用ar命令。

在系統(tǒng)提示符下鍵入以下命令將創(chuàng)建靜態(tài)庫文件libmyhello.a。

# ar cr libmyhello.a hello.o

#

我們同樣運(yùn)行l(wèi)s命令查看結(jié)果:

# ls

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

#

ls命令結(jié)果中有l(wèi)ibmyhello.a。


?

第4步:在程序中使用靜態(tài)庫;

靜態(tài)庫制作完了,如何使用它內(nèi)部的函數(shù)呢?只需要在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標(biāo)文件時(shí)指明靜態(tài)庫名,gcc將會(huì)從靜態(tài)庫中將公用函數(shù)連接到目標(biāo)文件中。注意,gcc會(huì)在靜態(tài)庫名前加上前綴lib,然后追加擴(kuò)展名.a得到的靜態(tài)庫文件名來查找靜態(tài)庫文件。

在程序3:main.c中,我們包含了靜態(tài)庫的頭文件hello.h,然后在主程序main中直接調(diào)用公用函數(shù)hello。下面先生成目標(biāo)程序hello,然后運(yùn)行hello程序看看結(jié)果如何。

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

# ./hello

Hello everyone!

#

我們刪除靜態(tài)庫文件試試公用函數(shù)hello是否真的連接到目標(biāo)文件 hello中了。

# rm libmyhello.a

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

# ./hello

Hello everyone!

#

程序照常運(yùn)行,靜態(tài)庫中的公用函數(shù)已經(jīng)連接到目標(biāo)文件中了。

我們繼續(xù)看看如何在Linux中創(chuàng)建動(dòng)態(tài)庫。我們還是從.o文件開始。


?

第5步:由.o文件創(chuàng)建動(dòng)態(tài)庫文件;

動(dòng)態(tài)庫文件名命名規(guī)范和靜態(tài)庫文件名命名規(guī)范類似,也是在動(dòng)態(tài)庫名增加前綴lib,但其文件擴(kuò)展名為.so。例如:我們將創(chuàng)建的動(dòng)態(tài)庫名為myhello,則動(dòng)態(tài)庫文件名就是libmyhello.so。用gcc來創(chuàng)建動(dòng)態(tài)庫。

在系統(tǒng)提示符下鍵入以下命令得到動(dòng)態(tài)庫文件libmyhello.so。

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

#

我們照樣使用ls命令看看動(dòng)態(tài)庫文件是否生成。“PIC”命令行標(biāo)記告訴GCC產(chǎn)生的代碼不要包含對(duì)函數(shù)和變量具體內(nèi)存位置的引用,這是因?yàn)楝F(xiàn)在還無法知道使用該消息代碼的應(yīng)用程序會(huì)將它連接到哪一段內(nèi)存地址空間。這樣編譯出的hello.o可以被用于建立共享鏈接庫。建立共享鏈接庫只需要用GCC的”-shared”標(biāo)記即可。

# ls

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

#


?

第6步:在程序中使用動(dòng)態(tài)庫;

在程序中使用動(dòng)態(tài)庫和使用靜態(tài)庫完全一樣,也是在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標(biāo)文件時(shí)指明動(dòng)態(tài)庫名進(jìn)行編譯。我們先運(yùn)行g(shù)cc命令生成目標(biāo)文件,再運(yùn)行它看看結(jié)果。

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

# ./hello

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

#

哦!出錯(cuò)了。快看看錯(cuò)誤提示,原來是找不到動(dòng)態(tài)庫文件libmyhello.so。程序在運(yùn)行時(shí),會(huì)在/usr/lib和/lib等目錄中查找需要的動(dòng)態(tài)庫文件。若找到,則載入動(dòng)態(tài)庫,否則將提示類似上述錯(cuò)誤而終止程序運(yùn)行。我們將文件libmyhello.so復(fù)制到目錄/usr/lib中,再試試。

(使用”-lmyhello”標(biāo)記來告訴GCC驅(qū)動(dòng)程序在連接階段引用共享函數(shù)庫libmyhello.so?!?L.”標(biāo)記告訴GCC函數(shù)庫可能位于當(dāng)前目錄。否則GNU連接器會(huì)查找標(biāo)準(zhǔn)系統(tǒng)函數(shù)目錄:它先后搜索1.elf文件的?DT_RPATH段—2.環(huán)境變量LD_LIBRARY_PATH—3./etc/ld.so.cache文件列表—4./lib/,/usr/lib目錄找到庫文件后將其載入內(nèi)存,但是我們生成的共享庫在當(dāng)前文件夾下,并沒有加到上述的4個(gè)路徑的任何一個(gè)中,因此,執(zhí)行后會(huì)出現(xiàn)錯(cuò)誤)

# mv libmyhello.so /usr/lib

# ./hello

Hello everyone!

#

成功了。這也進(jìn)一步說明了動(dòng)態(tài)庫在程序運(yùn)行時(shí)是需要的。

另外:既然連接器會(huì)搜尋LD_LIBRARY_PATH所指定的目錄,那么我們可以將這個(gè)環(huán)境變量設(shè)置成當(dāng)前目錄:

先執(zhí)行:

export LD_LIBRARY_PATH=$(pwd)

再執(zhí)行:

./hello

成功!

最后:執(zhí)行:??

ldconfig?? /usr/zhsoft/lib?????
? ??
? 注:?? 當(dāng)用戶在某個(gè)目錄下面創(chuàng)建或拷貝了一個(gè)動(dòng)態(tài)鏈接庫,若想使其被系統(tǒng)共享,可以執(zhí)行一下"ldconfig?? 目錄名"這個(gè)命令.此命令的功能在于讓ldconfig將指定目錄下的動(dòng)態(tài)鏈接庫被系統(tǒng)共享起來,意即:在緩存文件/etc/ld.so.cache中追加進(jìn)指定目錄下的共享庫.本例讓系統(tǒng)共享了/usr/zhsoft/lib目錄下的動(dòng)態(tài)鏈接庫.該命令會(huì)重建/etc/ld.so.cache文件

成功!

可以查看程序執(zhí)行時(shí)調(diào)用動(dòng)態(tài)庫的過程:

# ldd hello
執(zhí)行 test,可以看到它是如何調(diào)用動(dòng)態(tài)庫中的函數(shù)的。
[pin@localhost 20090505]$ ldd hello
??????? linux-gate.so.1 => (0x00110000)
??????? libmyhello.so => /usr/lib/libmyhello.so (0x00111000)
??????? libc.so.6 => /lib/libc.so.6 (0x00859000)
??????? /lib/ld-linux.so.2 (0x0083a000)

?

我們回過頭看看,發(fā)現(xiàn)使用靜態(tài)庫和使用動(dòng)態(tài)庫編譯成目標(biāo)程序使用的gcc命令完全一樣,那當(dāng)靜態(tài)庫和動(dòng)態(tài)庫同名時(shí),gcc命令會(huì)使用哪個(gè)庫文件呢?抱著對(duì)問題必究到底的心情,來試試看。

先刪除 除.c和.h外的 所有文件,恢復(fù)成我們剛剛編輯完舉例程序狀態(tài)。

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

# ls

hello.c hello.h main.c

#

在來創(chuàng)建靜態(tài)庫文件libmyhello.a和動(dòng)態(tài)庫文件libmyhello.so。

# gcc -c hello.c

# ar cr libmyhello.a hello.o

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

# ls

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

#

通過上述最后一條ls命令,可以發(fā)現(xiàn)靜態(tài)庫文件libmyhello.a和動(dòng)態(tài)庫文件libmyhello.so都已經(jīng)生成,并都在當(dāng)前目錄中。然后,我們運(yùn)行g(shù)cc命令來使用函數(shù)庫myhello生成目標(biāo)文件hello,并運(yùn)行程序 hello。

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

# ./hello

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

#

從程序hello運(yùn)行的結(jié)果中很容易知道,當(dāng)靜態(tài)庫和動(dòng)態(tài)庫同名時(shí), gcc命令將優(yōu)先使用動(dòng)態(tài)庫。

?

Note:

?

編譯參數(shù)解析

?


最主要的是GCC命令行的一個(gè)選項(xiàng):
-shared 該選項(xiàng)指定生成動(dòng)態(tài)連接庫(讓連接器生成T類型的導(dǎo)出符號(hào)表,有時(shí)候也生成弱連接W類型的導(dǎo)出符號(hào)),不用該標(biāo)志外部程序無法連接。相當(dāng)于一個(gè)可執(zhí)行文件
-fPIC:表示編譯為位置獨(dú)立的代碼,不用此選項(xiàng)的話編譯后的代碼是位置相關(guān)的所以動(dòng)態(tài)載入時(shí)是通過代碼拷貝的方式來滿足不同進(jìn)程的需要,而不能達(dá)到真正代碼段共享的目的。
-L.:表示要連接的庫在當(dāng)前目錄中
-ltest:編譯器查找動(dòng)態(tài)連接庫時(shí)有隱含的命名規(guī)則,即在給出的名字前面加上lib,后面加上.so來確定庫的名稱
LD_LIBRARY_PATH:這個(gè)環(huán)境變量指示動(dòng)態(tài)連接器可以裝載動(dòng)態(tài)庫的路徑。
?當(dāng)然如果有root權(quán)限的話,可以修改/etc/ld.so.conf文件,然后調(diào)用 /sbin/ldconfig來達(dá)到同樣的目的,不過如果沒有root權(quán)限,那么只能采用輸出LD_LIBRARY_PATH的方法了。

?

調(diào)用動(dòng)態(tài)庫的時(shí)候有幾個(gè)問題會(huì)經(jīng)常碰到,有時(shí),明明已經(jīng)將庫的頭文件所在目錄 通過 “-I” include進(jìn)來了,庫所在文件通過 “-L”參數(shù)引導(dǎo),并指定了“-l”的庫名,但通過ldd命令察看時(shí),就是死活找不到你指定鏈接的so文件,這時(shí)你要作的就是通過修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件來指定動(dòng)態(tài)庫的目錄。通常這樣做就可以解決庫無法鏈接的問題了。

?

靜態(tài)庫鏈接時(shí)搜索路徑順序:

1. ld會(huì)去找GCC命令中的參數(shù)-L

2. 再找gcc的環(huán)境變量LIBRARY_PATH

3. 再找內(nèi)定目錄 /lib /usr/lib /usr/local/lib 這是當(dāng)初compile gcc時(shí)寫在程序內(nèi)的

?

?

?

動(dòng)態(tài)鏈接時(shí)、執(zhí)行時(shí)搜索路徑順序:

?


1. ?編譯目標(biāo)代碼時(shí)指定的動(dòng)態(tài)庫搜索路徑;

2. ?環(huán)境變量LD_LIBRARY_PATH指定的動(dòng)態(tài)庫搜索路徑;

3. ?配置文件/etc/ld.so.conf中指定的動(dòng)態(tài)庫搜索路徑;

4. 默認(rèn)的動(dòng)態(tài)庫搜索路徑/lib;

5. 默認(rèn)的動(dòng)態(tài)庫搜索路徑/usr/lib。

?

?

?

有關(guān)環(huán)境變量:

LIBRARY_PATH環(huán)境變量:指定程序靜態(tài)鏈接庫文件搜索路徑

LD_LIBRARY_PATH環(huán)境變量:指定程序動(dòng)態(tài)鏈接庫文件搜索路徑

?

?

?

附注:

?

作為Linux程序開發(fā)員,最好對(duì)開發(fā)工具和資源的位置有個(gè)初步了解。下面簡(jiǎn)要介紹一下主要的文件夾和應(yīng)用程序。

?

1.應(yīng)用程序(Applications)

?

應(yīng)用程序通常都有固定的文件夾,系統(tǒng)通用程序放在/usr/bin,日后系統(tǒng)管理員在本地計(jì)算機(jī)安裝的程序通常放在/usr/local/bin或者/opt文件夾下。除了系統(tǒng)程序外,大部分個(gè)人用到的程序都放在/usr/local下,所以保持/usr的整潔十分重要。當(dāng)升級(jí)或者重裝系統(tǒng)的時(shí)候,只要把/usr/local的程序備份一下就可以了。

?

一些其他的程序有自己特定的文件夾,比如X Window系統(tǒng),通常安裝在/usr/X11中,或者/usr/X11R6。GNU的編譯器GCC,通常放置在/usr/bin或者/usr/local/bin中,不同的Linux版本可能位置稍有不同。

?

2.頭文件(Head Files)

?

在C語言和其他語言中,頭文件聲明了系統(tǒng)函數(shù)和庫函數(shù),并且定義了一些常量。對(duì)于C語言,頭文件基本上散落于/usr/include和它的子文件夾下。其他的編程語言的庫函數(shù)分布在編譯器定義的地方,比如在一些Linux版本中,X Window系統(tǒng)庫函數(shù)分布在/usr/include/X11,GNU C++的庫函數(shù)分布在/usr/include/g++。這些系統(tǒng)庫函數(shù)的位置對(duì)于編譯器來說都是“標(biāo)準(zhǔn)位置”,即編譯器能夠自動(dòng)搜尋這些位置。

?

如果想引用位于標(biāo)準(zhǔn)位置之外的頭文件,我們需要在調(diào)用編譯器的時(shí)候加上-I標(biāo)志,來顯式的說明頭文件所在文件夾。比如,

?

$ gcc -I/usr/openwin/include hello.c

?

會(huì)告訴編譯器除了標(biāo)準(zhǔn)位置外,還要去/usr/openwin/include看看有沒有所需的頭文件。詳細(xì)情況見編譯器的使用手冊(cè)(man gcc)。

?

庫函數(shù)(Library Files)

?

庫函數(shù)就是函數(shù)的倉庫,它們都經(jīng)過編譯,重用性不錯(cuò)。通常,庫函數(shù)相互合作,來完成特定的任務(wù)。比如操控屏幕的庫函數(shù)(cursers和ncursers庫函數(shù)),數(shù)據(jù)庫讀取庫函數(shù)(dbm庫函數(shù))等。

?

系統(tǒng)調(diào)用的標(biāo)準(zhǔn)庫函數(shù)一般位于/lib以及/usr/lib。C編譯器(精確點(diǎn)說,連接器)需要知道庫函數(shù)的位置。默認(rèn)情況下,它只搜索標(biāo)準(zhǔn)C庫函數(shù)。

?

庫函數(shù)文件通常開頭字母是lib。后面的部分標(biāo)示庫函數(shù)的用途(比如C庫函數(shù)用c標(biāo)識(shí), 數(shù)學(xué)庫函數(shù)用m標(biāo)示),小數(shù)點(diǎn)后的后綴表明庫函數(shù)的類型:

.a 指靜態(tài)鏈接庫.so 指動(dòng)態(tài)鏈接庫

去/usr/lib看一下,你會(huì)發(fā)現(xiàn),庫函數(shù)都有動(dòng)態(tài)和靜態(tài)兩個(gè)版本。

?

與頭文件一樣,庫函數(shù)通常放在標(biāo)準(zhǔn)位置,但我們也可以通過-L標(biāo)識(shí)符,來添加新的搜索文件夾,-l指定特定的庫函數(shù)文件。比如

?

?$ gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11

?

上述命令就會(huì)在編譯期間,鏈接位于/usr/openwin/lib文件夾下的libX11函數(shù)庫,編譯生成x11fred。

?

靜態(tài)鏈接庫(Static Libraries)

?

最簡(jiǎn)單的函數(shù)庫就是一些函數(shù)的簡(jiǎn)單集合。調(diào)用庫函數(shù)中的函數(shù)時(shí),需要在調(diào)用函數(shù)中include定義庫函數(shù)的頭文件。我們用-l選項(xiàng)添加標(biāo)準(zhǔn)函數(shù)庫之外的函數(shù)庫。

總結(jié)

以上是生活随笔為你收集整理的在Linux中创建静态库.a和动态库.so的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。