1. 程式人生 > >gcc 編譯工具(下)--- 外部庫、共享庫、靜態庫、動態庫

gcc 編譯工具(下)--- 外部庫、共享庫、靜態庫、動態庫

gcc 編譯工具(下)— 外部庫、共享庫、靜態庫、動態庫

1. 標頭檔案與庫檔案

  • 在使用C語言和其他語言進行程式設計時,需要標頭檔案來提供對常數的定義和對系統及函式呼叫的宣告。
  • 庫檔案是一些預先編譯好的函式集合,那些函式都是按照可重用原則編寫的。他們通常有一組互相關聯的用來完成某項常見工作的函式構成。比如用來處理螢幕顯式情況的函式(ncurses庫)和資料庫訪問例程(dbm庫)等。
    • 使用庫的好處:
    • 模組化:將不同功能模組的檔案編譯成不同的庫,有利用明確專案之間的分工。
    • 可重用性高:無需關心內部實現,直接呼叫即可。
    • 可維護性:當庫檔案的程式碼發生改變,無需更改使用庫檔案的程式碼,增強程式碼的可維護性。

2. 標頭檔案與庫檔案的位置

  • /usr/include 及其子目錄底下的 include 資料夾
  • /usr/loacl/include 及其子目錄底下的 include 資料夾
  • /usr/lib
  • /usr/local/lib

3. 使用外部庫(-l選項)

如下面這個例子:

#include <math.h>
#include <stdio.h>

int main(void)
{
    double d = pow(2.0, 4.0);
    printf("The cubed is %f\n", d);

    return 0;
}

我們想使用math.h

庫中的pow()函式,因此在編譯時,需要連線對應的庫。執行如下命令:

➜  test gcc -Wall calc.c -o calc -lm
➜  test ./calc 
The cubed is 16.000000

其中-lm表示要連結libm.so或者libm.a庫檔案。

4. 靜態庫與共享庫

  • 靜態庫(.a):程式在編譯連結的時候把庫的程式碼連結到可執行檔案中。程式執行的時候不再需要靜態庫。靜態庫會被連結到可執行檔案中,比較佔用磁碟空間,並且執行時會將庫的程式碼載入到記憶體,佔用更多的記憶體,並且多個程式無法共享。
  • 共享庫(.so 或 .sa):程式在執行的時候才去連結共享庫的程式碼,多個程式可以共享使用庫的程式碼。共享庫可以在多個程式間共享,所以動態連結使得可執行程式檔案更小,節省了磁碟空間,作業系統採用虛擬記憶體機制允許實體記憶體中的一份共享庫被要用到該庫的所有程序共用,節省了記憶體和磁碟空間。

一個與共享庫連結的可執行檔案僅僅包含它用到的函式入口地址的一個表,而不是外部函式在目標檔案的整個機器碼。

在可執行檔案開始執行以前,外部的機器碼由作業系統從磁碟上的該共享庫中複製到記憶體中,這個過程成為動態連結(dynamic linking)。

5. 生成靜態庫

生成靜態庫可以理解為將一個對.o檔案的歸檔。將一個或多個.o檔案打包生成.a檔案。

可以使用ar工具,例如:

➜  test gcc -Wall -c hello.c -o hello.o 
➜  test ar rcs libhello.a hello.o      
➜  test ls -l libhello.a 
-rw-rw-r-- 1 menwen menwen 1518 716 14:33 libhello.a
// ar是gnu的歸檔工具
// rcs = replace、create、save

接下來就是將生成的.a庫檔案和呼叫庫函式的檔案生成可執行檔案。

➜  test gcc -Wall main.c libhello.a -o main
➜  test ./main 
hello world

這樣生成可執行檔案時要注意main.c libhello.a這兩個檔案的書寫順序,否則編譯會出錯。

還有一種方法來生成可執行檔案,就是通過-l選項。例如:

➜  makefile gcc -Wall -L. main.c -o main -lhello
➜  makefile ./main 
hello world
// -L.:-L選項來指定庫的位置,在當前目錄下

6. 生成共享庫

生成共享庫的過程如下:

➜  makefile gcc -Wall -c -fPIC hello.c              // 編譯生成.o檔案時一定要加上-fPIC選項
➜  makefile gcc -shared -fPIC hello.o -o libhello.so
➜  makefile ls -l libhello.so 
-rwxrwxr-x 1 menwen menwen 8024 716 14:58 libhello.so
// -shared:生成共享庫格式
// -fPIC:產生位置無關碼(position independent code)

連結庫生成可執行檔案:

gcc -Wall -L. main.o -o main -lhello
➜  test ./main 
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

但是執行可執行檔案時報錯:無法連結到共享庫。因此我們要執行共享庫,一共有三種方式:

  1. 拷貝.so檔案到系統共享庫路徑下,一般是/usr/lib
  2. 更改LD_LIBRARY_PATH
  3. ldconfig。配置/etc/ld.so.conf,ldconfig更新ld.so.cache

我們將生成的.so庫拷貝到系統共享庫路徑下,就可以成功執行

➜  test sudo cp libhello.so /usr/lib
➜  test ./main 
hello world

7. 庫搜尋路徑

  • C_INCLUDE_PATH、LIBRARY_PATH(在~/.bash_profile檔案中配置使用者的環境變數)
  • 從左到右搜尋-I、-L指定的目錄
  • 由環境變數指定的目錄
  • 由系統指定的目錄

如果按照以上順序無法找到連結的庫,則會報錯。