最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

linux使用gcc編譯c語言共享庫步驟

 更新時間:2014年01月21日 11:13:11   作者:  
這篇文章主要介紹了在linux中使用gcc編譯c語言共享庫的步驟,大家參考使用吧

對任何程序員來說庫都是必不可少的。所謂的庫是指已經(jīng)編譯好的供你使用的代碼。它們常常提供一些通用功能,例如鏈表和二叉樹可以用來保存任何數(shù)據(jù),或者是一個特定的功能例如一個數(shù)據(jù)庫服務器的接口,就像MySQL。

大部分大型的軟件項目都會包含若干組件,其中一些你發(fā)現(xiàn)可以用在其他項目中,又或者你僅僅出于組織目的將不同組件分離出來。當你有一套可復用的并且邏輯清晰的函數(shù)時,將其構建為一個庫會十分有用,這樣你就不將這些源代碼拷貝到你的源代碼中,而且每次都要再次編譯它們。除此之外,你還可以保證你的程序各模塊隔離,這樣你修改其中一個模塊時也不會影響到其他的模塊。一旦你寫好一個模塊并且通過測試,你就可以無限次地安全地復用它,這可以節(jié)省大量時間和麻煩。
構建靜態(tài)庫太簡單了,對此我們幾乎不會遇到什么問題。我不想說明如何構建靜態(tài)庫。在此我只討論共享庫,因為對大多數(shù)人來說它更加難懂。

在我們正式開始前,讓我們列一下綱要來了解從源代碼到運行程序之間發(fā)生了什么:

預處理:這個階段處理所有預處理指令?;旧暇褪窃创a中所有以#開始的行,例如#define和#include。
編譯:一旦源文件預處理完畢,接下來就是編譯。因為許多人提到編譯時都是指整個程序構建過程,因此本步驟也稱作“compilation proper”。本步驟將.c文件轉換為.o文件。
連接:到這一步就該將你所有的對象文件和庫串聯(lián)起來使之成為最后的可運行程序。需要注意的是,靜態(tài)庫實際上已經(jīng)植入到你的程序中,而共享庫,只是在程序中包含了對它們的引用?,F(xiàn)在你有了一個完整的程序,隨時可以運行。當你從shell中啟動它,它就被傳遞給了加載器。
加載:本步驟發(fā)生在你的程序啟動時。首先程序需要被掃描以便引用共享庫。程序中所有被發(fā)現(xiàn)的引用都立即生效,對應的庫也被映射到程序。
 

第3步和第4步就是共享庫的奧秘所在。

現(xiàn)在,開始我們一個簡單的示例。

foo.h:

復制代碼 代碼如下:

 #ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif  // foo_h__


foo.c:
復制代碼 代碼如下:

#include <stdio.h>

void foo(void)
{
    puts("Hello, I'm a shared library");
}

main.c:

復制代碼 代碼如下:

#include <stdio.h>
#include "foo.h"

int main(void)
{
    puts("This is a shared library test...");
    foo();
    return 0;
}
 

oo.h 定義了一個接口連接我們的庫,一個簡單的函數(shù),foo()。foo.c包含了這個函數(shù)的實現(xiàn),main.c是一個用到我們庫的驅動程序。

為了更好的演示本例子,所有代碼都放在/home/username/foo目錄下。

Step 1: 編譯無約束位代碼

我們需要把我們庫的源文件編譯成無約束位代碼。無約束位代碼是存儲在主內存中的機器碼,執(zhí)行的時候與絕對地址無關。

復制代碼 代碼如下:

$ gcc -c -Wall -Werror -fpic foo.c
 

Step 2: 從一個對象文件創(chuàng)建共享庫

現(xiàn)在讓我們將對象文件變成共享庫。我們將其命名為libfoo.so:

復制代碼 代碼如下:

$ gcc -shared -o libfoo.so foo.o

Step 3: 連接共享庫

