gcc/g++ 動態編譯和鏈接問題


-l參數和-L參數:
-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 -lxxx”,也就是鏈接程序ld在那3個目錄里找不到libxxx.so,這時另外一個參數-L就派上用場了,比如常用的X11的庫,它在/usr /X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數,-L參數跟着的是庫文件所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數就是-L /aaa/bbb/ccc -ltest。
另外,大部分libxxxx.so只是一個鏈接,以RH9為例,比如libm.so它鏈接到/lib/libm.so.x,/lib/libm.so.6又鏈接到/lib/libm-2.3.2.so,如果沒有這樣的鏈接,還是會出錯,因為ld只會找libxxxx.so,所以如果你要用到xxxx庫,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一個鏈接就可以了ln -s libxxxx-x.x.x.so libxxxx.so。
手工來寫鏈接參數總是很麻煩的,還好很多庫開發包提供了生成鏈接參數的程序,名字一般叫xxxx-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鏈接參數,xxx-config除了--libs參數外還有一個參數是--cflags用來生成頭文件包含目錄的,也就是-I參數,在下面我們將會講到。你可以試試執行gtk-config --libs --cflags,看看輸出結果。
現在的問題就是怎樣用這些輸出結果了,最笨的方法就是復制粘貼或者照抄,聰明的辦法是在編譯命令行里加入這個`xxxx-config --libs --cflags`,比如編譯一個gtk程序:gcc gtktest.c `gtk-config --libs --cflags`這樣就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。


-include和-I參數:

-include用來包含頭文件,但一般情況下包含頭文件都在源碼里用#include xxxxxx實現,-include參數很少用。-I參數是用來指定頭文件目錄,/usr/include目錄一般是不用指定的,gcc知道去那里找,但是如果頭文件不在/usr/include里我們就要用-I參數指定了,比如頭文件放在/myinclude目錄里,那編譯命令行就要加上-I/myinclude參數了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I參數可以用相對路徑,比如頭文件在當前目錄,可以用-I.來指定。


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

GCC靜態鏈接與動態鏈接  

寫在前面:最近因為需要在不同版本的linux上運行編譯后的文件,經常會遇到找不到需要的鏈接庫文件的問題,后來突然想起了靜態編譯這一說。

1:建靜態庫

/*  hellos.h  */

#ifndef _HELLO_S_H

#define _HELLO_S_H

void printS(char* str);

#endif

/*  hellos.c  */

#include "hellos.h"

void printS(char* str)

{

    printf("print in static way: %s", str);

}

輸入命令:

gcc -c -o hellos.o hellos.c

ar cqs libhellos.a hellos.o      //ar是生成庫的命令,cqs是參數, libhellos.a是生成的靜態鏈接庫須以lib開頭,hellos是庫名,a表示是靜態鏈接庫,hellos.o是剛才生成目標文件。於是得到了libhellos.a這么一個靜態鏈接庫

 

2:主程序

/*  main.c  */

#include <stdio.h>

#include "hellos.h"

 

main()

{

    char* text = "Hello World!\n";

    printS(text);

}

 

編譯鏈接:

gcc -o hello main.c -static -L. –lhellos

下面是關於上面命令的解釋:

庫依賴

使用-I參數可以向gcc的頭文件搜索路徑中添加新目錄。

gcc hello.c -I /home/wuzhiguo/include -o hello

使用-L參數可以向gcc的庫文件搜索路徑中添加新目錄。

gcc hello.c -L /home/wuzhiguo/lib -l mylib -o hello

-l mylib 是指示gcc去鏈接庫文件libmylib.soLinux下的庫文件有一個約定,全部以lib開頭,因此可以省去lib

動態庫:.so結尾,在運行時加載。

靜態庫:.a結尾,在編譯時加載。

默認gcc優先加載動態庫,可以在通過-static選項強制使用靜態鏈接庫。

gcc hello.c -L /home/wuzhiguo/lib -static -l mylib -o hello

       所以-L后面的點為當前目錄,-l后面是要靜態連接的庫(libhellos.a

 

然后運行hello可以看到輸出

print in static way: Hello World!

刪除libhellos.ahellos.*, 程序仍然正常運行。

 

下面再來看動態鏈接

3:建動態庫

/*  hellod.h  */

#ifndef _HELLO_D_H

#define _HELLO_D_H

void printD(char* str);

#endif

/*  hellod.c  */

#include "hellod.h"

void printD(char* str)

{

    printf("print in dynamic way: %s", str);

}

輸入命令:

gcc -shared -o libhellod.so hellod.c

於是得到了libhellod.so這么一個動態鏈接庫,然后復制到/lib目錄中,否則運行的時候找不到庫文件。

 

4:主程序

/*  main.c  */

#include <stdio.h>

#include "hellod.h"

main()

{

    char* text = "Hello World!\n";

    printD(text);

}

 

編譯鏈接:

gcc -o hello main.c -L. -lhellod

然后運行hello可以看到輸出

print in dynamic way: Hello World!

如果這時候刪除剛剛生成的hellod.dll,再運行則會報告一個找不到hellod.dll的錯誤,程序無法正常運行。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM