嵌入式Linux-根檔案系統2_(利用交叉編譯工具鏈,構建/lib目錄)
光有應用程式(命令)是不夠的,因為應用程式本身需要使用C庫的庫函式,因此還必需製作for ARM的C庫,並將其放置於/lib目錄。my god,要自己寫C庫的原始碼嗎?不用!還記得交叉編譯工具鏈的3個組成部分嗎?交叉編譯器、for ARM的C庫和二進位制工具。我們只需要把嵌入式的C庫拷貝過來就可以了。遺憾的是:整個C庫目錄下的檔案總大小有26M。而我們根檔案系統所在分割槽不過區區16M而已,根本放不下。怎麼辦呢?
$ du -s --si/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib
26M /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib
需要C庫目錄下所有的檔案嗎?no,absolutely no! 讓我們來分析一下glibc庫目錄下內容的組成。該目錄下的子目錄和檔案共分8類:
1 目標檔案,如crtn.o,用於gcc連結可執行檔案
2 libtool庫檔案(.la),在連結庫檔案時這些檔案會被用到,比如他們列出了當前庫檔案所依賴的其它庫檔案,程式執行時無需這些檔案
3 gconv目錄,裡面是各種連結指令碼,在編譯應用程式時,他們用於指定程式的執行地址,各段的位置等
4 靜態庫檔案(.a),例如libm.a,libc.a
5 動態庫檔案(.so、.so.[0-9]*)
6動態連結庫載入器ld-2.3.6.so、ld-linux.so.2
7 其它目錄及檔案
很顯然,第1、2、3、4、7類檔案和目錄是不需要拷貝的。
由於動態連結的應用程式本身並不含有它所呼叫的C庫函式的程式碼,因此執行時需要動態連結庫載入器來為它載入相應的
除此之外,第5類檔案當然要拷貝。但第5類檔案的大小也相當大。
du -c --si *.so*
7.2M total
需要全部拷貝嗎?非也,非也!其實,需要哪些庫完全取決於要執行的應用程式使用了哪些庫函式。如果我們只製作最簡單的系統,那麼我們只需要執行busybox這一個應用程式即可。通過執行
$arm-linux-readelf -a bin/busybox | grep 'Shared'
0x00000001(NEEDED) Shared library: [libcrypt.so.1]
0x00000001(NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libc.so.6]
可知:busybox只用到了3個庫:通用C庫(libc)、數學庫(libm)、加密庫(libcrypt),因此我們只需要拷貝這3個庫的庫檔案即可。但是每個庫都有4個檔案,4個檔案都要拷貝嗎?當然不
$ls -l libcrypt[.-]*
-rwxr-xr-x 1 dennis dennis 30700 2008-01-22 05:32 libcrypt-2.3.6.so
-rw-r--r-- 1 dennis dennis 23118 2008-01-22 05:32 libcrypt.a
lrwxrwxrwx 1 dennis dennis 13 2008-12-22 15:38 libcrypt.so-> libcrypt.so.1
lrwxrwxrwx 1 dennis dennis 17 2008-12-22 15:38 libcrypt.so.1-> libcrypt-2.3.6.so
$ ls -llibm[.-]*
-rwxr-xr-x 1 dennis dennis 779096 2008-01-22 05:31 libm-2.3.6.so
-rw-r--r-- 1 dennis dennis 1134282 2008-01-22 05:32 libm.a
lrwxrwxrwx 1 dennis dennis 9 2008-12-2215:38 libm.so -> libm.so.6
lrwxrwxrwx 1 dennis dennis 13 2008-12-22 15:38libm.so.6 -> libm-2.3.6.so
$ ls -llibc[.-]*
-rwxr-xr-x 1 dennis dennis 1435660 2008-01-22 05:48 libc-2.3.6.so
-rw-r--r-- 1 dennis dennis 2768280 2008-01-22 05:31 libc.a
-rw-r--r-- 1 dennis dennis 195 2008-01-22 05:34 libc.so
lrwxrwxrwx 1 dennis dennis 13 2008-12-22 15:38libc.so.6 -> libc-2.3.6.so
4個檔案中的.a檔案是靜態庫檔案,是不需要拷貝的。另外3個檔案是:
· 實際的共享連結庫:libLIBRARY_NAME-GLIBC_VERSION.so。當然需要拷貝。
· 主修訂版本的符號連結,指向實際的共享連結庫:libLIBRARY_NAME.so.MAJOR_REVISION_VERSION,程式一旦連結了特定的連結庫,將會參用該符號連結。程式啟動時,載入器在載入程式前,會檢索該檔案。所以需要拷貝。
· 與版本無關的符號連結,指向主修訂版本的符號連線(libc.so是唯一的例外,他是一個連結命令列:libLIBRARY_NAME.so,是為編譯程式時提供一個通用條目)。這些檔案在程式被編譯時會被用到,但在程式執行時不會被用到,所以不必拷貝它。
關於共享庫的2個符號連結的作用的特別說明:
當我們使用gcc hello.c -o hello -lm編譯程式時,gcc會根據-lm的指示,加頭(lib)添尾(.so)得到libm.so,從而沿著與版本無關的符號連結(libm.so -> libm.so.6)找到libm.so.6並記錄在案(hello的ELF頭中),表示hello需要使用libm.so.6這個庫檔案所代表的數學庫中的庫函式。而當hello被執行的時候,動態連結庫載入器會從hello的ELF頭中找到libm.so.6這個記錄,然後沿著主修訂版本的符號連結(libm.so.6 -> libm-2.3.6.so)找到實際的共享連結庫libm-2.3.6.so,從而將其與hello作動態連結。可見,與版本無關的符號連結是供編譯器使用的,主修訂版本的符號連結是供動態連結庫載入器使用的,而實際的共享連結庫則是供應用程式使用的。
通過以上分析,我們只需要拷貝3個庫(每個庫各1個主修訂版本的符號連結和1個實際的共享連結庫)以及動態連結庫載入器(1個符號連結和1個實體檔案)。步驟如下:
cd /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib:
$mkdir /work/rootfs/lib
$cp libcrypt-* /work/rootfs/lib
$ cp -llibcrypt.so.* /work/rootfs/lib
$ cp libm-* /work/rootfs/lib
$ cp -llibm.so.* /work/rootfs/lib
$ cp libc-* /work/rootfs/lib
$ cp -llibc.so.* /work/rootfs/lib
$cp -l ld-* /work/rootfs/lib