Linux編程----動態庫、靜態庫

1. 庫是什麼

庫(library),在計算機軟件領域應該十分常見,從專業術語的角度來看,庫是具有某種特定功能的封裝好的模塊。通俗來說,庫是一堆函數的集合。那麼爲什麼需要庫呢?其實這是非常容易理解的,庫的作用和函數的功能都是相似的,都是爲了封裝好功能模塊,以便於代碼重用,避免重複造輪子,而庫和單純的函數是有區別的,庫屬於文件,函數屬於代碼!

舉一個例子,在hello.c文件中,使用 abs() 函數計算絕對值,我們應該通過 #include <math.h> 包含頭文件,與庫中的接口關聯起來,這樣子,在執行程序過程中程序就會去 libc.so 調動相關函數。得出如下關係圖:

  • libc.so是C語言標準庫,提供很多常見功能,例如math、標準輸入輸出等
圖1-1 庫使用流程

 

2. 動態庫和靜態庫

庫分爲兩種類型:動態庫(也稱爲共享庫)和靜態庫,動態庫和靜態庫總的來說最大的區別就是,庫在編譯階段會不會被編譯到可執行程序中

很顯然,一開始舉的例子屬於動態庫,因爲這個庫不存在於可執行程序中,調用接口需要訪問外面的文件。

圖2-1 動態庫、靜態庫對比圖

那麼動態庫以及靜態庫有什麼特點呢?

動態庫:

  • 優點
  1. 由於沒有把動態庫編譯進可執行文件中,可執行文件大小較小;
  2. 動態庫調入內存後,可供多個文件調用,減少內存消耗;
  3. 需要修改庫時,無需將可執行文件重新編譯,只需重新編譯庫,使用更加靈活。
  • 缺點
  1. 可執行程序運行時調用接口,需要訪問動態庫文件,執行速度下降;
  2. 可執行程序運行依賴於動態庫環境,動態庫環境破壞,可能使可執行程序運行異常。

靜態庫:

  • 優點
  1. 庫被編譯進可執行程序中,執行效率更高;
  2. 可執行程序不受庫環境影響,即使庫文件刪除或者移動了依舊可以正常執行。
  • 缺點
  1. 庫被編譯進可執行程序中,可執行程序大小較大;
  2. 修改庫需要重新編譯庫以及源程序,使用不靈活。

3. 庫的製作及使用

我們通過庫的製作和使用更加深入的瞭解庫的作用。

我們製作提供 add() 功能的add庫,並編寫 test 程序去測試庫功能。

表3-1 文件以及文件介紹表
文件名稱 文件介紹
test.c .c源文件
add.h add庫對應的.h頭文件
add.c add庫.c源文件

 

  • test.c

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

int main(){

    int a = 1, b = 2, sum = 0;
    
    sum = add(a, b);
    printf("sum=%d\n", sum);

    return 0;
}
  • add.h

#ifndef _ADD_H_
#define _ADD_H_


/*
 *@brief:     add fun
 *@param1:    value a
 *@param2:    value b
 *@retval:       sum
 */
int add(int a, int b);



#endif
  • add.c

#include "add.h"

/*
 *@brief:     add fun
 *@param1:    value a
 *@param2:    value b
 *@retval:       sum
 */
int add(int a, int b){

    return (a+b);
}

製作如上幾個文件。下面開始分別製作使用動態庫、靜態庫:

3.1 動態庫的製作、使用

在我的家目錄下有這麼一個目錄( /home/oracle/lib/test1/ )有如下文件:

圖3-1 目錄一覽圖
  • 製作動態庫:

使用命令:

gcc -shared -fpic -o libadd.so add.c

# -shared:    製作動態庫(共享庫)
# -fpic:      聲明生成代碼與位置無關
# -o:         output 後接輸出文件名
# libadd.so:  需要命名爲 libXXX.so  也可以帶版本號例如 libXXX.so.1
圖3-2 製作庫操作一覽圖

 對於 -fpic參數需要詳細瞭解的可以閱讀如下文章:

linux鏈接動態庫 fpic的使用

  • 編譯測試程序源文件

