靜態編譯
常規編譯示例:
$gcc xxx.c yyy.c zzz.c -o rslt
注明: gcc編譯器會對源文件min.c進行預處理, 編譯, 以及鏈接, 最后生成可執行文件
$gcc -c xxx.c yyy.c zzz.c
注明:gcc編譯器會對源文件min.c進行預處理, 編譯, 不進行鏈接, 最后生成的是object file (目標文件)
鏈接操作示例:
$ar rs libstack.a stack.o push.o pop.o is_empty.o
ar命令類似於tar命令,起一個打包的作用,但是把目標文件打包成靜態庫只能用ar命令而不能用tar命令。選項r表示將后面的文件列表添加到文件包,如果文件包不存在就創建它,如果文件包中已有同名文件就替換成新的。s是專用於生成靜態庫的,表示為靜態庫創建索引,這個索引被鏈接器使用。ranlib命令也可以為靜態庫創建索引,以上命令等價於:
$ ar r libstack.a stack.o push.o pop.o is_empty.o
$ ranlib libstack.a
最后編譯demo時鏈接靜態庫:
$gcc main.c -L. -lstack -Istack -o main
符號注明:-I 頭文件目錄 -L庫目錄 -l鏈接庫名稱
鏈接動態庫和靜態庫優先級說明:編譯器會首先找有沒有共享庫libstack.so,如果有就鏈接它,如果沒有就找有沒有靜態庫libstack.a,如果有就鏈接它。所以編譯器是優先考慮共享庫的,如果希望編譯器只鏈接靜態庫,可以指定-static選項。
動態編譯
組成共享庫的目標文件和一般的目標文件有所不同,在編譯時要加-fPIC和-share選項,例如:
$gcc -fPIC -shared testa.c testb.c testc.c -o libtest.so
-f后面跟一些編譯選項,PIC是其中一種,表示生成位置無關代碼(Position Independent Code)。
-shared該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標志外部程序無法連接。相當於一個可執行文件
-fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯后的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。
最后編譯demo時鏈接動態庫,和靜態庫鏈接一樣:
$gcc main.c -L. -lstack -Istack -o main
如果運行main找不到*.so時候,使用ldd命令查看鏈接庫。
動態庫目錄搜索優先級:
我們知道一個程序要想在內存中運行,除了編譯之外還要經過鏈接和裝入這兩個步驟。當然linux中動態鏈接也是經過這三個過程。Linux 使用這個ld-linux.so*中的來裝載(其實這只是一個鏈接)其他庫。所以這個庫必須放在linux中/lib下。對於其他,通常我們共享庫放在/lib這個路徑下,而且也是系統默認的搜索路徑。
Linux共享庫的搜索路徑先后順序:
1、編譯目標代碼時指定的動態庫搜索路徑:在編譯的時候指定-Wl,-rpath=路徑
2、環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑
3、配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
4、默認的動態庫搜索路徑/lib
5、默認的動態庫搜索路徑 /usr/lib
臨時設置2的命令是:export LD_LIBRARY_PATH=.