linux動態鏈接庫


前言

靜態鏈接庫會編譯進可執行文件,並被加載到內存,會造成空間浪費

靜態鏈接庫對程序的更新、部署、發布帶來麻煩。如果靜態庫更新了,使用它的應用程序都需要重新編譯、發布給用戶(對於玩家來說,可能是一個很小的改動,卻導致整個程序重新下載,全量更新)

動態庫在程序編譯時並不會被鏈接到目標代碼中,而是在執行文件中記錄對動態庫的引用,在程序運行時才被載入。不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例,規避了空間浪費問題。動態庫在程序運行時才被載入,也解決了靜態庫對程序的更新、部署和發布帶來的麻煩,用戶只需要更新動態庫即可,增量更新。

Linux下動態庫文件的文件名形如 libxxx.so,其中so是 Shared Object 的縮寫,即可以共享的目標文件。

特點

  • 動態庫把對一些庫函數的鏈接載入推遲到程序運行的時期
  • 可以實現進程之間的資源共享。(因此動態庫也稱為共享庫)
  • 將一些程序升級變得簡單。
  • 甚至可以真正做到鏈接載入完全由程序員在程序代碼中控制(顯示調用)

生成動態鏈接庫

  1. 編寫源文件
  2. 將一個或幾個源文件編譯鏈接,生成共享庫。
  3. 通過 -L<path> -lxxx 的gcc選項鏈接生成的libxxx.so。
  4. 把 libxxx.so 放入鏈接庫的標准路徑,或指定 LD_LIBRARY_PATH,才能運行鏈接了libxxx.so的程序。

例子

源文件

add.c

int add(int a, int b) { return a + b; }

subtract.c

int subtract(int a, int b) { return a - b; }

編譯

gcc -fPIC -c add.c gcc -fPIC -c subtract.c

其中,PIC是 Position Independent Code 的縮寫,表示要生成位置無關的代碼,這是動態庫需要的特性

鏈接

gcc -shared -o libmymath.so subtract.o add.o

-shared是鏈接選項,告訴gcc生成動態庫而不是可執行文件

這兩步可以合並成一個命令:

gcc -o libmymath.so -fPIC -shared subtract.c add.c

編寫頭文件

#ifndef _MYMATH_H_ #define _MYMATH_H_

int add(int, int); int subtract(int, int); #endif

使用鏈接庫

main.c

#include <stdio.h> #include "mymath.h"


int main() { printf("%d, %d\n", add(2, 3), subtract(9, 8)); return 0; }

鏈接

gcc main.c -L. -lmymath

如果同一目錄下同時存在同名的動態庫和靜態庫,比如 libmymath.so 和 libmymath.a 都在當前路徑下,則gcc會優先鏈接動態庫。

運行

當執行 ./a.out,發現程序報錯

./a.out: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory

這涉及到程序如何定位共享庫文件

  1. 當系統加載可執行代碼時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑。此時就需要系統動態載入器(dynamic linker/loader)
  2. 對於elf格式的可執行程序,是由ld-linux.so*來完成的,它先后搜索elf文件的 DT_RPATH段 -- 環境變量LD_LIBRARY_PATH -- /etc/ld.so.cache文件列表 -- /lib/,/usr/lib 目錄找到庫文件后將其載入內存。

/etc/ld.so.cache 是 ldconfig 程序讀取 /etc/ld.so.conf 文件生成的

所以,我們想讓程序找到自己寫的動態鏈接庫,有如下方法:

  • 指定 LD_LIBRARY_PATH 環境變量為 libmymath.so 文件所在的目錄
  • 編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑; 同時,運行ldconfig ,該命令會重建/etc/ld.so.cache文件
  • 把 libmymath.so 拷貝到/lib或者/usr/lib下,那么ld默認能夠找到,無需其他操作

我們可以執行:

 

LD_LIBRARY_PATH=. ./a.out

 

Makefile

.PHONY: all all: build target build: libmymath.so libmymath.so: add.o subtract.o gcc -o $@ -shared $^ add.o: add.c gcc -c -fPIC $< subtract.o: subtract.c gcc -c -fPIC $< target: a.out a.out: main.c gcc main.c -L. -lmymath .PHONY: clean clean: rm *.o a.out libmymath.so

 


免責聲明!

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



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