gcc -o test test.c -L ./ -ladd

# -o:        output 後接輸出文件名
# test:      輸出文件名
# -L:        後接所需庫的目錄路徑
# ./:        所需庫在當前目錄,所以是 "./"
# -ladd:     所需的庫, 需要寫成 -lXXX, XXX爲庫名
圖3-3 編譯測試源程序操作一覽圖
  • 運行測試程序

圖3-4 運行測試程序出錯一覽圖

 會發現,直接運行測試程序會出錯,提示無法打開共享對象文件,沒有找到此文件。這是,我們就要注意了,編譯程序需要制定庫所在的目錄以及庫名,那麼運行的時候也許要指定,不過不同的是,不能像編譯階段那樣子手動指定,而是通過配置系統環境變量的方式。主要有三種方式:

1. 通過配置 LD_LIBRARY_PATH 環境變量

LD_LIBRARY_PATH是Linux環境變量名,該環境變量主要用於指定查找共享庫(動態鏈接庫)時除了默認路徑外的其他路徑。(上述默認路徑指的是:/lib、/usr/lib 等)

  •  臨時配置:

通過如下命令導入路徑:

export LD_LIBRARY_PATH=/home/oracle/lib/test1:$LD_LIBRARY_PATH

# export:                         設置環境變量工具
# /home/oracle/lib/test1:         庫對應的目錄
# $LD_LIBRARY_PATH:               取出原來庫的值,相當於追加,不改變原來的值        

通過如下命令確認是否導入成功:

echo $LD_LIBRARY_PATH

# echo:                環境變量查看工具
# $LD_LIBRARY_PATH:     環境變量的值
圖3-5 臨時配置LD_LIBRARY_PATH環境變量操作一覽圖

臨時配置操作簡單,但是臨時配置關機後LD_LIBRARY_PATH會重置,也就是說,臨時配置只對這次開機有效,關機重啓需要再次設置。

  • 永久配置:

永久配置其實原理上和臨時配置是一樣的,只不過是配置腳本添加進系統啓動中,使其每次啓動自動配置環境變量,常見的啓動腳本有 :

/etc/profile                        #需要root權限,對整個系統有效
/home/xxx(根據用戶名變化)/.bashrc    #對特定用戶有效

在家目錄下的  .bashrc 最後一行加入:

export LD_LIBRARY_PATH=/home/oracle/lib/test1:$LD_LIBRARY_PATH   
source /home/oracle/.bashrc    #使環境變量立即生效

那麼,就完成通過修改 LD_LIBRARY_PATH 環境變量永久配置了

2. 通過修改 /etc/ld.so.conf 文件

通過文件名,我們就可以知道這個文件是動態鏈接庫的配置文件,以下是操作一覽圖:

圖3-6 配置操作一覽圖
圖3-7 配置/etc/ld.so.conf 操作一覽圖

 ldconfig這個程序,位於/sbin下,它的作用是將文件/etc/ld.so.conf列出的路徑下的庫文件緩存到/etc/ld.so.cache以供使用,因此當安裝完一些庫文件,或者修改/etc/ld.so.conf增加了庫的新的搜索路徑,需要運行一下ldconfig,使所有的庫文件都被緩存到文件/etc/ld.so.cache中,如果沒做,可能會找不到剛安裝的庫。

 3. 將庫文件移動到動態鏈接庫存放默認目錄

默認路徑指的是:/lib、/usr/lib,將庫文件拷貝到此目錄這無需配置環境,操作最簡單,但是可能造成系統庫默認目錄混亂。

3.2. 靜態庫的製作、使用

在我的家目錄下有這麼一個目錄( /home/oracle/lib/test1/ )有如下文件:

圖3-8 目錄文件一覽圖
  •  製作靜態庫

圖3-9 製作庫文件操作一覽圖
  • 編譯測試程序源文件

圖3-10 編譯測試程序源文件操作一覽圖
  • 運行測試程序

圖3-11 運行測試程序操作一覽圖

 由於庫直接編譯進測試程序,可直接運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章