如你所見,一切都很簡單。我們現(xiàn)在有了一個共享庫?,F(xiàn)在我們編譯我們的main.c并且將它連接到libfoo。我們將最終的運行程序命名為test。注意:-lfoo選項并不是搜尋foo.o,而是libfoo.so。GCC編譯器會假定所有的庫都是以lib開頭,以.so或.a結尾(.so是指shared object共享對象或者shared libraries共享庫,.a是指archive檔案,或者靜態(tài)連接庫)。

復制代碼 代碼如下:

$ gcc -Wall -o test main.c -lfoo
/usr/bin/ld: cannot find -lfoo
collect2: ld returned 1 exit status

告訴GCC去哪找共享庫

Uh-oh!連接器不知道該去哪里找到libfoo。GCC有一個默認的搜索列表,但我們的目錄并不在那個列表當中。我們需要告訴GCC去哪里找到libfoo.so。這就要用到-L選項。在本例中,我們將使用當前目錄/home/username/foo:

復制代碼 代碼如下:

$ gcc -L/home/username/foo -Wall -o test main.c -lfoo

Step 4: 運行時使用庫

好的,沒有異常。讓我們運行一下程序:

復制代碼 代碼如下:

$ ./test
./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

Oh no! 加載器不能找到共享庫。我們沒有將它安裝到標準位置,因此我們需要幫一幫加載器。我們有兩個選項:使用環(huán)境變量LD_LIBRARY_PATH或者rpath。讓我們先看看LD_LIBRARY_PATH:

使用LD_LIBRARY_PATH

復制代碼 代碼如下:

$ echo $LD_LIBRARY_PATH
 

目前什么都沒有。現(xiàn)在把我們的工作目錄添加到LD_LIBRARY_PATH中:

復制代碼 代碼如下:

$ LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH
$ ./test
./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

為什么還報錯?雖然我們的目錄在LD_LIBRARY_PATH,但是我們還沒有導出它。在Linux中,如果你不將修改導出到一個環(huán)境變量,這些修改是不會被子進程繼承的。加載器和我們的測試程序沒有繼承我們所做的修改,不過放心,要修復這個問題很簡單:

復制代碼 代碼如下:

$ export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH
$ ./test
This is a shared library test...
Hello, I'm a shared library

很好,運行正常!LD_LIBRARY_PATH很適合做快速測試,尤其是那些你沒有管理員權限的系統(tǒng)。另一方面,導出LD_LIBRARY_PATH變量意味著可能會造成其他依賴LD_LIBRARY_PATH的程序出現(xiàn)問題,因此在做完測試后最好將LD_LIBRARY_PATH恢復成之前的樣子。

使用rpath

現(xiàn)在讓我們來試試rpath,首先需要清除LD_LIBRARY_PATH,確保我們是使用rpath來搜索庫文件。Rpath,或者稱為run path,是種可以將共享庫位置嵌入程序中的方法,從而不用依賴于默認位置和環(huán)境變量。我們在連接環(huán)節(jié)使用rpath。注意“-Wl,-rpath=/home/username/foo”選項。-Wl會發(fā)送以逗號分隔的選項到連接器,因此我們通過它發(fā)送-rpath選項到連接器。(譯者按:逗號分隔符后面沒有空格,而是緊跟需要發(fā)送的選項。本例中為-rpath。一定注意"-Wl,-rpath"之間沒有空格。)

復制代碼 代碼如下:

$ unset LD_LIBRARY_PATH
$ gcc -L/home/username/foo -Wl,-rpath=/home/username/foo -Wall -o test main.c -lfoo
$ ./test
This is a shared library test...
Hello, I'm a shared library

非常好,奏效了。rpath方法非常棒,因為每個程序都可以單獨羅列它自己的共享庫位置,因此不同的程序不會再在錯誤的路徑上搜索LD_LIBRARY_PATH。

rpath和LD_LIBRARY_PATH

rpath也存在一些反作用面。首先,它要求共享庫必須安裝在一個固定的位置,這樣所有的用戶才可以在同一個位置訪問到庫。這就意味著在系統(tǒng)配置中不夠靈活。其次,如果庫涉及NFS掛載或者其他網(wǎng)絡驅動,你在啟動程序時會遇到延時或者更糟的情況。

