歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

linux下動態庫的生成和鏈接

linux下動態庫的生成和鏈接(.so)
本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。
windows和linux下都存在庫,但不同。
靜態庫:.a 文件。靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。
動態庫:.so,也叫共享庫(shared object)。程序運行時的動態鏈接,多個進程可以鏈接同一個共享庫。動態庫在程序編譯時並不會被連接到目標代碼中,程序運行時被載入,因此在程序運行時還需要動態庫存在。
優點:一旦動態庫中的函數發生變化,對於可執行程序來說是透明的,可執行程序無需重新編譯。這對於程序的發布、維護、更新起到了積極的作用。
當靜態庫和動態庫同名時, gcc命令將優先使用動態庫
以後慢慢研究原理,先實現一個最簡單的庫鏈接。
LINUX下 so文件即為動態庫,類似於windows下的DLL。
作用:1、代碼復用,簡化代碼,節約資源
2、不同的應用程序如果調用相同的庫,那麼在內存裡只需要有一份該共享庫的實例
//test.h
#include <stdio.h>

int a();
int b();

//test.c
#include "test.h"

int a()
{
    printf("hello world\n");
    return 0;
}

int b()
{
    printf("welcome to China\n");
    return 0;
}

//main.c
#include "test.h"
int main()
{
    a();
    b();
    printf("program excute success\n");
    return 0;
}

編譯生成 libtest .so 文件,並通過鏈接庫編譯生成可執行文件 mm
gcc test.c -fPIC -shared -o libtest.so
gcc main.c -L. -ltest -o mm
-shared:該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標志外部程序無法連接。相當於一個可執行文件
-fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。
-L.:表示要連接的庫在當前目錄中
-ltest:編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來確定庫的名稱
LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑。
當然如果有root權限的話,可以修改/etc/ld.so.conf文件,然後調用 /sbin/ldconfig來達到同樣的目的,不過如果沒有root權限,那麼只能采用輸出LD_LIBRARY_PATH的方法了。
執行:./mm
./mm: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
執行出錯了,原因是操作系統無法找到庫。
查看一下依賴的庫:ldd mm
ldd mm
linux-vdso.so.1 => (0x00007fffc01ff000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0592b06000)
/lib64/ld-linux-x86-64.so.2 (0x00007f05930af000)
發現libtest.so並沒有鏈接進去
解決方法一:
1、將.so文件放入默認搜索路徑中。一般在:/etc/lib/.下
2、在多用戶環境下,一般我們不享有默認路徑寫入的權限。可以通過設置 LD_LIBRARY_PATH 環境變量解決:
export LD_LIBRARY_PATH=.
或者: export LD_LIBRARY_PATH=$(pwd)
這裡的意思是將當前文件添加為共享目錄。當然,後面的目錄可以自己手動輸入絕對路徑
按照這樣設置後,在執行可執行文件時,操作系統會先在LD_LIBRARY_PATH下搜索庫文件,搜索不到再去默認路徑中繼續搜索。
缺點:修改環境變量,會影響所有的可執行程序。如果我們在編譯其他程序時,如果我們不小心,很可能導致其他可執行文件無法運行。
解決方法二:提供 -rpath選項(runtime path)
將搜索路徑信息寫入可執行文件,不需要設置環境變量。
缺點:當庫文件移動時,需要重新編譯生成可執行文件。
編譯命令:
gcc -g -o mm main.c -ltest -L. -Wl,-rpath=.
-Wl(大寫的W,小寫的l)
-rpath選項是傳遞給連接器(linker),“.”表示當前目錄
ldd mm
linux-vdso.so.1 => (0x00007fffc01ff000)
libtest.so => /opt/code/xqf/dcs/src/linux_practice/libtest.so (0x00007f0592eac000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0592b06000)
/lib64/ld-linux-x86-64.so.2 (0x00007f05930af000)
執行:./mm
hello world
welcome to China
program excute success
成功!!
文件列表:ll
-rwxr-xr-x 1 root root 1936 Apr 20 08:31 libtest.a
-rwxr-xr-x 1 root root 8200 Apr 18 22:21 libxqf.so
-rwxr-xr-x 1 root root 105 Apr 18 22:19 main.c
-rwxr-xr-x 1 root root 136 Apr 18 22:19 test.c
-rwxr-xr-x 1 root root 38 Apr 18 19:41 test.h
-rwxr-xr-x 1 root root 1792 Apr 19 19:30 test.o
-rwxr-xr-x 1 root root 12410 Apr 18 22:24 mm
./mm & 表示在後台執行該可執行文件
幾點知識,參考資料:
靜態庫鏈接時搜索路徑順序:
1. ld會去找GCC命令中的參數-L
2. 再找gcc的環境變量LIBRARY_PATH
3. 再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程序內的
動態鏈接時、執行時搜索路徑順序:
1. 編譯目標代碼時指定的動態庫搜索路徑;
2. 環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑;
3. 配置文件/etc/ld.so.conf中指定的動態庫搜索路徑;
4. 默認的動態庫搜索路徑/lib, /usr/lib, /usr/local/lib
新安裝一個庫之後如何讓系統能夠找到它
如果安裝在/lib或者/usr/lib下,那麼ld默認能夠找到,無需其他操作。
如果安裝在其他目錄,需要將其添加到/etc/ld.so.cache文件中,步驟如下
1.編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑
2.運行ldconfig,該命令會重建/etc/ld.so.cache文件
編譯生成靜態庫:
gcc -c test.c 生成 test.o 文件
ar crv libtest.a test.o 創建靜態庫文件 libtest.a
gcc -o mm main.c -static -L. -ltest 生成可執行文件 mm
執行:./mm
hello world
welcome to China
program excute success
Copyright © Linux教程網 All Rights Reserved