g 鏈結 gcc 編譯的動態庫

2021-10-09 03:34:53 字數 4477 閱讀 4772

背景

需要在c++**的基礎上,連線上c語言編譯的動態庫。

方式一:將c檔案,使用g++編譯生成動態庫,然後在用g++連線到c++生成的目標檔案上。

可以編譯通過,但是在程式測試拷機中,出現異常退出。

方式二:使用gcc 編譯c檔案,生成動態庫,在c++**中新增c的標頭檔案時候,使用

extern "c" ;

然後再用g++把gcc 生成的動態庫連線到c++上,生成目標檔案。

無上述異常退出。

由此,仔細查詢了gcc和g++的區別和用法。

一:gcc與g++比較

編譯c/c++**的時候,有人用gcc,有人用g++,於是各種說法都來了,譬如c**用gcc,而 c++**用g++,或者說編譯用gcc,鏈結用g++,一時也不知哪個說法正確,如果再遇上個extern "c",分歧就更多了,這裡我想作個了結,畢竟知識的目的是令人更清醒,而不是更糊塗。

誤區一:gcc只能編譯c**,g++只能編譯c++**

兩者都可以,但是請注意:

1.字尾為.c的,gcc把它當作是c程式,而g++當作是c++程式;字尾為.cpp的,兩者都會認為是c++程式,注意,雖然c++是c的超集,但是兩者對語法的要求是有區別的,例如:

#include

int main(int argc, char* ar**)

int printstring(char* string)

如果按照c的語法規則,ok,沒問題,但是,一旦把字尾改為cpp,立刻報三個錯:「printstring未定義」;

「cannot convert `char**' to `char*」;

」return-statement with no value「;

分別對應前面紅色標註的部分。可見c++的語法規則更加嚴謹一些。

2.編譯階段,g++會呼叫gcc,對於c++**,兩者是等價的,但是因為gcc命令不能自動和c++程式使用的庫聯接,所以通常用g++來完成鏈結,為了統一起見,乾脆編譯/鏈結統統用g++了,這就給人一種錯覺,好像cpp程式只能用g++似的。

誤區二:gcc不會定義__cplusplus巨集,而g++會

實際上,這個巨集只是標誌著編譯器將會把**按c還是c++語法來解釋,如上所述,如果字尾為.c,並且採用gcc編譯器,則該巨集就是未定義的,否則,就是已定義。

誤區三:編譯只能用gcc,鏈結只能用g++

嚴格來說,這句話不算錯誤,但是它混淆了概念,應該這樣說:編譯可以用gcc/g++,而鏈結可以用g++或者gcc -lstdc++。因為gcc命令不能自動和c++程式使用的庫聯接,所以通常使用g++來完成聯接。但在編譯階段,g++會自動呼叫gcc,二者等價。

誤區四:extern "c"與gcc/g++有關係

實際上並無關係,無論是gcc還是g++,用extern "c"時,都是以c的命名方式來為symbol命名,否則,都以c++方式命名。試驗如下:

me.h:

extern "c" void cppprintf(void);

me.cpp:

#include

#include "me.h"

using namespace std;

void cppprintf(void)

test.cpp:

#include

#include

#include "me.h"       

int main(void)

1. 先給me.h加上extern "c",看用gcc和g++命名有什麼不同

[root@root g++]# g++ -s me.cpp

[root@root g++]# less me.s

.globl _z9cppprintfv        //注意此函式的命名

.type   cppprintf, @function

[root@root gcc]# gcc -s me.cpp

[root@root gcc]# less me.s

.globl _z9cppprintfv        //注意此函式的命名

.type   cppprintf, @function

完全相同!

2. 去掉me.h中extern "c",看用gcc和g++命名有什麼不同

[root@root gcc]# gcc -s me.cpp

[root@root gcc]# less me.s

.globl _z9cppprintfv        //注意此函式的命名

.type   _z9cppprintfv, @function

[root@root g++]# g++ -s me.cpp

[root@root g++]# less me.s

.globl _z9cppprintfv        //注意此函式的命名

.type   _z9cppprintfv, @function

完全相同!

【結論】完全相同,可見extern "c"與採用gcc/g++並無關係,以上的試驗還間接的印證了前面的說法:在編譯階段,g++是呼叫gcc的。

二:gcc和g++的包含標頭檔案庫檔案方法

-l引數就是用來指定程式要鏈結的庫,-l引數緊接著就是庫名,那麼庫名跟真正的庫檔名有什麼關係呢?就拿數學庫來說,他的庫名是m,他的庫檔名是libm.so,很容易看出,把庫檔名的頭lib和尾.so去掉就是庫名了。