使用ldconfig修改ld.so

如果我們想讓系統(tǒng)上所有用戶都可以使用我的庫時該怎么辦?對此,你需要管理員權限。緣由有二:首先,將庫放到標準位置,很可能是/usr/lib或者/usr/local/lib,這些地方普通用戶是沒有寫的權限。其次,你需要修改ld.so配置文件并緩存。以root身份做一下操作:

復制代碼 代碼如下:

$ cp /home/username/foo/libfoo.so /usr/lib
$ chmod 0755 /usr/lib/libfoo.so

現(xiàn)在文件在標準位置,對所有人都可讀。我們現(xiàn)在需要告訴加載器庫文件可用,因此讓我們更新一下緩存:

復制代碼 代碼如下:

$ ldconfig

這將創(chuàng)建一個鏈接到我們的共享庫,并且更新緩存以便它可立即生效。讓我們再核實一下:

復制代碼 代碼如下:

$ ldconfig -p | grep foo
libfoo.so (libc6) => /usr/lib/libfoo.so

現(xiàn)在我們的庫安裝好了,在我們開始測試它之前,我們一定要先清理一下其他東西:

以防萬一,先清理一下LD_LIBRARY_PATH:

復制代碼 代碼如下:

$ unset LD_LIBRARY_PATH

重新連接我們的可執(zhí)行程序。注意:我們不需要-L選項,因為我們的庫保存在默認位置,我們可以不用rpath選項:

復制代碼 代碼如下:

$ gcc -Wall -o test main.c -lfoo
 

讓我們確認一下我們將使用/usr/lib中我們庫的實例,使用ldd命令:

復制代碼 代碼如下:

$ ldd test | grep foo
libfoo.so => /usr/lib/libfoo.so (0x00a42000)
 

很好,現(xiàn)在運行一下程序吧:

復制代碼 代碼如下:

$ ./test
This is a shared library test...
Hello, I'm a shared library
 

以上就是所有內容。我們講述了如何構建一個共享庫,如何連接,如果解決最常見的共享庫加載問題,還有各種方法的優(yōu)劣性。

附:

1. Shared Libraries(共享庫) 和 Static Libraries(靜態(tài)庫)區(qū)別

共享庫是以.so(Windows平臺為.dll,OS X平臺為.dylib)作為后綴的文件。所有和庫有關的代碼都在這一個文件中,程序在運行時引用它。使用共享庫的程序只會引用共享庫中它要用到的那段代碼。

靜態(tài)庫是以.a(Windows平臺為.lib)作為后綴的文件。所有和庫有關的代碼都在這一個文件中,靜態(tài)庫在編譯時就被直接鏈接到了程序中。使用靜態(tài)庫的程序從靜態(tài)庫拷貝它要使用的代碼到自身當中。(Windows還有一種.lib文件是用來引用.dll文件,但其實它們和第一種情況是一樣的。)

兩種庫各有千秋。

使用共享庫可以減少程序中重復代碼的數(shù)量,讓程序體積更小。而且讓你可以用一個功能相同的對象來替換共享對象,這樣可以在增加性能的同時不用重新編譯那些使用到該庫的程序。但是使用共享庫會小額增加函數(shù)的執(zhí)行的成本,同樣還會增加運行時的加載成本,因為共享庫中的符號需要關聯(lián)到它們使用的東西上。共享庫可以在運行時加載到程序中,這是二進制插件系統(tǒng)最通用的一種實現(xiàn)機制。

靜態(tài)庫總體上增加了程序體積,但它也意味著你無需隨時隨地都攜帶一份要用到的庫的拷貝。因為代碼在編譯時就已經(jīng)被關聯(lián)在一起,因此在運行時沒有額外的消耗。

2. GCC首先在/usr/local/lib搜索庫文件,其次在/usr/lib,然后搜索-L參數(shù)指定路徑,搜索順序和-L參數(shù)給出路徑的順序一致。

3. 默認的GNU加載器ld.so,按以下順序搜索庫文件:

