libtool 創建庫的工具


libtool 創建庫的工具

1. 背景

  在不同的系統中建立動態鏈接庫的方法有很大的差別,這主要是因為每個系統對動態鏈接庫的用法和實現並不相同,以及編譯器對動態鏈接庫支持的選項也不太一樣。

  對於開發人員,如果嘗試將使用動態庫的軟件在這些系統之間移植,需要參考枯澀難懂的系統手冊,以及修改相應的 Makefile,這一工作是乏味的,並且具有一定的難度。

  使用 GNU Libtool 可以容易的在不同的系統中建立動態鏈接庫。它通過一個稱為 Libtool 庫的抽象,隱藏了不同系統之間的差異,給開發人員提供了一致的的接口。對於大部分情況,開發人員甚至不用去查看相應的系統手冊,只需要掌握 GNU Libtool 的用法就可以了。並且,使用 Libtool 的 Makefile 也只需要編寫一次就可以在多個系統上使用

  Libtool 庫可以是一個靜態鏈接庫,可以是一個動態鏈接庫,也可以同時包含兩者。

  在這篇文檔中,我們圍繞 Libtool 庫的建立和使用,只是在適當的說明 Libtool 庫和系統動態或者靜態鏈接庫之間的映射關系

2. Libtool 是一個工具

  雖然 Libtool 隱藏了在不同平台創建鏈接庫的復雜性,但其最終還是需要底層系統對鏈接庫的支持,它不能超越系統的限制,例如,Libtool 並不能在不支持動態鏈接庫的系統中創建出動態鏈接庫。

3.  Libtool 基本用法

  以實例來說明如何使用 Libtool 從源代碼創建最終鏈接庫以及執行程序的完整步驟,這是軟件開發過程中經常使用的內容,包括 :

  • 創建 Libtool 對象文件 ;
  • 創建 Libtool 庫;
  • 安裝 Libtool 庫 ;
  • 使用 Libtool 庫 ;
  • 卸載 Libtool 庫 ;

  首先需要准備一個源文件 compress.c,代碼如下

#include <sys/mman.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <limits.h> 
#include <assert.h> 
#include <zlib.h> 
 
/* 一個簡單的文件壓縮函數 */ 
int compress_file (const char *filename) 
{ 
 int src_fd, dest_fd; 
 struct stat sb; 
 Bytef *src, *dest; 
 uLong dest_len; 
 char dest_file[PATH_MAX]; 
 
 src_fd = open (filename, O_RDONLY); 
 assert (dest_fd != -1); 
 
 assert (fstat (src_fd, &sb) != -1); 
 
 src = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, src_fd, 0); 
 assert (src != MAP_FAILED); 
 
 dest_len = compressBound (sb.st_size); 
 dest = malloc (dest_len); 
 assert (dest); 
 
 assert (compress (dest, &dest_len, src, sb.st_size) == Z_OK); 
 
 munmap (src, sb.st_size); 
 close (src_fd); 
 
 snprintf (dest_file, sizeof (dest_file), "%s.z", filename); 
 dest_fd = creat (dest_file, S_IRUSR | S_IWUSR); 
 assert (dest_fd != -1); 
 
 write (dest_fd, dest, dest_len); 
 close (dest_fd); 
 free (dest); 
 
 return 0; 
}

  這個文件實現了一個函數 compress_file(),它接收一個文件名作為參數,然后對文件進行壓縮,生成一個 .z結尾的壓縮文件。在這個文件中使用了 compress()函數,這個函數是有由 libz 提供的

  從源文件建立 Libtool 庫需要經過兩個步驟,先建立 Libtool 對象文件,再建立 Libtool 庫。

(1) Libtool 對象文件

  如果使用傳統的方式,建立對象文件通常使用下面的命令 

$ gcc -c compress.c

  使用 Libtool 則使用下面的命令 :

$ libtool --mode=compile gcc -c foo.c    

  可以看到,使用 Libtool 只需要將“傳統”的命令 (gcc -c foo.c) 作為參數傳遞給 Libtool 即可。

  在上面的命令中,libtool 使用 compile模式 (--mode=compile 選項 ),這是建立對象文件的模式,Libtool 還有其它的模式,后面將介紹。

  上面的命令輸出如下 :

mkdir .libs 
gcc -c compress.c  -fPIC -DPIC -o .libs/compress.o 
gcc -c compress.c -o compress.o >/dev/null 2>&1

  它建立了兩個文件,一個是 .libs/compress.o,在建立這個文件時,Libtool 自動插入了 -fPIC和 -DPIC選項,告訴編譯器生成位置獨立的代碼,之后將用這個文件來建立動態鏈接庫。生成第二個文件 compress.o沒有添加額外的選項,它准備用來建立靜態鏈接庫。

  除了上面的兩個文件之外,Libtool 還建立了一個文件 compress.lo,這個文件就是 Libtool 對象文件,實際上也就是一個文本文件,里面記錄了建立動態鏈接庫靜態鏈接庫分別所需要的真實文件名稱,后面 Libtool 將使用這個文件而不是直接的使用 .libs/compress.o 和 compress.o。

