庫文件的存在極大的提升了 C/C++ 程序的複用性,本文簡單介紹如何生成、使用它們。html
命名約定: 咱們通常對庫文件約定以 lib
開頭,動態庫文件通常以 .so
(*nix)或 .dll
(Windows) 結尾,靜態庫文件通常以 .a
(*nix)或 .lib
(Windows) 結尾。linux
動態庫還分爲兩種用法:架構
下面咱們以 Linux 爲例,Windows 的用法與此有所不一樣,但思路大同小異。函數
將庫源碼編譯成目標文件:工具
$ gcc -c struct.c [-o struct.o]
打包庫文件:.net
$ ar cr libstruct.a struct.o # 注意參數順序不能錯
這裏的 ar
和 tar
相似,是一種打包工具。插件
可使用 $ ar -t libstruct.a
命令 檢查包含哪些 .o
文件。設計
構建符號表:code
$ ranlib libstruct.a
這個命令不是必須的,是由於部分 ar
的實現集成了該功能,此時的 ranlib
就是一個空殼命令。htm
連接靜態庫,生成可執行文件:
$ gcc main.c -static -L . -lstruct -o main
由於咱們約定庫文件以 lib
開頭,因此這裏能夠省掉它。
設置庫文件的環境路徑:
LD_LIBRARY_PATH
環境變量,添加動態庫文件的路徑。ld.so.conf
文件中,而後用 ldconfig
加載。ldconfig <path-to-so-directory>
臨時加載。編譯時,若是出現重名的動態庫和靜態庫,優先使用動態庫。
編譯動態連接庫文件:
$ gcc -shared -fPIC struct.c -o libstruct.so
這其實融合了好幾條命令,但咱們不作細述。
-fPIC
表示編譯爲「地址無關」的代碼,用於編譯共享庫。若是不加 -fPIC
則加載 so 文件的代碼段時,代碼段引用的數據對象須要重定位,重定位會修改代碼段的內容,這就形成每一個使用這個 so 文件代碼段的進程在內核裏都會生成這個 so 文件代碼段的副本。
通常老是用 -fPIC
來生成 .so
文件,也歷來不用fPIC來生成 .a
文件。
通常如下幾種狀況不須要:
連接動態庫,生成可執行文件:
$ gcc main.c -L . lstruct -o main
通常咱們習慣將動態連接庫放入系統庫目錄:
$ gcc -shared -Wl,-soname,libstruct.so.1 -o libstruct.so.1 *.o
其中 -Wl
前綴的命令會傳遞給 ld
命令。咱們以前說過,gcc
融合了多條命令。
也就是在連接 .o
文件時會執行:
$ ld -soname libstruct.so.1
libstruct.so
用於在編譯期間使用 -lstruct
找到動態庫,而 libstruct.so.1
則在運行期間真正被連接。
$ mv libstruct.so.1 /opt/lib $ ln -sf /opt/lib/libstruct.so.1 /opt/lib/libstruct.so.1 $ ln -sf /opt/lib/libstruct.so.1 /opt/lib/libstruct.so
$ ldd main libstruct.so.1 => /opt/lib/libstruct.so.1 (0x00002aaaaaaac000) libc.so.6 => /lib64/tls/libc.so.6 (0x0000003aa4e00000) /lib64/ld-linux-x86-64.so.2 (0x0000003aa4c00000)
obj 文件的格式和組成多是系統差別性的一大致現,好比 Windows 下的 PE、Linux 和部分 Unix 下的 elf、Mac OS 下的 mach-o、aix 下的 xcoff。
使用 nm
、objdump
、readelf
等命令能夠查看 .o
.a
.so
文件中的符號信息。
好比,下面這將打印出 hello.o 中未定義的符號:
$ nm -u hello.o
須要應用程序但願設計成插件化的架構,這就須要能夠動態加載和卸載庫的機制。與動態連接不一樣的是,動態加載的意思是,編譯期間能夠對動態庫的存在一無所知,而是在運行期間經過用戶程序嘗試加載進來的。
經過 dlfcn.h
中的 dlopen
、dlsym
、dlclose
等函數實現此種功能。
另外,使用 dlfcn
機制須要在連接時使用 -rdynamic
選項,它將指示鏈接器把全部符號(而不只僅只是程序已使用到的外部符號,但不包括靜態符號,好比被 static 修飾的函數)都添加到動態符號表(即 .dynsym
表)裏。
現在許多軟件的編譯都採用 libtool
工具,libtool 是一個編譯連接包裝工具,實際只是一個腳本,用 libtool 編譯和連接會產生相似 .la
的文件,這種文件實際上是個文本文件,指向 .a
文件,並聲明一些版本信息。