【引言:進一步推進工作,開始工具鏈的製作,其間命令較多且較複雜,需謹慎細心。】
本節主要記錄如何構建一個新的不依賴於宿主系統的工具鏈(編譯器、彙編器 、 連接器、庫文件以及一些有用的軟件),並對每步操作進行相應說明,外加筆者遇到的一些問題及解決方案。
首先什麼叫工具鏈?
LFS/CLFS工具鏈是一套用於從C/C++源代碼生成可執行文件的軟件組件適當地組合在一起形成的系統。它包括4大部分,缺一不可:
1. Linux API 一套頭文件,包含了這些源代碼所需要訪問的系統接口;
2. binutils 包含一些處理二進制可執行文件所需的工具,如彙編器、連接器等;
3. gcc 包含了編譯C/C++源代碼所需的工具,並且還能自動調用相關的binutils工具來完成生成源代碼的工具;
4. glibc 包含了系統接口的具體實現。
在上面的定義中,這些軟件適當地組合形成完整的工具鏈。
本節編譯的文件將安裝在 $LFS/tools 目錄下,編譯出來的軟件包起臨時作用,後面還會繼續調整工具鏈。
注:上節已說明,所有爲輸入命令都爲藍色標識,輸入文本爲灰色標識。
3.1 安裝 Binutils (10分鐘)
安裝的第一個軟件包是 Binutils,它包含一個鏈接器,一個彙編器和其他處理目標文件的工具。
cd $LFS/sources 進入工作目錄;
tar xvf /lfs-sources/binutils-2.17.tar.bz2 解壓binutils壓縮包到當前目錄;
mkdir binutils-build 創建一個專用目錄來編譯;
cd binutils-build 進入編譯目錄;
../binutils-2.15.94.0.2.2/configure --prefix=/tools --disable-nls
參數說明:
--prefix=/tools 參數告訴 configure 腳本,準備把 Binutils 軟件包中的程序安裝到 /tools 目錄中;
--disable-nls 禁止了國際化(通常簡稱i18n),因爲臨時工具不需要i18n特性;
此步操作是爲編譯做準備,在當前目錄下生成編譯需要的 Makefile。
make 開始編譯;
make install 安裝;
make -C ld clean
表示進入ld目錄,執行ld/Makefile中的clean編譯生成的文件;
make -C ld LIB_PATH=/tools/lib 進入ld目錄進行make,將make的環境變量LIB_PATH設置爲/tools/lib;
cp -v ld/ld-new /tools/bin 拷貝ld目錄下的ld-new文件到/tools/bin;
cd .. 回到上層目錄$LFS/sources。
注意:這裏暫時不要刪除binutils-build目錄,因爲後面需要這個編譯過的binutils-build
3.2 安裝 GCC-4.1.2 (30分鐘)
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2 解壓壓縮包到當前目錄下;
mkdir gcc-build 同上,創建一個單獨的目錄來編譯;
cd gcc-build 進入編譯目錄;
../gcc-4.1.2/configure --prefix=/tools --libexecdir=/tools/lib \
--with-local-prefix=/tools --disable-nls \
--enable-shared --enable-languages=c
參數說明:
--disable-shared 該參數強制 GCC 鏈接其內部的靜態庫,這樣做是爲了避免和宿主系統產生問題;
--enable-languages=c 此參數確保只建立 C 編譯器,因爲現在只需要這一種編譯器。
由於上面命令過長,因此用連接符"\"進行連接,在輸入時也可直接全部輸入,注意參數與參數之間的空格。
make bootstrap 編譯GCC編譯器;
命令說明:
該命令一般在編譯編譯器時用。bootstrap不只是編譯GCC,而要連着編譯多次,它第一次用主機的GCC進行編譯,第二次用剛編譯好的GCC編譯,
然後再用編譯好的GCC編譯,然後會畢較第二次和第二次的結果以確保它能正確無誤的生成它自己。
make install 安裝GCC;
ln -vs gcc /tools/bin/cc 第一遍編譯GCC時,創建了符號鏈接,是把/tools/bin/cc 鏈接到 /tools/bin/cc/gcc;
cd ..
rm -rf gcc-build gcc-4.1.2 刪除gcc編譯目錄和解壓的源文件。
注意:這裏不要圖省事而不刪gcc目錄,因爲這樣可能會給後面的編譯產生一些意外的錯誤。
3.3 安裝 Linux API Headers (5分鐘)
這裏必須得說明一下,也是筆者遇到的一個很大的困惑:
LFS6.3以前的版本是使用linux-libc-headers-2.6.11.2.tar.bz2,但此版本LiveCD沒有此文件,而是使用內核包linux-2.6.22.5.tar.bz2,通過處理Linux內核源程序tar包中的各種C頭文件而實現應用程序接口 (API)獲取,以供系統C庫(在LFS中是Glibc)使用。
tar xvf /lfs-sources/linux-2.6.22.5.tar.bz2 解壓;
cd linux-2.6.22.5 進入剛解壓到當前目錄的內核目錄;
make mrproper 確保上一次的活動沒有留下失效的文件和依賴;
make headers_check 從源碼中測試內核頭文件;
make INSTALL_HDR_PATH=dest headers_install 提取過程會刪除目標目錄中的原有文件,所以把它們放在一箇中間的本地目錄中;
cp -rv dest/include/* /tools/include 拷貝目標目錄中的所有原文件到/tools/include;
cd ..
rm -rf linux-2.6.22.5 刪除解壓的內核目錄。
3.4 安裝 Glibc (30分鐘)
tar xvf /lfs-sources/glibc-2.5.1.tar.bz2 解壓;
mkdir glibc-build 同上,創建一個單獨的目錄來編譯;
cd glibc-build 同上;
../glibc-2.5.1/configure --prefix=/tools --disable-profile \
--enable-add-ons --enable-kernel=2.6.0 --with-binutils=/tools/bin \
--without-gd --with-headers=/tools/include --without-selinux
參數說明:
--disable-profile 關掉了分析(profiling)信息相關的庫文件編譯;
--enable-add-ons 告訴 Glibc 使用附加的 NPTL 包作爲它的線程庫;
--enable-kernel=2.6.0 告訴Glibc 編譯支持2.6.0版和更新版Linux 內核的庫;
--with-headers=/tools/include 指示Glibc 按照前面剛剛安裝到tools 目錄中的內核頭文件編譯自己,
從而準確的知道內核的特性以根據這些特性對自己進行最佳化編譯。
make 編譯;
mkdir /tools/etc 創建etc目錄;
touch /tools/etc/ld.so.conf 創建ld.so.conf文件,因爲touch創建不存在的文件,避免編譯安裝出現警告;
make install 安裝;
cd ..
rm -rf glibc-build glibc-2.5.1 刪除glibc編譯和解壓目錄。
3.5 調整並測試工具鏈 (10分鐘)
mv -v /tools/bin/{ld,ld-old} 備份/tools/bin/ld文件;
mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old} 同樣備份ld文件;
mv -v /tools/bin/{ld-new,ld} 更新ld文件;
ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld 創建新的ld連接;
以上4步操作結果如下圖:
現在已經安裝好了臨時C庫,接下來本章中要編譯的所有工具都應該連接到這些庫上。爲了達到這個目標,需要調整交叉編譯器的 specs 文件,以便指向 /tools
目錄中的新的動態鏈接器。
將編譯器的 “specs” 文件轉存到一個位置,在那裏可以按默認值找到它。然後,一個簡單的sed替代工具更改GCC 將用到的動態鏈接器。這裏的原則是,在/lib 中找到所有相關的動態鏈接器文件,並調整它們,以便指向新的位置 /tools。
gcc -dumpspecs | sed 's@^/lib/ld-linux.so.2@/tools&@g' > `dirname $(gcc -print-libgcc-file-name)`/specs
GCC_INCLUDEDIR=`dirname $(gcc -print-libgcc-file-name)`/include &&
find ${GCC_INCLUDEDIR}/* -maxdepth 0 -xtype d -exec rm -rvf '{}' \; &&
rm -vf `grep -l "DO NOT EDIT THIS FILE" ${GCC_INCLUDEDIR}/*` &&
unset GCC_INCLUDEDIR
工具鏈的的調整方法有好幾種,而且不同版本GCC的specs可能會有不同,但實際上都是把specs文件中的/lib/ld-linux.so.2替換成了/tools/lib/ld-linux.so.2,也可直接用gcc -dumpspecs導出後手工直接編輯specs文件。這裏就是採用的這種方法。
確認新工具鏈的基本功能(編譯和連接)是否按預期工作,運行下面的命令做一個簡單的合理性檢查:
echo 'main(){}' > dummy.c
cc dummy.c
readelf -l a.out | grep 'tools'
查看a.out的依賴庫,輸出大致如下
[Requesting program interpreter: /tools/lib/ld-linux.so.2]
則表示調整成功,因爲所有的庫已經連接到了/tools/lib下。
rm -rf a.out dummy.c
下面介紹筆者在此過程中所遇到的一些問題,以供參考:
1.編譯GCC編譯器 makebootstrap 時報錯:
mkdir -p --/usr/local/lib/gcc/i686-pc-linux-gnu/3.4.3
mkdir: cannot create directory`/usr/local/lib/gcc': Permission denied
make[1]: *** [installdirs] Error 1
make[1]: Leaving directory`/mnt/lfs/sources/gcc-build/gcc'
make: *** [install-gcc] Error 2
原因出在GCC參數配置錯誤。
2.
--------------------------------------------------------------------------------------
2013年最後一天,寫完跨年,依舊堅持細節,需更嚴謹。
2013-12-31