(2)建立 Libtool 庫

$ libtool --mode=link gcc -o libcompress.la【目標文件】 compress.lo【輸入文件】 -rpath /tmp -lz

  注意這里使用 compress.lo 作為輸入文件,並且告訴 Libtool 生成的目標文件為 libcompress.la,.la 是 Libtool 的庫文件后綴。

  -rpath選項告訴 Libtool 這個庫將被安裝到什么地方,如果省略了 -rpath選項,那么不會生成動態鏈接庫

  因為我們的庫中使用了 libz 提供的 compress 函數,所以也提供了 -lz 選項,Libtool 會記住這個依賴關系,后續在使用我們的庫時自動的將依賴的庫鏈接進來。

gcc -shared  .libs/compress.o  -lz  -Wl,-soname -Wl,libcompress.so.0 
                                       -o .libs/libcompress.so.0.0.0 
 (cd .libs && rm -f libcompress.so.0 && 
 ln -s libcompress.so.0.0.0 libcompress.so.0) 
 (cd .libs && rm -f libcompress.so && 
 ln -s libcompress.so.0.0.0 libcompress.so) 
 ar cru .libs/libcompress.a  compress.o 
 ranlib .libs/libcompress.a 
 creating libcompress.la 
 (cd .libs && rm -f libcompress.la && 
 ln -s ../libcompress.la libcompress.la)

  可以看到,Libtool 自動的插入了建立動態鏈接庫需要的編譯選項 -shared。並且,它也建立了靜態鏈接庫 .libs/libcompress.a,后面我們將會介紹如何控制 Libtool 只建立需要的庫

  你可能會奇怪為什么建立的動態鏈接庫有 .0 和 .0.0.0 這樣的后綴,這里先不用理會它,后面在介紹 Libtool 庫版本信息時將會解釋這點。

  值得注意的是,Libtool 希望后續使用 libcompress.la 文件而不是直接使用 libcompress.a 和 libcompress.so 文件,如果你這樣做,雖然可以,但會破壞 Libtool 庫的可移植性。

 

4. 安裝 Libtool 庫

  發布建立好的 Libtool 庫,可以使用下面的命令安裝它 :

$ libtool --mode=install install -c libcompress.la /tmp

  我們需要告訴 Libtool 使用的安裝命令,Libtool 支持 install 和 cp,這里使用的是 install。

  雖然前面我們在建立庫時,通過 -rpath 選項指定了庫准備安裝的路徑 (/tmp),但是這里我們還得要提供安裝路徑。請確保它們一致。

  這個命令的輸出如下 :

install .libs/libcompress.so.0.0.0 /tmp/libcompress.so.0.0.0 
(cd /tmp && { ln -s -f libcompress.so.0.0.0 libcompress.so.0 || 
{ rm -f libcompress.so.0 && 
ln -s libcompress.so.0.0.0 libcompress.so.0; }; }) 
(cd /tmp && { ln -s -f libcompress.so.0.0.0 libcompress.so || 
{ rm -f libcompress.so && ln -s libcompress.so.0.0.0 libcompress.so; }; }) 
install .libs/libcompress.lai /tmp/libcompress.la 
install .libs/libcompress.a /tmp/libcompress.a 
chmod 644 /tmp/libcompress.a 
ranlib /tmp/libcompress.a 
...

  可以看到它安裝了真實的動態鏈接庫和靜態鏈接庫,同時也安裝了 Libtool 庫文件 libcompress.la,這個文件可以被后續的 Libtool 命令使用。

  在安裝完成之后,可能還需要做一些配置才能正確使用,Libtool 的 finish 模式可以在這方面給我們一些提示 :

$ libtool -n --mode=finish /tmp

  這個命令的輸出有點長,所以不在這里列出,如果不能正常的使用安裝好的庫,請運行這個命令。

 

5.使用 Libtool 庫

  要在應用程序中使用前面創建的 Libtool 庫很簡單,准備一個源文件 main.c,它將使用 libcompress.la 庫中定義的函數,代碼如下 :

  清單 2: main.c

#include <stdio.h> 
 
extern int compress_file (const char *filename); int main (int argc, char *argv[]) 
{ 
 if (argc < 2) 
   {   
     printf ("usage : %s file\n", argv[0]); 
     return 1; 
   }   
 return compress_file (argv[1]); 
}

  我們還是要先為 main.c 建立 Libtool 對象文件,這和前面的方法一樣 :

$ libtool --mode=compile gcc -c main.c

。。。。。

 

 

 

 

 

參考博客:

  https://www.ibm.com/developerworks/cn/aix/library/1007_wuxh_libtool/index.html


免責聲明!

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



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