(C/C++) 如何在Linux上編譯與使用 static /shared library#
Demo project#
LinkLoadDemo這個Project總共包含了6個projects以及一個資料夾
Project_StaticLib模擬建立一個static libraryProject_LinkStaticLib模擬使用static libraryProject_SharedLib模擬建立一個shared libraryProject_LinkSharedLib模擬使用shared libraryProject_SharedLibForDynamicLoad模擬建立一個shared libraryProject_LoadSharedLib模擬動態載入一個shared librarySharedLib為佈署shared library的路徑
Static Linking#
Static Linking 特點#
通常是以
.a(Unix-like) 或.lib(Windows) 為副檔名編譯期將library的程式碼加入執行檔,因此執行檔size會較大與
library的source file之間的dependency相對較高,引用的library有更新時需要將程式重編譯才能得到更新過後的內容Deployment不需要處理其他程式,相對簡單library的程式會被放到同一個
address space,所以執行速度會會稍微快一點。
建立 static library#
寫一個
header file (.h)作為library的API讓library使用者可以正確的呼叫屬於library的function將
source file編譯成object files將
object files打包成static library fileNote
static library檔名的固定格式為lib{library name}.a
Example: 建立 static library#
1# 編譯指令
2gcc src/prog1.c -c -o src/prog1.o
3gcc src/prog2.c -c -o src/prog2.o
4gcc src/prog3.c -c -o src/prog3.o
5# 打包指令, 打包出一個名為 staticlink 的 static library
6ar rcs libstaticlink.a src/prog1.o src/prog2.o src/prog3.o
使用static library#
佈署 static library#
將
static library檔案複製到佈署資料夾
使用 static library 編譯程式#
includelibrary的header file後呼叫要使用的function(通常會將.h放到include資料夾下)將程式編譯成執行檔時加上相關的參數
Note
-static用來指示若有同名的static library與shared library的話會優先使用static library (預設為優先使用shared library)-I {path}用來指示header file放置的路徑,-I與{path}中間可以不需要空格隔開-L {path}用來指示static library file放置的路徑,-L與{path}中間可以不需要空格隔開-l {library name}用來指示library name,-l與{library name}中間可以不需要空格隔開
Example: 使用 static library#
1# 佈署指令
2cp -r ../Project_StaticLib/include .
3cp ../Project_StaticLib/libstaticlink.a lib
4# 編譯指令
5gcc src/main.c -static -I include -L lib -l staticlink -o main
Dynamic Linking#
Dynamic Linking 特點#
通常是以
.so(Unix-like) 或.dll(Windows) 為副檔名編譯期並不將library的程式碼加入執行檔而是只留下一個stub,因此執行檔會比較小與library的
source file之間的dependency相對較低,引用的library有更新時只需要更新library即可得到更新過後的內容Deployment需要處理另外的設定,相對教複雜程式在啟動之前
dynamic linker會介入去把stub綁定到library function實際的位址。因為綁定的位址是受到OS管控的,因此會稍微
慢一點。library的程式由OS管控,只會載入一次。如果有多個程式會共用這個library的話則是透過OS間接取得這些
library function的reference。因此可節省系統資源。
建立 shared library#
寫一個
header file作為library的API讓library使用者可以正確的呼叫屬於library的function將
source file編譯成object files將
object files打包成shared library fileNote
version code: 代表大版本更動,可能造成與前面的版本不相容minor code: 代表有新增功能,但library有向前相容release code: 代表功能有變更,通常是bug修正或者是針對程式重構real name: 實際的檔案名稱,慣用格式為lib{library name}.so.{version code}.{minor code}.{release code}linker name: 要編譯執行檔時linker尋找library的檔案名稱,慣用格式為lib{library name}.soso name: 執行檔要啟動時linker尋找library的檔案名稱,慣用格式為lib{library name}.so.{version code}
指令講解
Note
-fPIC是用來提示compiler要將檔案編譯成position-independent code-shared是用來提示compiler要將檔案編譯成shared object-Wl,{option}是用來將option傳給linker的指令,要傳給linker的指令用逗點隔開-soname是linker的指令,用來提示當編譯好的執行檔啟動時,要用soname去找到shared library而不是使用real name去找,設定so name可以讓編譯與執行不使用同一個library進而增加程式的彈性
Example: 建立 shared library#
1# 編譯指令
2gcc src/prog1.c -c -fPIC -o src/prog1.o
3gcc src/prog2.c -c -fPIC -o src/prog2.o
4gcc src/prog3.c -c -fPIC -o src/prog3.o
5# 打包指令, 打包出一個名為 dynamiclink 的 dynamic library
6gcc src/prog1.o src/prog2.o src/prog3.o -shared -Wl,-soname,libdynamiclink.so.1 -o libdynamiclink.so.1.0.0
使用 shared library#
佈署 shared library#
將
shared library檔案複製到部署路徑資料夾下建立
linker name的soft link建立
so name的soft link如果佈署路徑不是系統預設資料夾則須使用下面任一種方法完成設置
(Optional) 使用環境變數
1export LD_LIBRARY_PATH=/path/to/shared/libs:$LD_LIBRARY_PATH
(Optional) 使用
ldconfig配置將佈署路徑加入到下面兩個選項其中之一
在
/etc/ld.so.conf.d/資料夾下面增加新的配置檔案(Ex:custom-libs.conf)直接修改
/etc/ld.so.conf檔
更新
ld.so.cache
1sudo ldconfig
啟動有使用 dynamic linking 的程式時尋找library路徑的順序#
環境變數
LD_LIBRARY_PATH用':'隔開的那些路徑/etc/ld.so.cache中指定的library列表/lib/usr/lib/usr/local/lib
使用 shared library 編譯程式#
include library的header file後呼叫要使用的function(通常會將
.h放到include資料夾下將程式編譯成執行檔時加上相關的參數
Note
-I {path}用來指示header file放置的路徑,-I與{path}中間可以不需要空格隔開-L {path}用來指示shared library file放置的路徑-L與{path}中間可以不需要空格隔開-l {library name}用來指示library name,-l與{library name}中間可以不需要空格隔開會依據
linker name去找library
Example: 使用 shared library#
1# 佈署指令, 將 dynamic library 佈署到 ../SharedLib 資料夾下並建立兩個對應的 soft link
2cp -r ../Project_SharedLib/include .
3mkdir -p ../SharedLib
4cp ../Project_SharedLib/libdynamiclink.so.1.0.0 ../SharedLib
5ln -fs ../SharedLib/libdynamiclink.so.1.0.0 ../SharedLib/libdynamiclink.so.1
6ln -fs ../SharedLib/libdynamiclink.so.1.0.0 ../SharedLib/libdynamiclink.so
7# 編譯程式
8gcc src/main.c -I include -L ../SharedLib -l dynamiclink -o main
9# 環境變數設定 & 執行編譯好的程式
10LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../SharedLib
11./main
Dynamic Loading#
Dynamic Loading 特點#
編譯時並不將library的內容連結,在執行期動態將library以
plug-in的方式載入與釋放,更具彈性。因為系統需要處理的工作更多,因此執行速度
更慢Dynamic Loading載入的程式可以是static library、shared library或執行檔。透過
dl這個library達成,用法參考檔案Project_LoadSharedLib/src/main.c可以不需要includelibrary的
header file,但是需要從header file或文件確定好要使用的function或變數的typedlopen的檔名如果以'/'開頭則會用絕對路徑去找,若不是以的話會依照啟動有使用 dynamic linking 的程式時尋找library路徑的順序的規則去尋找編譯指令有
-ldl的原因是因為需要用到dl這個library