http://blog.sina.com.cn/s/blog_602f87700100fc8t.html
libtool作用:
libtool 是一個通用庫支持腳本(/usr/bin/libtool),將使用動態庫的復雜性隱藏在統一、可移植的接口中。
可以在不同平台上創建並調用動態庫,我們可以認為libtool是gcc的一個抽象,也就是說,它包裝了gcc或者其他的任何編譯器,用戶無需知道細節, 只要告訴libtool說我需要要編譯哪些庫即可,並且,它只與libtool文件打交道,例如lo、la為后綴的文件。
libtool生成一個抽象的后綴名為la高層庫libxx.la(其實是個文本文件),並將該庫對其它庫的依賴關系,都寫在該la的文 件中。該文件中的dependency_libs記錄該庫依賴的所有庫(其中有些是以.la文件的形式加入的);libdir則指出了庫的安裝位 置;library_names記錄了共享庫的名字;old_library記錄了靜態庫的名字。
libtool使用方法:
1. 編譯為一個object文件:
以BTX 為例:
源文件為:BTX.c. 頭文件在 ../include/BTX.h
#libtool --mode=compile gcc -g -O -I../include -c BTX.c
用gcc編譯一切正常:
mkdir .libs
gcc -g -O -I../include -c BTX.c -fPIC -DPIC -o .libs/BTX.o
gcc -g -O -I../include -c BTX.c -o BTX.o >/dev/null 2>&1
#libtool --mode=compile mipsel_linux_gcc -g -O -I../include -c BTX.c
顯示需要--tag.
libtool支持多語言,以下是語言與tag的對應:
Language name Tag name
C CC
C++ CXX
Java GCJ
Fortran 77 F77
Windows Resource RC
#libtool --mode=compile --tag=CC mipsel-linux-gcc -g -I../include -c BTX.c
則正常了。
libtool: ignoring unknown tag mipsel-linux-gcc
mipsel-linux-gcc -g -I../include -c BTX.c -fPIC -DPIC -o .libs/BTX.o
mipsel-linux-gcc -g -I../include -c BTX.c -o BTX.o >/dev/null 2>&1
--mode:表示此次動作是 compile(編譯)。
--tag: 如果是交叉編譯器,則需要用--tag指定編譯器。
gcc -g -O -I../include -c BTX.c: 很清楚。
然后libtool作了3件事:
1.創建.libs
2.編譯了一個與位置無關(-fPIC)的obj文件。 放在 .lib中。
3.編譯了一個普通obj文件在本地。
另外,它還創建了一個lo文件。用於描述上面2個obj文件和他們的位置。格式與la文件類似。
2. 將Object文件編譯成可執行文件:
Object的描述文件為 *.lo文件,而libtool只與lo,la文件打交道,
#libtool --mode=link --tag=CC mipsel-linux-gcc main.lo -o test
則利用先前編譯出的main.lo編譯出結果: 可執行文件test.
3. 編譯一個庫文件:
#libtool --mode=link --tag=CC gcc -g -O -o libBTX.la -rpath /usr/local/lib BTX.lo
顯示結果為:
rm -fr .libs/libBTX.a .libs/libBTX.la .libs/libBTX.lai .libs/libBTX.so .libs/libBTX.so.0 .libs/libBTX.so.0.0.0
gcc -shared .libs/BTX.o -Wl,-soname -Wl,libBTX.so.0 -o .libs/libBTX.so.0.0.0
(cd .libs && rm -f libBTX.so.0 && ln -s libBTX.so.0.0.0 libBTX.so.0)
(cd .libs && rm -f libBTX.so && ln -s libBTX.so.0.0.0 libBTX.so)
ar cru .libs/libBTX.a BTX.o
ranlib .libs/libBTX.a
creating libBTX.la
(cd .libs && rm -f libBTX.la && ln -s ../libBTX.la libBTX.la)
link出兩個共享庫,一個是static,一個則是dynamic;需要注意的是,-rpath必須有才能產生dynamic庫來,如果用-static,則只創建static庫。
libBTX.la則指出靜態庫和動態庫的名字和位置。
ranlib的作用:
在一些舊版本的系統上,ranlib負責把靜態庫轉換為其他的某種格式,使得新的庫能夠更快的鏈接;現在ar命令已經包含了上述功能;
為了兼容性,在makefile中還是保留ranlib
#mipsel
#libtool --mode=link --tag=CC mipsel-linux-gcc -O -o libBTX.la -rpath /usr/local/lib BTX.lo
當這樣設置時,libtool會使用gcc,Sam 怎么也沒法改正。所以只好臨時在
/usr/bin/libtool中修改CC="mipsel-linux-gcc" 。這樣就可以了。
mipsel-linux-gcc -shared .libs/BTX.o -Wl,-soname -Wl,libBTX.so.0 -o .libs/libBTX.so.0.0.0
但這里,Sam發現libBTX.la中並沒有顯示出libBTX.so依賴於libbluetooth.so。這不是沒有達到使用libtool的目的嗎?
於是Sam又作了修改:
#libtool --mode=link --tag=CC mipsel-linux-gcc BTX.lo -rpath /home/sam/work/current/BCM/BCM7405/ToolChain/crosstools_hf-linux-2.6.18.0_gcc-4.2-9ts_uclibc-nptl-0.9.29-20070423_20080702/mipsel-linux/lib -o libBTX.la -lbluetooth
果然:在la文件中,可以看到dependency_libs=' -lbluetooth'
則在編譯為可執行文件時,可以不用寫 -lbluetooth
#libtool --mode=link --tag=CC mipsel-linux-gcc main.lo libBTX.la -o test -lpthread
當然,也可以隱式的寫:
#libtool --mode=link --tag=CC mipsel-linux-gcc main.lo -lBTX -o test -lpthread
結果也正常:
mipsel-linux-gcc .libs/main.o -o .libs/test /home/sam/work/current/BCM/BCM7405/Bluetooth/Bluetooth_App/Second_New_Version/BTX_source/BTX_Release/src/.libs/libBTX.so -lbluetooth -lpthread -Wl,--rpath -Wl,/home/sam/work/current/BCM/BCM7405/ToolChain/crosstools_hf-linux-2.6.18.0_gcc-4.2-9ts_uclibc-nptl-0.9.29-20070423_20080702/mipsel-linux/lib
creating test
libtool 從libBTX.la中取出相應的東西。
4. 將object + so 編譯出一個可執行文件:
#libtool --mode=link mipsel-linux-gcc -L../resource main.lo libBTX.la -o BTX_Test -lbluetooth -lpthread
顯示為:
mipsel-linux-gcc .libs/main.o -o .libs/BTX_Test -L/home/sam/work/current/BCM/BCM7405/Bluetooth/Bluetooth_App/Second_New_Version/BTX_source/BTX_Release/resource ./.libs/libBTX.so -lbluetooth -lpthread -Wl,--rpath -Wl,/usr/local/lib
背景知識:
背景知識1:libtool為何使用 -Wl,--rpath-link -Wl,
使用libtool解決編譯問題看上去沒什么問題:庫的名稱、路徑、依賴都得到了很好的解決。但下結論不要那么着急,一個顯而易見的問題就是:並不是所有的庫都是用libtool編譯的。
例如:我用常規辦法生成libBTX.so. 則需要編譯連接成可執行文件時,就沒有libBTX.la文件。
這樣,libBTX.so依賴於 libbluetooth.so這個信息就無人得知。
#libtool --mode=link --tag=CC mipsel-linux-gcc main.lo -L./ -lBTX -o test -lpthread
則因為沒有libBTX.la, 所以根本沒有 依賴於 libbluetooth.so的信息。所以用到libbluetooth.so的東西全無法鏈接。
選項“-Wl,--rpath-link –Wl,DIR”會把-rpath-link選項及路徑信息傳遞給鏈接器。
相當於 --rpath-link /xxx/lib
背景知識2:
是因為如果在本地編譯的情況下,link時,gcc在命令行中找不到一個庫(比如上面的liba.so)依賴的其它庫(比如libb.so),鏈接器會按照某種策略到某些路徑下面去尋找需要的共享庫:
1. 所有由'-rpath-link'選項指定的搜索路徑.
2. 所有由'-rpath'指定的搜索路徑. '-rpath'跟'-rpath_link'的不同之處在於,由'-rpath'指定的路徑被包含在可執行文件中,並在運行時使用, 而'-rpath-link'選項僅僅在連接時起作用.
3. 在一個ELF系統中, 如果'-rpath'和'rpath-link'選項沒有被使用, 會搜索環境變量'LD_RUN_PATH'的內容.它也只對本地連接器起作用.
4. 在SunOS上, '-rpath'選項不使用, 只搜索所有由'-L'指定的目錄.
5. 對於一個本地連接器,環境變量'LD_LIBRARY_PATH'的內容被搜索.
6. 對於一個本地ELF連接器,共享庫中的`DT_RUNPATH'和`DT_RPATH'操作符會被需要它的共享庫搜索. 如果'DT_RUNPATH'存在了, 那'DT_RPATH'就會被忽略.
7. 缺省目錄, 常規的,如'/lib'和'/usr/lib'.
8. 對於ELF系統上的本地連接器, 如果文件'/etc/ld.so.conf'存在, 這個文件中有的目錄會被搜索.
從以上可以看出,在使用本地工具鏈進行本地編譯情況下,只要庫存在於某個位置,gcc總能通過如上策略找到需要的共享庫。但在交叉編譯下,上述八種策略,可以使用的僅僅有兩個:-rpath-link,-rpath。這兩個選項在上述八種策略當中優先級最高,當指定這兩個選項時,如果鏈接需要的共享庫找不到,鏈接器會優先到這兩個選項指定的路徑下去搜索需要的共享庫。通過上面的描述可以看到:-rpath指定的路徑將被寫到可執行文件中;-rpath- link則不會;我們當然不希望交叉編譯情況下使用的路徑信息被寫進最終的可執行文件,所以我們選擇使用選項-rpath-link。