首先搜索程序中DT_RPATH區(qū)域,除非還有DT_RUNPATH區(qū)域。
其次搜索LD_LIBRARY_PATH。如果程序是setuid/setgid,出于安全考慮會跳過這步。
搜索DT_RUNPATH區(qū)域,除非程序是setuid/setgid。
搜索緩存文件/etc/ld/so/cache(停用該步請使用'-z nodeflib'加載器參數(shù))
搜索默認目錄/lib,然后/usr/lib(停用該步請使用'-z nodeflib'加載器參數(shù))

相關文章

  • C語言實現(xiàn)學生信息管理系統(tǒng)(單鏈表)

    C語言實現(xiàn)學生信息管理系統(tǒng)(單鏈表)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)學生信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++迭代器失效問題及解決

    C++迭代器失效問題及解決

    這篇文章主要介紹了C++迭代器失效問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C++解析特殊符號tab和換行符號詳情

    C++解析特殊符號tab和換行符號詳情

    這篇文章主要給大家介紹的是C++解析一些特殊符號tab、換行符號的一些相關資料,需要的小伙伴可以參考下面文章的具體內容
    2021-09-09
  • C/C++浮點數(shù)使用的兩個注意事項詳解

    C/C++浮點數(shù)使用的兩個注意事項詳解

    浮點數(shù)都是有符號的,沒有 unsigned 浮點數(shù),下面這篇文章主要給大家介紹了關于C/C++浮點數(shù)使用的兩個注意事項,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • c++關鍵字mutable深入解析

    c++關鍵字mutable深入解析

    先說用法,mutable關鍵字只能修飾非靜態(tài)以及非常量成員變量,使用mutable修飾的成員變量在const函數(shù)中的值是可以修改的
    2013-09-09
  • C++ OpenCV模擬實現(xiàn)微信跳一跳

    C++ OpenCV模擬實現(xiàn)微信跳一跳

    這篇文章主要介紹了使用C++和OpenCV模擬實現(xiàn)微信跳一跳功能,本文圖文并茂通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • 手把手教你如何一眼分辨是C還是C++

    手把手教你如何一眼分辨是C還是C++

    在很大程度上,C++是C的超集,這意味著一個有效的C程序也是一個有效的C++程序,下面這篇文章主要給大家介紹了關于如何一眼分辨是C還是C++的相關資料,需要的朋友可以參考下
    2023-02-02
  • 利用C++求解八數(shù)碼問題實例代碼

    利用C++求解八數(shù)碼問題實例代碼

    所謂八數(shù)碼問題是指這樣一種游戲,將分別標有數(shù)字1,2,3,…,8的八塊正方形數(shù)碼牌任意地放在一塊3×3的數(shù)碼盤上,放牌時要求不能重疊,下面這篇文章主要給大家介紹了關于利用C++求解八數(shù)碼問題的相關資料,需要的朋友可以參考下
    2022-11-11
  • C語言練習題:求1到10的階乘之和簡單實例

    C語言練習題:求1到10的階乘之和簡單實例

    下面小編就為大家?guī)硪黄狢語言練習題:求1到10的階乘之和簡單實例。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • C語言實現(xiàn)堆排序的簡單實例

    C語言實現(xiàn)堆排序的簡單實例

    這篇文章主要介紹了C語言實現(xiàn)堆排序的簡單實例,講述了堆排序的原理,需要的朋友可以參考下
    2014-07-07

最新評論

拜泉县| 峨边| 宜川县| 唐海县| 广水市| 宝应县| 长乐市| 图木舒克市| 广元市| 惠东县| 嫩江县| 息烽县| 原平市| 西乌珠穆沁旗| 阿克| 都安| 上犹县| 临沭县| 越西县| 江门市| 临泉县| 铜川市| 彭阳县| 博客| 岐山县| 江达县| 惠水县| 平度市| 宁国市| 安康市| 蕉岭县| 揭西县| 平顺县| 独山县| 海阳市| 睢宁县| 鹤庆县| 明光市| 达拉特旗| 都兰县| 石狮市|