好了現在我們知道怎麼得到庫名,當我們自已要用到乙個第三方提供的庫名字libtest.so,那麼我們只要把 libtest.so拷貝到/usr/lib裡,編譯時加上-ltest引數,我們就能用上libtest.so庫了(當然要用libtest.so庫里 的函式,我們還需要與libtest.so配套的標頭檔案)

放在/lib和/usr/lib和/usr/local/lib裡的庫直接用-l引數就能鏈結了,但如果庫檔案沒放 在這三個目錄裡,而是放在其他目錄裡,這時我們只用-l引數的話,鏈結還是會出錯,出錯資訊大概是:「/usr/bin/ld: cannot find -l***」,也就是鏈結程式ld在那3個目錄裡找不到lib***.so,這時另外乙個引數-l就派上用場了,比如常用的x11的庫,它在/usr /x11r6/lib目錄下,我們編譯時就要用-l/usr/x11r6/lib -lx11引數,-l引數跟著的是庫檔案所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈結引數就是-l /aaa/bbb/ccc -ltest

另外,大部分lib***x.so只是乙個鏈結,以rh9為例,比如libm.so它鏈結到/lib/libm.so.x,/lib/libm.so.6又鏈結到/lib/libm-2.3.2.so,

如果沒有這樣的鏈結,還是會出錯,因為ld只會找lib***x.so,所以如果你要用到***x庫,而只有lib***x.so.x或者lib***x-x.x.x.so,做乙個鏈結就可以了ln -s lib***x-x.x.x.so lib***x.so

手工來寫鏈結引數總是很麻煩的,還好很多庫開發包提供了生成鏈結引數的程式,名字一般叫***x-config,一般放在/usr/bin目錄下,比如

gtk1.2的鏈結引數生成程式是gtk-config,執行gtk-config --libs就能得到以下輸出"-l/usr/lib -l/usr/x11r6/lib -lgtk -lgdk -rdynamic

-lgmodule -lglib -ldl -lxi -lxext -lx11 -lm",這就是編譯乙個gtk1.2程式所需的gtk鏈結引數,***-config除了--libs引數外還有乙個引數是--cflags用來生成頭 檔案包含目錄的,也就是-i引數,在下面我們將會講到。你可以試試執行gtk-config --libs --cflags,看看輸出結果

現在的問題就是怎樣用這些輸出結果了,最笨的方法就是複製貼上或者照抄,聰明的辦法是在編譯命令列裡加入這個 `***x-config --libs --cflags`,比如編譯乙個gtk程式:gcc gtktest.c `gtk-config --libs --cflags`這樣就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。

5、-include和-i引數

-include用來包含標頭檔案,但一般情況下包含標頭檔案都在原始碼裡用#include ******實現,-include引數很少用。-i引數是用來指定頭檔案目錄,/usr/include目錄一般是不用指定的,gcc知道去那裡找,但 是如果標頭檔案不在/usr/include裡我們就要用-i引數指定了,比如標頭檔案放在/myinclude目錄裡,那編譯命令列就要加上-i /myinclude引數了,如果不加你會得到乙個"***x.h: no such file or directory"的錯誤。-i引數可以用相對路徑,比如標頭檔案在當前目錄,可以用-i.來指定。

結論例子:

g++ curltest.cpp -o curltest -l/mnt/hgfs/windows/curl-7.19.5/lib/.libs -lcurl -i/mnt/hgfs/windows/curl-7.19.5/include

GCC 編譯使用動態鏈結庫

動態鏈結庫 1.建立動態鏈結庫 複製 如下 include void hello 用命令gcc shared hello.c o libhello.so編譯為動態庫。可以看到,當前目錄下多了乙個檔案libhello.so。2.再編輯乙個測試檔案test.c,內容如下 複製 如下 include in...

linux下 GCC編譯鏈結靜態庫 動態庫

目錄 回到頂部 有時候需要把一組 編譯成乙個庫,這個庫在很多專案中都要用到,例如libc就是這樣乙個庫,我們在不同的程式中都會用到libc中的庫函式 例如printf 也會用到libc中的變數 例如以後 要講到的environ變數 本文將介紹怎麼建立這樣乙個庫。這些檔案的目錄結構是 tree mai...

G 編譯 動態鏈結庫的鏈結與使用

今天在寫v8的demo時出現了乙個問題,根據v8 document的命令 g iinclude hello world.cpp o hello world libv8.a lpthread 無法編譯和鏈結成功,試了半天,搞清楚了些東西。編譯時 i 告訴編譯器在指定資料夾搜尋標頭檔案 l 會解析成li...