转载:使用 GNU Libtool 创建库
轉載自:http://www.ibm.com/developerworks/cn/aix/library/1007_wuxh_libtool/
介紹
在不同的系統中建立動態鏈接庫的方法有很大的差別,這主要是因為每個系統對動態鏈接庫的看法和實現并不相同,以及編譯器對動態鏈接庫支持的選項也不太一樣。對于開發人員,如果嘗試將使用動態庫的軟件在這些系統之間移植,需要參考枯澀難懂的系統手冊,以及修改相應的 Makefile,這一工作是乏味的,并且具有一定的難度。
使用 GNU Libtool 可以容易的在不同的系統中建立動態鏈接庫。它通過一個稱為 Libtool 庫的抽象,隱藏了不同系統之間的差異,給開發人員提供了一致的的接口。對于大部分情況,開發人員甚至不用去查看相應的系統手冊,只需要掌握 GNU Libtool 的用法就可以了。并且,使用 Libtool 的 Makefile 也只需要編寫一次就可以在多個系統上使用。
Libtool 庫可以是一個靜態鏈接庫,可以是一個動態鏈接庫,也可以同時包含兩者。在這篇文檔中,我們圍繞 Libtool 庫的建立和使用,只是在適當的說明 Libtool 庫和系統動態或者靜態鏈接庫之間的映射關系。
Libtool 是一個工具
雖然 Libtool 隱藏了在不同平臺創建鏈接庫的復雜性,但其最終還是需要底層系統對鏈接庫的支持,它不能超越系統的限制,例如,Libtool 并不能在不支持動態鏈接庫的系統中創建出動態鏈接庫。
回頁首
Libtool 基本用法
這一節以實例來說明如何使用 Libtool 從源代碼創建最終鏈接庫以及執行程序的完整步驟,這是軟件開發過程中經常使用的內容,包括 :
- 創建 Libtool 對象文件 ;
- 創建 Libtool 庫;
- 安裝 Libtool 庫 ;
- 使用 Libtool 庫 ;
- 卸載 Libtool 庫 ;
首先需要準備一個源文件 compress.c,代碼如下:
清單 1: 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 庫。
建立 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。
建立 Libtool 庫
用下面的命令建立 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 庫的可移植性。
安裝 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 |
這個命令的輸出有點長,所以不在這里列出,如果不能正常的使用安裝好的庫,請運行這個命令。
使用 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 |
使用安裝的庫
| 然后使用下面的命令鏈接執行文件 : $ libtool --mode=link gcc -o main main.lo /tmp/libcompress.la |
我們也可以直接使用 libcompress.a 或者 libcompress.so,但是使用 Libtool 更加簡單,因為它會將幫助你解決依賴關系,例如我們的 libcompress 依賴 libz。
上面命令的輸出如下 :
| gcc -o main .libs/main.o /tmp/libcompress.so -lz -Wl,--rpath -Wl,/tmp -Wl,--rpath -Wl,/tmp |
這里,Libtool 自動選擇鏈接動態鏈接庫,并且加上了運行時需要的 --rpath 選項,以及依賴的庫 -lz。
如果要使用靜態鏈接庫,只需要加上?-static-libtool-libs選項即可,如下 :
| $ libtool --mode=link gcc -o main main.lo /tmp/libcompress.la -static-libtool-libs |
這個命令的輸出如下 :
| gcc -o main .libs/main.o /tmp/libcompress.a -lz |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">使用未安裝的庫
也可以使用還沒有安裝的庫,這和使用安裝好的庫幾乎相同,只是指定的輸入文件位置不一樣,假如我們在同一個目錄中開發 compress.c 和 main.c,那么使用下面的命令 :
| $ libtool --mode=link gcc -o main main.lo ./libcompress.la |
和使用安裝的庫不一樣,這個時候建立的 main 程序只是一個封裝腳本,如果你直接執行它不會有什么問題,但是如果你想調試它,例如 :
| $ gdb main |
gdb 會報怨 main 不是可執行格式,不能接受。這個時候我們需要使用 Libtool 的執行模式,使用下面的命令調試程序 :
| $ libtool --mode=execute gdb main |
卸載 Libtool 庫
使用下面的命令可以卸載安裝的庫 :
| $ libtool --mode=uninstall rm /tmp/libcompress.la |
這個命令的輸出如下 :
| rm /tmp/libcompress.la /tmp/libcompress.so.0.0.0 /tmp/libcompress.so.0 /tmp/libcompress.so /tmp/libcompress.a |
這將刪除所有安裝的庫文件。
回頁首
Libtool 高級用法
這一節將對 Libtool 進行更加全面的描述,包括下面的內容 :
- 創建可動態加載模塊 ;
- 禁止創建動態或者靜態鏈接庫 ;
- Libtool 命令模式 ;
- 庫版本信息 ;
創建可動態加載模塊
有些高級的軟件系統在建立時不需要與特定的庫鏈接,而在運行時可以動態加載符合規范的庫,來提供額外的功能,這通常稱為插件系統。
可動態加載的庫和通常的庫有一些區別,它們可以通過?dlopen() 打開,并且可以通過?dlsym() 查詢它輸出的符號。
使用 Libtool 可以很容易的建立這樣的庫,還是以前面的 compress.c 為例,我們可以通過這樣的命令建立一個可動態加載模塊 :
| $ libtool --mode=link gcc -o compress.la compress.lo -rpath /tmp -lz -module -avoid-version |
這里添加了額外的兩個參數,-module告訴 Libtool 建立一個可動態加載的模塊,-avoid-version告訴 Libtool 不要添加版本號。
在 UNIX/Linux 系統中,庫通常以 lib 作為前綴,可在上面我們指定的輸出文件為?compress.la而不是 libcompress.la,這也是可動態加載模塊的一個特征,它不需要遵循通常的庫命名規則。
在實際應用中,可動態加載模塊通常會使用主程序提供的一些函數,為了滿足動態模塊的需求,在編譯主程序時,需要添加?-export-dynamic選項。
禁止創建動態或者靜態鏈接庫
大部分情況下,Libtool 都配置成同時創建動態鏈接庫和靜態鏈接庫。可以通過下面的命令查看 Libtool 的當前配置 :
| $ libtool – features |
它的輸出如下 :
| host: i686-pc-linux-gnu enable shared libraries enable static libraries |
可是有時侯,只想創建動態鏈接庫或者只想創建靜態鏈接庫,這需要修改 Libtool 自身。后面介紹 Libtool 結合 Autoconf 和 Automake 使用時,將有更加簡單的辦法。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">禁止創建動態鏈接庫
Libtool 自身是一個安裝在 /usr/bin 目錄下的 Shell 腳本,為了修改它,我們需要將它復制到一個有修改權限的目錄,然后找到下面的兩行 :
| 52 # Whether or not to build shared libraries. 53 build_libtool_libs=yes |
將 yes 改為 no。之后用這個修改過的 libtool 就不會創建動態鏈接庫。
還有其它幾個方法可以禁止創建動態鏈接庫,第一個方法是在鏈接時不提供 -rpath 選項,第二個方法是在鏈接時使用?-all-static選項,第三個方法是指定目標文件為 libcompress.a 而不是 libcompress.la。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">禁止創建靜態鏈接庫
在 Libtool 腳本中找到下面兩行
| 55 # Whether or not to build static libraries. 56 build_old_libs=no |
將 yes 改為 no。之后用這個修改過的 libtool 就不會創建靜態鏈接庫。
Libtool 命令模式
在前面,我們已經用到了 Libtool 的大部分命令模式,每個命令模式用于不同的階段,Libtool 根據當前的命令模式添加需要的編譯器選項。
Libtool 支持下面的幾個命令模式 :
- 編譯模式 ;
- 連接模式 ;
- 安裝模式 ;
- 完成模式 ;
- 卸載模式 ;
- 執行模式 ;
- 清除模式 ;
每個命令模式對應開發中的不同階段,但并不是在每個項目中都需要使用上面所有的模式,例如一個不需要安裝的庫就不需要安裝和卸載模式。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">編譯模式
編譯模式用于建立從源文件建立對象文件。它需要一個編譯器名稱作為第一個參數,并且還要提供 -c 選項,Libtool 將根據源文件名稱自動選擇目標文件名稱。如果是建立動態鏈接庫,它也會加入相應的選項,例如 -fPIC等等。
編譯模式使用示例 :
| $ libtool --mode=compile gcc -c src.c |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">鏈接模式
鏈接模式用于建立 Libtool 庫或者可執行文件,如果輸出文件名稱以 .la 結尾,那么它將嘗試建立 Libtool 庫。如果輸出文件名稱以 .a 結尾,它就只建立靜態鏈接庫。如果輸出文件名稱以 .lo 或者 .o 結尾,則建立一個可重新加載的對象文件,這經常叫做部分鏈接。否則它就建立一個執行文件。
鏈接模式使用示例 :
| $ libtool --mode=link gcc -o library.la src.lo -rpath /usr/local/lib |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">安裝模式
安裝模式用于安裝 Libtool 庫或者執行程序。它的第一個參數必須是 install 或者 cp,之后是要安裝的文件以及目標路徑。
安裝模式使用示例 :
| $ libtool --mode=install install -c library.la /usr/local/lib |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">完成模式
完成模式是在安裝完 Libtool 庫之后,在使用之前進行適當的配置。finish 模式需要一個參數,即 Libtool 庫的安裝路徑。
完成模式使用示例 :
| $ libtool --mode=finish /usr/local/lib |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">卸載模式
卸載模式用于卸載已經安裝的 Libtool 庫或者執行程序。
卸載模式使用示例 :
| $ libtool --mode=uninstall rm /usr/local/lib/library.la |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">執行模式
執行模式用來執行應用程序,它在啟動應用程序之前自動的設置好庫的路徑。
執行模式使用示例 :
| $ libtool --mode=execute gdb program |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">清除模式
清除模式和卸載模式差不多,只是它用來清除開發過程中的中間文件。
清除模式使用示例 :
| $ libtool --mode=clean rm library.la |
庫版本信息
和應用程序一樣,庫也需要不斷的升級,考慮一個第三方應用程序使用了我們之前發布的 libcompress。現在我們對 libcompress 的性能進行了優化,并且提供了新的接口,所以我們又發布了這個新版本。
這引入了幾個問題,如果以前的應用程序采用靜態方式鏈接,那么如果它想使用新庫的功能,就必須用新庫重新鏈接應用程序。如果是采用動態鏈接方式,那么新庫安裝后,應用程序應該使用新庫還是舊庫呢?并且,如何避免新庫和舊庫之間的沖突呢?
庫版本號可以解決上述這些問題,一個動態鏈接庫有一個版本號,它在鏈接時硬編碼到動態鏈接庫中,當一個應用程序鏈接動態鏈接庫時,它也存儲了鏈接庫的版本信息,動態加載器 ( 如?ld-linux.so.2) 可以在程序啟動時正確的加載版本匹配的庫。
用?ldd命令可以查看應用程序使用的動態鏈接庫以及它們的版本信息 :
| $ ldd .libs/lt-main linux-gate.so.1 => (0x00182000) libcompress.so.0 => /home/.../.libs/libcompress.so.0 (0x00c25000) libz.so.1 => /lib/libz.so.1 (0x00565000) libc.so.6 => /lib/libc.so.6 (0x003ad000) /lib/ld-linux.so.2 (0x0038d000) |
我們需要用 .libs/lt-main 作為輸入文件,當前目錄下的 main 只是一個封裝腳本。從上面的輸出可以看到,main 程序依賴 libcompress.so 的版本 0。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">庫接口
庫接口是 應用程序可以和庫交流的入口,常用的庫接口包括 :
- 全局變量、結構體、常數 ;
- 全局函數,包括參數類型、數量和返回類型 ;
- socket、管道,以及其它進程間通訊的協議格式 ;
當然還有其它的接口。在設計和實現庫時,應該考慮盡量在將來減少庫接口的改變。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">庫版本號
通常一個庫有兩個版本號,一個主版本號,一個次版本號,主版本號指示接口的改變,次版本號指示性能增強或者錯誤修復。但不是每個系統都是如此。
在前面的例子中我們可以看到,為動態鏈接庫 libcompress.so.0.0.0 建立了兩個符號鏈接 :
- libcompress.so -> libcompress.so.0.0.0
- libcompress.so.0 -> libcompress.so.0.0.0
其中 libcompress.so 是供鏈接器 ( 例如 ld) 使用的,它應該指向當前系統中 libcompress 的最新版本,這樣新程序總是可以鏈接最新的庫版本。
libcompress.so.0 是供動態加載器 ( 例如 ld-linux.so.2) 使用的,它應該指向當前系統中相同接口號 ( 這里是 0) 的最新版本,這樣動態鏈接器就可以加載相同接口最新的庫版本。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">Libtool 庫版本號
每個系統的庫版本機制并不一樣,Libtool 通過一種抽象的版本機制,最終在創建庫時映射到具體的系統版本機制。
Libtool 的版本號分為 3 個部分 :
- current: 表示當前庫輸出的接口的數量 ;
- revision: 表示當前庫輸出接口的修改次數 ;
- age: 表示當前庫支持先前的庫接口的數量,例如?age為 2,表示它可以和支持當前庫接口的執行文件,或者支持前面兩個庫接口的執行文件進行鏈接。所以?age應該總是小于或者等于?current。
Libtool 的庫版本通過參數?-version-info?current:revision:age指定,例如下面的例子 :
| $ libtool --mode=link gcc -l libcompress.la -version-info 0:1:0 |
如果沒有指定,默認版本是 0.0.0。
注意,應該盡可能少的更新庫版本號,尤其是不能強行將庫版本號和軟件發行號保持一致,下面是更新庫版本號的幾個策略 :
- 如果修改了庫的源代碼,那么應該增加?revision。這是當前接口的新的修訂版本。
- 如果改變了接口,應該增加?current,將?revision重置為 0。這是接口的新版本。
- 如果新接口是前面接口的超集 ( 前面的接口還是可用 ),那么應該增加?age。這是一個向后兼容的版本。
- 如果新接口刪除了前面接口的元素,那么應該將?age重置為 0。這是一個新的,但是不向后兼容的版本。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">避免版本信息
有些動態鏈接庫,例如可動態加載模塊,不需要版本號,這時可使用 Libtool 的?-avoid-version選項,例如下面的命令 :
| $ libtool --mode=link gcc -o libcompress.la compress.lo -rpath /tmp -avoid-version |
將只會創建一個 .so 結尾的動態鏈接庫,而沒有 .0.0.0 這樣的版本后綴。
回頁首
結合 Autoconf 和 Automake 使用 Libtool
在使用 Autoconf 和 Automake 的項目中使用 Libtool 更加容易,只需要添加或者修改幾個地方,后續由 Automake 來幫你正確的調用 Libtool。
和 Autoconf 和 Automake 一樣,當在其它主機上編譯發布的軟件包時,不需要安裝 Libtool。
我們以前面的 compress.c 文件為例,介紹如何將它轉換成一個 Autoconf/Automake/Libtool 項目。
建立 configure.ac
使用下面的命令建立一個 configure.ac 模板 :
| $ autoscan |
這將生成一個 configure.scan 文件,將它改名為 configure.ac。
在 AC_INIT() 之后加入下面幾行 :
| # 初始話 Automake AM_INIT_AUTOMAKE([-Wall]) # 這是在 Autoconf 中使用 Libtool 唯一必須的宏 AC_PROG_LIBTOOL |
在 AC_OUTPUT 之前加入幾行 :
| # 告訴 Autoconf 通過 Makefile.in 自動生成 Makefile AC_CONFIG_FILES([Makefile]) |
建立 Makefile.am
建立一個 Makefile.am 文件,內容如下 :
| # _LTLIBRARIES 是 Automake 支持 Libtool 的原語 lib_LTLIBRARIES = libcompress.la libcompress_la_SOURCES = compress.c # 可以通過 _LDFLAGS 傳遞選項給 Libtool libcompress_la_LDFLAGS = # 通過 _LIBADD 可以指定庫依賴關系 libcompress_la_LIBADD = -lz |
注意上面用?lib_LTLIBRARIES,而不是?lib_LIBRARIES,這告訴 Automake 使用 Libtool 創建 Libtool 庫。
建立 configure 和 Makefile
用下面的命令建立幾個空文件 :
| $ touch NEWS README AUTHORS ChangeLog |
然后運行 :
| $ autoreconf -i -s 這將建立 configure 腳本,運行它將得到 Makefile: $ ./configure |
同時,configure 也建立了 libtool 腳本,后續 Automake 將使用這個 libtool 腳本,而不是系統的那個。
建立 Libtool 庫
現在已經有了 Makefile,我們只需要簡單的輸入 :
| $ make |
便可以創建 libcompress 了,這比手動調用 Libtool 要方便很多。
注意 Automake 自動為 Libtool 選擇了 -rpath 的路徑,這是跟隨 UNIX 系統習慣定義的,庫文件安裝到 $prefix/lib 目錄中,頭文件安裝到 $prefix/include 目錄中。我們可以通過 configure 腳本的?--prefix選項改變上面的 $prefix,也可以使用 configure 腳本的?--libdir明確的指定庫文件的安裝目錄。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">靜態庫和動態庫
前面在 configure.ac 中的 AC_PROG_LIBTOOL 宏為 configure 腳本添加了兩個選項 :
- --enable-static
- --enable-shared
這兩個選項可以控制是否建立動態或者靜態鏈接庫,例如,如果只想建立動態鏈接庫,可以這樣運行 configure:
| $ ./configure --enable-shared – disable-static |
在開發過程中,禁止創建動態鏈接庫有幾個優勢 :
- 編譯速度提高了,這可以節省時間 ;
- 調試更加容易,因為不用處理任何動態鏈接庫引入的復雜性 ;
- 你可以了解 Libtool 在只支持靜態鏈接庫的平臺的行為 ;
為了避免在 configure 時忘記?--disable-shared選項,你可以在 configure.ac 中 AC_PROG_LIBTOOL 之前加入一行 :
| AC_DISABLE_SHARED |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">可動態加載模塊
Libtool 的 鏈接模式支持 -module選項,它用來建立一個可動態加載模塊,可以通過 Automake 將這個選項傳遞給 Libtool。只需要選項添加到 Makefile.am 中的?libcompress_la_LDFLAGS變量即可,所以,要建立可動態加載模塊,我們需要修改 Makefile.am:
| libcompress_la_LDFLAGS = -module -avoid-version |
修改 Makefile.am 之后,需要運行 Automake:
| $ automake |
這將重新生成 Makefile.in 文件,以至于 Makefile。
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">安裝 Libtool 庫
安裝 Libtool 庫非常的簡單,只需要運行 :
| $ make install |
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">卸載 Libtool 庫
和安裝 Libtool 庫同樣簡單 :
| $ make uninstall |
建立執行程序
通過 Automake 使用 Libtool 庫也非常容易,我們需要在 Makefile.am 中加入下面的幾行 :
| bin_PROGRAMS = main main_SOURCES = main.c main_LDFLAGS = main_LDADD = libcompress.la |
注意在建立 libcompress.la 是,我們通過 _LIBADD 指定依賴庫,而建立執行文件 main 時,我們通過 _LDADD 指定依賴庫,要記住這點區別。
也記得把前面為測試可動態加載模塊時修改的 libcompress_la_LDFLAGS 變量改回來 :
| libcompress_la_LDFLAGS = |
修改 Makefile.am 之后,需要運行 Automake 更新 Makefile.in:
| $ automake |
然后運行
| $ make |
就可以建立可執行程序 main。
調試執行程序
在結合 Autoconf 和 Automake 使用 Libtool 時,我們幾乎永遠都不會直接調用 Libtool,除了一個例外,那就是 Libtool 的執行模式。
例如我們在開發時要調試執行程序,可以使用下面的命令 :
| $ libtool --mode=execute gdb main |
如果直接使用 :
| $ gdb main |
gdb 會抱怨 main 的格式不可接受,因為使用 Libtool 建立的 main 只是一個封裝腳本,它最終啟動的是 .lib/lt-main。
回頁首
小結
本文檔描述了 GNU Libtool 解決的問題,它的工作方式,以及在實際工作中使用 Libtool 的方法。有興趣的讀者應該進一步參考 GNU Libtool 手冊獲得更詳細的信息。在安裝了 GNU Libtool 的系統中可以直接通過 info libtool 來查看手冊。
參考資料
學習
- Shared libraries: 這篇 HOWTO 描述了 Linux 系統中動態鏈接庫名字、位置,以及使用動態鏈接庫相關的環境變量,可以在http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html查看。
- Autoconf, Automake, Libtool: 這本在線書籍詳細描述了 GNU Autotools(Autoconf, Automake, Libtool) 之間的關系,以及如何在軟件項目中結合使用 GNU Autotools。可以在?http://sources.redhat.com/autobook/?查看本書的在線版本,或者從http://sources.redhat.com/autobook/download.html下載。
- GNU Libtool :可以在?http://www.gnu.org/software/libtool/從這里可以下載 GNU Libtool 的最新版本,閱讀在線手冊,或者下載 PDF 版本的手冊。
- GNU Autoconf:GNU Autotool 解決了 UNIX 世界大部分常見的軟件移植性問題,它通過使用各種手段去探測當前操作系統的特征,以及系統中安裝的軟件包的特征,最后生成一個頭文件,定義各種各樣的宏來表示系統的特征。應用程序可以通過這個頭文件來針對不同的環境來進行開發。可以在?http://www.gnu.org/software/autoconf/下載 Autoconf 最新版本的軟件包和手冊,或者查看在線手冊。
- GNU Automake:GNU Automake 解決了編寫可移植 Makefile 的問題,它使用和 Makefile 規則不同的語法來描述軟件項目的依賴關系。其生成的 Makefile 通常比手工寫的 Makefile 更加規范,例如它總是包含 dist, install, uninstall 等等常用的 Makefile target。它支持幾種常見的語言,例如 Java, vala 等等。可以在?http://www.gnu.org/software/automake/下載 Automake 最新版本的軟件包和手冊,或者查看在線手冊。
- AIX and UNIX 專區:developerWorks 的“AIX and UNIX 專區”提供了大量與 AIX 系統管理的所有方面相關的信息,您可以利用它們來擴展自己的 UNIX 技能。
- AIX and UNIX 新手入門:訪問“AIX and UNIX 新手入門”頁面可了解更多關于 AIX 和 UNIX 的內容。
- AIX and UNIX 專題匯總:AIX and UNIX 專區已經為您推出了很多的技術專題,為您總結了很多熱門的知識點。我們在后面還會繼續推出很多相關的熱門專題給您,為了方便您的訪問,我們在這里為您把本專區的所有專題進行匯總,讓您更方便的找到您需要的內容。
- AIX and UNIX 下載中心:在這里你可以下載到可以運行在 AIX 或者是 UNIX 系統上的 IBM 服務器軟件以及工具,讓您可以提前免費試用他們的強大功能。
- IBM Systems Magazine for AIX 中文版:本雜志的內容更加關注于趨勢和企業級架構應用方面的內容,同時對于新興的技術、產品、應用方式等也有很深入的探討。IBM Systems Magazine 的內容都是由十分資深的業內人士撰寫的,包括 IBM 的合作伙伴、IBM 的主機工程師以及高級管理人員。所以,從這些內容中,您可以了解到更高層次的應用理念,讓您在選擇和應用 IBM 系統時有一個更好的認識。
?
轉載于:https://www.cnblogs.com/xuechao/archive/2012/01/14/2322531.html
總結
以上是生活随笔為你收集整理的转载:使用 GNU Libtool 创建库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动态代理的简单实例.
- 下一篇: 在冬夜中燃起的火把