歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux資訊 >> 更多Linux

內核研究 :CLFS2.0原理分析

前言:  實際上,兩三個星期前我第一次看CLFS2.0的時候有一種似曾相似的感覺,而且感覺看的非常順,所以我只看到工具鏈完成後又看了兩三個包的編譯我就感覺想明白原理了,因為CLFS2.0的制作的方法我曾經自己嘗試過,當時想研究出一種和LFS方法不同的方式來構建系統,雖然當時也做出來了一些成果,但感覺不成功(最重要的就是當時我不知道有--with-sysroot這個參數),但也有不少收獲,而且我認為我當時的想法沒有錯,這可以在我以前的兩篇文章《體積小巧、功能單一的LFS》和《LFS反向分析》中看到這個方法的影子,而後續包制作也和我在做憨牛包管理器中的打包方式方法類似,所以我感覺 CLFS2.0方法不光適合用在交叉編譯上,同樣在非交叉的情況下也是適用的。下面我就將我對CLFS2.0方法的理解總結一下,希望對CLFS感興趣的朋友有所幫助,同時附加上我根據CLFS2.0的原理制作的PowerPC和MIPS的工具鏈部分,但因能力和理解力的限制,難免會有差錯,也希望各位發現問題後能及時提出,以便及時更改,謝謝。  更新,由於篇幅比較長所以難免出現一些錯誤或者筆誤,也有可能加入新內容,因此難免會進行修正或增刪一些內容,如果本文被轉載或者發現文章的更新日期已經比較久了,可能已經有更新,您可以在www.Linuxsir.org的LFS版中或者在本人的Blog中查看最新版本。  linuxsir:http://www.linuxsir.org/bbs/showthread.PHP?t=267672  我的Blog:http://youbest.cublog.cn  如須轉載請注明作者為沖天飛豹(youbest),並提供轉載出處。好的開始:  設置好環境變量對於後面的編譯參數變的通用,也便於輸入方便不容易出錯  這裡需要注意的是在cat > ~/.bashrc << "EOF"set +humask 022CLFS=/mnt/clfsLC_ALL=POSIXPATH=${CLFS}/cross-tools/bin:/bin:/usr/bineXPort CLFS LC_ALL PATHEOF裡的PATH設置,這個PATH設置一直到制作結束也沒有變化,這不同於LFS在第五章和第六章使用不同的PATH,這個問題之後在文章中會回答。另一個重要設置就是export CLFS_HOST="$(echo $MACHTYPE sed "s/$(echo $MACHTYPE cut -d- -f2)/cross/")"export CLFS_TARGET="arm-unknown-linux-gnu"這個設置對於不同的體系平台會不一樣,在文章的附錄中有另外兩個體系平台的定義。  一個說明:我們暫時把CLFS2.0中第五章的部分稱為交叉工具鏈部分,而把第六章稱為目標體系平台。CLFS2.0中的絕招sysroot參數  sysroot參數一共出現了也就出現了三次,但這三次的使用可以說完全改變了以前的制作完整工具鏈的方法。  sysroot的目的其實很簡單:就是將--with-sysroot所指定的目錄作為根目錄來使用。  我們會在文章中看到這三次sysroot是如何使用來達到目的的。分析開始:  首先開始復制一些頭文件到${CLFS}中的usr/include中,這個步驟似乎和以前沒什麼區別,但實際上我個人覺得這裡少了一步,應該在復制前增加一句 代碼:

make include/linux/version.h

  接著我們就要安裝binutils,這個包的目的就是為了連接目標文件為可執行文件,那麼在第一次編譯binutils的時候我們就要開始用--with-sysroot這個“神奇”的參數了。../binutils-2.17/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --with-sysroot=${CLFS} \--disable-nls --enable-shared --disable-multilib  從參數上的理解是,binutls將被安裝到${CLFS}/cross-tools中(--prefix=${CLFS}/cross- tools),編譯出來的二進制文件將運行在${CLFS_HOST}所指定的平台上(--host=${CLFS_HOST}),而其連接出的可執行文件是運行在${CLFS_TARGET}所指定的平台上(--target=${CLFS_TARGET}),屏蔽國際化支持(--disable- nls),同時編譯出共享鏈接庫(--enable-shared),不支持多種架構庫(--disable-multilib),同時將${CLFS} 所定義的目錄作為根目錄(--with-sysroot)  接著的make configure-host不要少了,這樣可以利用前面設置的參數全面配置binutils所有需要編譯的部分。  編譯這個binutils是使用主系統的binutils和gcc來實現的,主系統是i386結構的,因此,這次我們編譯出的這個binutils是利用主系統這個工具鏈來完成編譯的,編譯出來的程序也是運行在i386上的。下面我們圖解這個部分 點擊查看大圖  由上圖我們可以看出,實際上binutils編譯過程中是沒有用到目標體系的內核頭文件的,因此復制內核的目標體系頭文件和編譯binutils的順序是無所謂的。




  接著我們就要准備開始編譯GCC(不要以為我這裡漏掉了glibc-2.4的headers這部分,這樣安排正是為了說明glibc-2.4的headers部分為什麼要在編譯GCC之前處理),我們來看一下它的編譯參數../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --disable-shared \--enable-languages=c  從參數上理解就是,gcc將被安裝到${CLFS}/cross-tools,而且只編譯c語言部分,同時將${CLFS}所定義的目錄作為根目錄(--with-sysroot)  這裡有必要解釋一下一個比較重要的概念就是“交叉編譯”,交叉編譯簡單的講就是在一種體系的機器上編譯出運行於另一種體系的代碼(兩種體系也可以是相同的,但通常是以不同的體系來說明),如下圖: 點擊查看大圖  這裡很重要的一個部分就是編譯器和鏈接器,這二者在這裡對應的是GCC和binutils,它們即要運行於當前體系的系統下,又要能生成和處理目標體系的文件,因此稱它們為交叉編譯工具鏈。  這裡比較重要的是GCC(並不是binutils不重要,只是我們重點要說明的是GCC),那麼GCC是如何進行編譯的呢?  這個問題要說清楚的話可以寫一本書了,這裡我只是從CLFS的角度來說明這個問題。GCC要編譯出其它體系的代碼,除了需要要編譯的程序的源代碼外還需要符合該體系的頭文件,這裡最重要的就是內核的頭文件和glibc的頭文件,所以作為交叉編譯用的GCC,除了在編譯其它程序的時候用到頭文件,其自身也必須“了解”這些頭文件,它必須掌握目標體系的全部細節,這已經由Linux的內核頭文件給出了,另一點需要注意的是,GCC不僅可以用來在Linux 下用,也可以用在其它支持的系統上,比如BSD,而C庫也不局限於glibc,有可能是其它的C庫,比如UClibc,所以要能夠生成在目標體系的目標系統下運行的二進制代碼,那麼就必須對這一切都要了解,所以在編譯GCC的時候必須有目標體系及目標系統相對應的頭文件,這就解釋了為什麼要在編譯GCC之前要先編譯一個glibc-2.4的頭文件部分。  下面來圖解這段內容 點擊查看大圖  現在我們回過頭來,編譯glibc-2.4符合目標系統的頭文件,這部分我感覺也是各個體系差異比較大的部分,所以我們這裡參考CLFS2.0第一個完成的體系ARM來說明(我只說重點,全部內容可以參考手冊說明)tar -jxvf ../glibc-ports-2.4.tar.bz2mv -v glibc-ports-2.4 ports這部分實際上是為了glibc能夠支持arm而安裝的,標准的glibc並不支持ARM等幾個體系,而glibc-ports就是為了補充這部分的支持而出現的(這裡必須將其改為ports,否則編譯無法找到)。echo "libc_cv_forced_unwind=yes" > config.cacheecho "libc_cv_c_cleanup=yes" >> config.cacheecho "libc_cv_arm_tls=yes" >> config.cache這部分實際上是強制指定一些編譯時候的參數,因為目前還沒有交叉編譯用的GCC,所以用主系統做./configure的時候有些參數會設置一些不正確的參數,因此這裡強制聲明是非常必要的,到工具鏈中第一遍的GCC完成後就可以正確設置這些參數了,所以再編譯glibc就可以不用指定這些參數。echo "install_root=${CLFS}" > configparms這個就是為了指定安裝目錄,方便以後用make install直接裝到${CLFS}目錄下,其實不要這句也沒問題,後面的make install改為make install_root=${CLFS} install-headers就可以了。CC=gcc ../glibc-2.4/configure --prefix=/usr \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--with-headers=${CLFS}/usr/include --cache-file=config.cache這個編譯參數說明gcc用的是主系統的gcc,這裡需要注意的是--prefix=/usr雖然指定的是/usr目錄,但實際上最後安裝到的是$ {install_root}/usr下,如果沒有指定install_root,那自然是安裝到了/usr,而因為前面指定了install_root 的目錄,實際上最後安裝到了${CLFS}/usr下,這裡還需要注意的是--host和--build的指定(--host=$ {CLFS_TARGET} --build=${CLFS_HOST}),對比前面編譯的binutils的參數(--host=${CLFS_HOST} --target=${CLFS_TARGET}),和後面GCC的參數(--host=${CLFS_HOST} --target=${CLFS_TARGET}),看到沒有:glibc-2.4 :--host=${CLFS_TARGET} --build=${CLFS_HOST}binutils :--host=${CLFS_HOST} --target=${CLFS_TARGET}gcc  :--host=${CLFS_HOST} --target=${CLFS_TARGET}



     這裡--host的指定剛好binutils和gcc相反,指定為目標體系,這點很重要,這是為了讓後面即將編譯的GCC能夠准確的了解其要編譯出的符合目標系統的二進制所需要的信息。--with-headers指定了使用的頭文件的目錄,glibc唯一必須要的頭文件就是內核的頭文件,這點很有意義,因為glibc也是可以支持多種內核平台的,比如BSD,所以它也必須了解所服務的內核的所有特征細節,因此就不難理解為什麼內核頭文件必須先於glibc的頭文件安裝,只有這樣 glibc才能“了解”到准確的內核信息。--cache-file則沒什麼好說的,就是讓./configure對於--cache-file指定的文件中設置的參數強制使用。make install-headers到這裡,我們還不需要一個完整的glibc,其實也無法進行編譯的,因為目前的交叉編譯用的GCC還沒有,所以是無法編譯的,但編譯一個交叉編譯的GCC又必須要一組C庫的頭文件,好在安裝目標平台的glibc的頭文件並不需要交叉編譯器,所以這裡直接安裝頭文件即可。cp -v ../glibc-2.4/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h \${CLFS}/usr/include/bits這個是為了安裝支持NPTL的頭文件,這部分根據不同的平台復制的文件是不一樣的,文章的附錄中將介紹PowerPC和MIPS兩種體系需要復制的文件,可作為參考。(如果你前面沒有仔細看,我提個醒,上面提到的glibc-headers部分和GCC第一次編譯部分是反過來講的,因此和書上沒有沖突。)  好了,到目前為止已經有了一個交叉編譯用的GCC和一個交叉鏈接用的binutils,以及一組目標平台和目標系統用的庫文件,現在就可以正式的開始編譯Linux平台的基礎部分——C庫(glibc)  在編譯glibc的時候,同樣指定了兩個參數  echo "libc_cv_forced_unwind=yes" > config.cache  echo "libc_cv_c_cleanup=yes" >> config.cache  這兩個參數於體系無關,而第三個參數  echo "libc_cv_arm_tls=yes" >> config.cache  則省略了,因為交叉編譯環境已經完全了解你要編譯的目標體系,所以可以自行檢測出來。  這裡著重需要明白的是glibc的編譯參數BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc" \AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \../glibc-2.4/configure --prefix=/usr --libexecdir=/usr/lib/glibc \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--disable-profile --enable-add-ons \--with-tls --enable-kernel=2.6.0 --with-__thread \--with-binutils=${CLFS}/cross-tools/bin --with-headers=${CLFS}/usr/include \--cache-file=config.cache  BUILD_CC所指定的是用來建立在編譯過程中需要運行的程序用什麼gcc來編譯,這個很重要,可以看出BUILD_CC指定的是主系統的gcc,主系統的gcc是一個運行於i386,編譯出i386體系的編譯器,因此它編譯出來的程序可以在當前系統下運行,因為在編譯過程中會編譯一些臨時使用的程序,而這些程序是編譯完後就馬上要用的,所以這些程序必須能在當前體系的平台上運行,因此必須以一個運行於當前體系平台,又編譯出當前體系平台的編譯器來完成,所以主系統的gcc自然成了最合適的選擇。而CC所指定的是${CLFS_TARGET}-gcc,很明顯是交叉編譯用的GCC,原因很簡單,最後編譯出來的glibc的二進制庫都是要在目標體系平台上運行的。AR和RANLIB是binutils中的工具,它們也是在編譯過程中需要用到的,而且是用來處理目標平台的二進制文件,所以它們也是使用交叉編譯用的版本。  --prefix和--libexecdir已經在前面編譯glibc-headers部分說明過了,不要被表面現象所“迷惑”,最後安裝到的是${install_root}/usr和${install_root}/usr/lib/glibc下。  --host指定也表明這裡最後編譯出來的庫是用在目標體系平台下的。  --with-binutils則是為了表明在需要使用binutils的時候使用交叉版本所在的目錄(這裡不會影響BUILD_CC編譯的臨時程序,因為交叉版本在交叉工具鏈階段是有前綴的)。  --with-headers和--cache-file解釋同glibc-headers部分。  其余參數於LFS中含義相同,這裡就不做解釋了。  後面的make和make install自然沒什麼好說明的,只是這裡因為前面設置了install_root的原因,在make install階段會安裝到install_root下。  下面按道理應該要安裝locales了,但這裡運行make localedata/install-locales並不能正確完成,原因很簡單localedef是目標體系平台的程序,所以無法在本階段完成,這裡需要和前面說明的BUILD_CC編譯的是可以在當前體系平台運行的臨時程序分開看,因為localedef並不是一個臨時用的文件,而是glibc的標准程序,所以這裡也可以算是一個未解決的問題。我的建議是暫時跳過安裝localedata部分。  在完成了glibc的編譯和設置後,我們要進行第二次編譯交叉版本的GCC了。這裡我想說明一下為什麼要進行兩次GCC編譯的目的,這裡和我們已經熟知的LFS中工具鏈裡的兩次GCC編譯有著不同的原理。這一部分也算是CLFS2.0中的重點部分,我將以我的理解來說明這個問題:  在LFS裡,工具鏈中第一遍編譯gcc,是為了編譯工具鏈中的glibc而編譯的,而且為了能夠保證編譯器的正確則使用了make bootstrap來編譯,在編譯完glibc後,則再編譯一遍gcc,目的是為了讓這個gcc使用剛剛在工具鏈中編譯好的glibc,為了是在後面完成工具鏈後chroot時保證工具鏈的可用,並且可以用來編譯目標系統的glibc和LFS其他需要的軟件。  而在CLFS2.0中,第一遍編譯gcc,也確實為了編譯glibc,而這個glibc卻不是工具鏈中要用的,這是目標系統用的(這一點也可以通過第六章中沒有編譯glibc的部分來間接驗證),並不是為了第二次編譯gcc,讓gcc鏈接到這個glibc用的,而且gcc也不能鏈接到這個glibc 上,因為第一遍編譯的交叉版本的gcc來編譯出的glibc必然是目標體系平台的代碼,所以在當前的體系平台上是運行不起來的,如果第二次編譯的gcc鏈接到這個glibc上,那麼這個gcc也就不能在當前的體系平台上運行了,所以CLFS2.0在工具鏈階段的兩次編譯gcc,不是為了讓gcc連接到新編譯的glibc上。  那麼究竟是什麼原因呢?  我們先來看CLFS2.0第一編譯GCC,沒有使用make bootstrap來編譯,而是使用make all-gcc來編譯,也就是只編譯了一次,這是合情合理的,要知道這個gcc是交叉版本,也就是說它再編譯出來的是目標體系平台的二進制文件,雖然可以完成make bootstrap的第二步,但第三步是無法進行的,因為目標體系平台無法在當前平台上運行(make bootstrap,就是用第一遍編譯的gcc來編譯第二遍的gcc,再用第二遍的gcc編譯第三遍的gcc,然後比較第二遍和第三遍的gcc,來確定編譯是否正確),因此這裡只需要也只能編譯一遍。  在LFS裡,第一遍gcc只編譯了c語言部分,是因為編譯glibc只需要c語言就行了,你當然也可以編譯其它的語言支持,但沒有什麼意義,因為第一遍的gcc會被第二遍替換掉,而且第一遍是依賴於主系統glibc的,所以在chroot後就不能用了。  在CLFS2.0裡沒有chroot的過程,所以無論是工具鏈中的第一遍還是第二遍編譯,gcc所依賴的glibc都是主系統的glibc,但對後面的編譯並不造成影響。  那為什麼要編譯兩次呢?  CLFS2.0的工具鏈中第一遍只編譯一個支持c的gcc,原因是要編譯出一個支持交叉的c++,必須有一個編譯好的用於目標體系平台的glibc,而不是只有glibc的頭文件就可以的,好在編譯glibc有c支持就夠了,所以編譯glibc也成了第一遍的gcc唯一的理由和作用。  在LFS中,工具鏈裡第二遍的gcc是由第一遍的gcc來完成編譯的。  在CLFS2.0中,我們知道第一遍編譯的gcc就是交叉版本的gcc,如果由它來編譯第二次的gcc,那麼編譯出來的就是目標體系平台的二進制文件,是無法在當前體系平台上運行的,而我們還要用第二次編譯的交叉版本的gcc來編譯後面的內容,所以絕對不能用第一遍的gcc來編譯第二遍的gcc。  那麼是誰來編譯第二次的gcc呢?  現在看這個問題應該是有點廢話,目前就只剩下主系統的gcc了,也只有主系統的gcc現在能編譯出在當前體系平台運行的交叉版本的gcc了。  現在明白了吧,工具鏈中gcc的第一次和第二次編譯都是由主系統的gcc和binutils來完成的(之前沒有提及binutils,只是為了理解方便,但實際上編譯後是少不了鏈接過程的,這個過程是要binutils來完成的)。



  到目前為止只有在編譯glibc的時候用到了交叉版本的binutils,其它部分的鏈接都是由主系統的binutils來完成的。  現在對工具鏈中gcc的兩次編譯的目的和原因差不多搞清楚了,我們來看一下gcc兩次編譯參數的對比第一次:../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --disable-shared \--enable-languages=c第二次:../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --enable-shared \--enable-languages=c,c++ --enable-__cxa_atexit \--enable-c99 --enable-long-long --enable-threads=posix  看來沒什麼特別需要說明的,非交叉編譯用的參數基本上和LFS沒什麼太大區別,反正最重要的就是這個--with-sysroot,好了,三次--with-sysroot都出現了,雖然前面對這個參數也說明了一下,但不夠詳細,下面我就來說說對這個關鍵參數的理解。  我們在做LFS的過程中了解到gcc在編譯過程中是默認從/usr/include中找頭文件的來編譯的,而binutils中的工具ld是從 /lib /usr/lib、LD_LIBRARY_PATH、/etc/ld.so.conf等設置中所指定的路徑搜索動態庫或者靜態庫進行鏈接操作的,而要改變這種默認情況則可以通過參數指定、打補丁等方式來達到目的,但是這樣非常煩瑣,所以就產生了LFS中工具鏈的方法,通過先做一個能自我編譯的工具鏈,但這些工具鏈中的程序都是連接到類似/tools/lib這樣的目錄下的庫中,而且也是通過參數指定或者打補丁的方式來實現的,並不符合標准的/lib /usr/lib,所以後面在chroot後再用這個工具鏈來生成目標系統。  而現在我們用CLFS2.0的方法不需要再建立這個完整的工具鏈了,只是建立一個交叉用的工具鏈,而這個工具鏈中的程序都是鏈接到/lib和 /usr/lib裡的庫的,這樣一個工具鏈是不能chroot,但現在我們要利用這個“不健全”的工具鏈來完成目標體系平台,就必須要用到更改默認路徑的方式,這個方式就是--with-sysroot。  一個簡單的理解就是,默認的路徑實際上都是{--with-sysroot}/usr {--with-sysroot}/usr/lib {--with-sysroot}/usr/include這樣的形式,只是在默認的情況下{--with-sysroot}表示的是空字符串,這樣就變成了/usr /usr/lib /usr/include,而如果我們指定了--with-sysroot,比如--with-sysroot=/mnt/clfs,則默認路徑就變成了 /mnt/clfs/usr /mnt/clfs/usr/lib /mnt/clfs/usr/include,這樣我們在編譯時查找頭文件以及在鏈接時查找動態或靜態庫就自動到--with-sysroot指定的路徑下來完成。這個就是--with-sysroot參數的目的。  這裡需要注意的是,--with-sysroot默認是只支持交叉編譯的情況的,我們可以從代碼中印證:  在gcc-core解壓後的Makefile.in文件(你可以理解為是Makefile的一個摸板文件)中有一段代碼

代碼:

# Default native SYSTEM_HEADER_DIR, to be overridden by targets. NATIVE_SYSTEM_HEADER_DIR = /usr/include # Default cross SYSTEM_HEADER_DIR, to be overridden by targets. CROSS_SYSTEM_HEADER_DIR = @CROSS_SYSTEM_HEADER_DIR@而對於CROSS_SYSTEM_HEADER_DIR的賦值在configure中有如下代碼 代碼:

CROSS_SYSTEM_HEADER_DIR='$(TARGET_SYSTEM_ROOT)$(NATIVE_SYSTEM_HEADER_DIR)'而同在configure中對TARGET_SYSTEM_ROOT的賦值 代碼:

TARGET_SYSTEM_ROOT=$with_sysroot



  現在明白了吧,對於交叉方式,是默認支持--with-sysroot的,而普通的編譯方式是不行的,但也不是說我們就沒辦法了,其實辦法說起來也很簡單,就是改代碼、打補丁。  我們來看三次使用--with-sysroot的作用和目的  第一次,binutils下使用,目的是讓binutils在查找庫的時候到--with-sysroot指定的地方查,接著的glibc-headers和gcc都沒有用到這個binutils,我們先放一下,看第二次使用;  第二次,第一次編譯gcc下使用,目的是讓這個gcc在編譯的時候默認到{--with-sysroot}/usr/include下找頭文件。  接著我們就開始編譯目標體系平台下的glibc了,這個時候交叉版本的binutils和第一次編譯的gcc都用上了,則我們也就清楚了,在編譯這個 glibc的時候是到${CLFS}/usr/include裡找頭文件,到${CLFS}/lib等目錄下鏈接庫的,不過glibc是目標系統的第一個軟件包,因此,他並不需要到${CLFS}/lib等目錄下的庫鏈接,但交叉版本的binutils還是順利的完成了glibc編譯目錄下自己眾多庫文件的鏈接工作。這裡binutils的--with-sysroot沒有體現出來,但gcc的--with-sysroot已經發揮作用了。  第三次,實際上這次是為了替換掉第一次編譯的gcc而“重復”的(原因前面已經講過了),所以可以理解和第二次使用--with-sysroot是一樣的。  到現在為止,gcc中的--with-sysroot已經體現出其作用了,但binutils什麼時候才能發揮作用呢?  不要著急,很快就到了它的用武之地了。  現在我們就完成了交叉工具鏈了……(畫外音:等等,還有兩個包沒說呢,怎麼工具鏈就完成了?)  這裡我們先把--with-sysroot的問題放下,現在出現了另外一個問題,在LFS過程中我們知道工具鏈除了binutils和gcc外還有很多大量的工具包,而在CLFS2.0中就只有file和groff兩個包,是什麼意思呢?  這裡我們要全面了解工具鏈的作用以及這些工具包的作用,在LFS中的工具鏈的目的不光是為了能編譯,而且是為了能夠成為一個完整的自已自足的“系統”,再進入(chroot)這個“系統”後,能夠利用這種自已自足的能力創造新系統,而這個過程中,大量的工具包是少不了的,這也就是為什麼LFS的方法中需要在工具鏈階段裡加入大量的工具包。  而在CLFS2.0之所以沒有加入大量的包是因為,CLFS2.0的方法裡沒有chroot這個環節,所以使用主系統的工具就可以了,因此只需要 gcc和binutils就可以完成任務了,而file和groff其實我覺得也是沒有必要的,只要主系統中的file和groff是符合要求的版本就可以了,如果沒有符合的版本編譯一個也是可以的,這裡要注意的是file和groff是用主系統的gcc和binuitls完成編譯鏈接的並依賴於主系統的glibc。  好了,下面我們就要開始編譯目標系統的文件了。  之前我們已經在第五章的部分完成了glibc的編譯,所以我們就可以直接編譯各個包了,從CLFS2.0的手冊來看,似乎還是遵循著LFS的先編譯binutils和gcc,然後再編譯其它的包,但這裡又是和LFS的方法有著本質上的區別,下面我們就來對照一下看看。  在LFS中,我們在完成了工具鏈後,利用工具鏈來編譯目標系統的glibc,之後是編譯binutils,然後利用剛剛編譯的binutils和工具鏈中的gcc來編譯目標系統中的gcc,之後就利用剛剛編譯的binutils和gcc來編譯後面的部分,而之後每編譯一個包,在後面的編譯過程中需要用到這個包就是用剛剛編譯好的,而不是工具鏈中的,直到把工具鏈中的所有包都替換成目標系統中的包,工具鏈就算完成目的了。比如在編譯sed包之前,使用的是工具鏈中的sed命令,而當sed包編譯完成之後,再用sed命令的時候,就是用剛剛編譯好的目標系統中的sed命令了。  而在CLFS2.0中,我們知道現在用的是交叉版本的工具鏈,所以編譯出來的是目標體系平台的代碼,那麼是不能在當前的體系平台下運行的,因此,也不會出現LFS中的替換過程,所以在CLFS2.0的方法中,還以sed命令為例,在交叉工具鏈編譯目標體系平台的sed包前用的是主系統的sed命令,而編譯完sed後,再用sed命令時,依然用的還是主系統的sed命令,因為剛剛編譯的sed根本就不能在當前體系平台上運行。  現在我們就清楚了,我們也得出了幾個結論:  1、第六章編譯的包都是運行於目標體系平台的,所以不可以在當前體系平台上運行。  2、在CLFS2.0中第六章部分的binutils和gcc不是必須編譯的,除非你需要在這個系統完成後移植到目標體系的機器中運行並要繼續編譯其它程序才需要編譯binutils和gcc(這點和我以前寫的《體積小巧、功能單一的LFS》思路是一樣的);  3、第六章的包編譯順序是不需要這麼嚴格的,特別是只有命令的包,是可以隨便擺放順序的,比如coreutils這個包,在手冊中是位於gcc之後就編譯了,但實際上即使放在最後一個包編譯也沒問題,因為這個包編譯出來的命令根本就在這裡用不上,部分命令如果覺得在目標系統中根本不用,即使不編譯都可以,比如你不打算在目標體系平台中用patch 命令,你就可以不安裝這個命令,這是不會影響編譯效果的。  4、不是所有的包都可以隨意改變編譯順序的,對於有動態或者靜態庫的文件,如果有其它的包需要,那麼就必須先於依賴於它的包編譯,比如ncurses和readline,因為readline要鏈接ncurses的庫,所以ncurses必須比readline先編譯,否則會導致編譯問題。  5、在整個第六章的過程中都是由主系統中的工具包和交叉編譯工具鏈來完成編譯的,這個時候binutils和gcc的--with-sysroot發揮著重要的作用(binutils中的--with-sysroot終於開始用上了),因為這個參數,使得整個第六章的編譯過程在沒有路徑補丁的情況下變的相對“順利”起來。

關於系統的“純淨度”  說到這裡不得不提我對這裡編譯過程中使用主系統的工具包來完成編譯的看法,就是系統“純淨度”的問題,在LFS的方法中,利用獨立的工具鏈來生成目標系統以保證和原系統“不相干”,而這裡沒有這樣一個完整的工具鏈是否會影響它的“純淨度”呢?  我的回答是:不影響任何“純淨度”。  原因很簡單,對純淨度的影響最主要的就是編譯過程中對原系統中庫的依賴,但實際上我們知道交叉編譯的目的就是為了編譯出運行於其它體系平台的代碼,如果編譯出的代碼和原系統還有關系的話,這個結果就是完全失敗的東西,因為有部分代碼無法在目標體系平台中運行,這是非常失敗的。在CLFS2.0中交叉編譯用的binutils和gcc都新編譯出來的,不是主系統的,因此這方面沒什麼問題(實際上即使主系統提供了交叉編譯的工具,也沒有問題。),接著就是這些主系統提供的工具包是否會帶來“純淨度”的問題,我的一個觀點就是這些工具只是處理諸如文本之類的於平台無關的文件,所以只要能夠正確處理這類文件,就沒問題,這是完全跟“純淨度”無關的因素。當然如果主系統提供的命令不適合或者版本太低,則需要象前面的提到的file和groff的方式一樣——編譯一個。  好了,在講完第六章的的幾個結論後,再來談談第六章編譯的包的安裝問題,對編譯過程比較清楚的朋友基本上都了解一般軟件包的編譯過程./configure 若干參數makemake install  前兩個命令沒什麼問題,最後一個make install,一般會將其安裝到--prefix指定的目錄中,而一般我們在參數中都是用--prefix=/usr這樣的,這個參數是很重要的,有些包在運行過程中都可能受這個參數的影響,那麼我們現在要安裝到${CLFS}才行,如果用這樣的--prefix=/usr參數,又用make install來安裝的話,但願你不是用root來執行的,否則你的系統就要被破壞了。這裡正確的方法是用DESTDIR來指定“根”目錄,如make DESTDIR=${CLFS} install,這很類似前面說明的--with-sysroot的概念,這裡就不多說了,我在做憨牛包管理器的時候就用到了這個方法,很實用,但不是所有的包都支持,但大多數標准的gun包是支持的,可參考各個包的說明,也可以查看代碼來確定。  最後要說的就是關於目標系統如何啟動了,在發稿時為止CLFS2.0還是開發中的版本,而它目前也只有arm和x86兩中體系,x86我們知道可以用grub來做啟動,而arm卻沒有提到,各種體系都有各自的啟動系統,可以參考CLFS1.0中的相應部分。  最後我們來嘗試畫一個CLFS2.0的邏輯圖(圖中未表達出--with-sysroot的作用,但不影響表達CLFS2.0的方法)。 點擊查看大圖  如果觀察仔細的話會發現這副圖裡沒有提到任何Linux的字樣,因為我覺得這樣的方法是適合其它類似的開源系統的,比如BSD。

附錄:PowerPC的工具鏈制作過程及內核編譯環境設置過程(略)export CLFS_HOST="$(echo $MACHTYPE sed "s/$(echo $MACHTYPE cut -d- -f2)/cross/")"export CLFS_TARGET="powerpc-unknown-linux-gnu"echo export CLFS_HOST=\""${CLFS_HOST}\"" >> ~/.bashrcecho export CLFS_TARGET=\""${CLFS_TARGET}\"" >> ~/.bashrcLinux-Kernel-headersmake include/linux/version.hinstall -dv ${CLFS}/usr/include/{asm,asm-generic,linux,net,mtd,scsi,sound}cp -av include/asm-generic/* ${CLFS}/usr/include/asm-genericcp -av include/linux/* ${CLFS}/usr/include/linuxcp -av include/mtd/* ${CLFS}/usr/include/mtdcp -av include/net/* ${CLFS}/usr/include/netcp -av include/scsi/* ${CLFS}/usr/include/scsicp -av include/sound/* ${CLFS}/usr/include/soundinstall -dv ${CLFS}/usr/include/asm-ppccp -av include/asm-powerpc/* ${CLFS}/usr/include/asmcp -av include/asm-ppc/* ${CLFS}/usr/include/asm-ppcbinutils-2.17patch -Np1 -i ../binutils-2.17-posix-1.patchmkdir -v ../binutils-buildcd ../binutils-build../binutils-2.17/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --with-sysroot=${CLFS} \--disable-nls --enable-shared --disable-multilibmake configure-hostmakemake installcp -v ../binutils-2.17/include/libiberty.h ${CLFS}/usr/includeglibc-2.4-headerscp configure{,.orig}sed -e 's/3.4/3.[0-9]/g' configure.orig > configuremkdir -v ../glibc-buildcd ../glibc-buildecho "libc_cv_forced_unwind=yes" > config.cacheecho "libc_cv_c_cleanup=yes" >> config.cacheecho "libc_cv_powerpc32_tls=yes" >> config.cacheecho "libc_cv_ppc_machine=yes" > config.cacheecho "libc_cv_mlong_double_128=yes" >> config.cacheecho "libc_cv_mlong_double_128ibm=yes" >> config.cacheecho "install_root=${CLFS}" > configparmsCC=gcc ../glibc-2.4/configure --prefix=/usr \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--with-headers=${CLFS}/usr/include --cache-file=config.cachemake install-headersinstall -dv ${CLFS}/usr/include/bitscp -v bits/stdio_lim.h ${CLFS}/usr/include/bitstouch ${CLFS}/usr/include/gnu/stubs.hcp -v ../glibc-2.4/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h \${CLFS}/usr/include/bitsgcc-4.1.1第一遍patch -Np1 -i ../gcc-4.1.1-posix-1.patchpatch -Np1 -i ../gcc-4.1.1-cross_search_paths-1.patchmkdir -v ../gcc-buildcd ../gcc-build../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --disable-shared \--enable-languages=cmake all-gccmake install-gccglibc-2.4patch -Np1 -i ../glibc-2.4-libgcc_eh-1.patchpatch -Np1 -i ../glibc-2.4-localedef_segfault-1.patchpatch -Np1 -i ../glibc-2.4-crosscompile_timezone_fix-1.patchpatch -Np1 -i ../glibc-2.4-iconv_fix-1.patchmkdir -v ../glibc-buildcd ../glibc-buildecho "libc_cv_forced_unwind=yes" > config.cacheecho "libc_cv_c_cleanup=yes" >> config.cacheecho "install_root=${CLFS}" > configparmsBUILD_CC="gcc" CC="${CLFS_TARGET}-gcc" \AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \../glibc-2.4/configure --prefix=/usr --libexecdir=/usr/lib/glibc \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--disable-profile --enable-add-ons \--with-tls --enable-kernel=2.6.0 --with-__thread \--with-binutils=${CLFS}/cross-tools/bin --with-headers=${CLFS}/usr/include \--cache-file=config.cachemakemake installcat > ${CLFS}/etc/nsswitch.conf << "EOF"# Begin /etc/nsswitch.confpasswd: filesgroup: filesshadow: fileshosts: files dnsnetworks: filesprotocols: filesservices: filesethers: filesrpc: files# End /etc/nsswitch.confEOFTZDIR="${CLFS}/usr/share/zoneinfo" ${CLFS}/usr/bin/tzselectcp -v --remove-destination ${CLFS}/usr/share/zoneinfo/[xxx] \${CLFS}/etc/localtimecat > ${CLFS}/etc/ld.so.conf << "EOF"# Begin /etc/ld.so.conf/usr/local/lib/opt/lib# End /etc/ld.so.confEOFgcc-4.1.1第二遍patch -Np1 -i ../gcc-4.1.1-posix-1.patchpatch -Np1 -i ../gcc-4.1.1-PR20425-1.patchpatch -Np1 -i ../gcc-4.1.1-cross_search_paths-1.patchmkdir -v ../gcc-buildcd ../gcc-build../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --enable-shared \--enable-languages=c,c++ --enable-__cxa_atexit \--enable-c99 --enable-long-long --enable-threads=posixmakemake installfile-4.17./configure --prefix=${CLFS}/cross-toolsmakemake installGroff-1.19.2PAGE=A4 ./configure --prefix=${CLFS}/cross-tools --without-xmakemake install



工具鏈制作完成目標系統制作export CC="${CLFS_TARGET}-gcc"export CXX="${CLFS_TARGET}-g++"export AR="${CLFS_TARGET}-ar"export AS="${CLFS_TARGET}-as"export RANLIB="${CLFS_TARGET}-ranlib"export LD="${CLFS_TARGET}-ld"export STRIP="${CLFS_TARGET}-strip"echo export CC=\""${CC}\"" >> ~/.bashrcecho export CXX=\""${CXX}\"" >> ~/.bashrcecho export AR=\""${AR}\"" >> ~/.bashrcecho export AS=\""${AS}\"" >> ~/.bashrcecho export RANLIB=\""${RANLIB}\"" >> ~/.bashrcecho export LD=\""${LD}\"" >> ~/.bashrcecho export STRIP=\""${STRIP}\"" >> ~/.bashrcLinux-2.6.17.6make ARCH=powerpc CROSS_COMPILE=${CLFS_TARGET}- menuconfigmake ARCH=powerpc CROSS_COMPILE=${CLFS_TARGET}-make ARCH=powerpc CROSS_COMPILE=${CLFS_TARGET}- \INSTALL_MOD_PATH=${CLFS} modules_installcp vmlinux ${CLFS}/boot/clfskernel-2.6.17.6cp System.map ${CLFS}/boot/System.map-2.6.17.6cp .config ${CLFS}/boot/config-2.6.17.6MIPS的工具鏈制作過程及內核編譯環境設置過程(略)export CLFS_HOST="$(echo $MACHTYPE sed "s/$(echo $MACHTYPE cut -d- -f2)/cross/")"export CLFS_TARGET="mips-unknown-linux-gnu"echo export CLFS_HOST=\""${CLFS_HOST}\"" >> ~/.bashrcecho export CLFS_TARGET=\""${CLFS_TARGET}\"" >> ~/.bashrcLinux-Kernel-headersmake include/linux/version.hinstall -dv ${CLFS}/usr/include/{asm,asm-generic,linux,net,mtd,scsi,sound}cp -av include/asm-generic/* ${CLFS}/usr/include/asm-genericcp -av include/linux/* ${CLFS}/usr/include/linuxcp -av include/mtd/* ${CLFS}/usr/include/mtdcp -av include/net/* ${CLFS}/usr/include/netcp -av include/scsi/* ${CLFS}/usr/include/scsicp -av include/sound/* ${CLFS}/usr/include/soundcp -av include/asm-mips/* ${CLFS}/usr/include/asmbinutils-2.17patch -Np1 -i ../binutils-2.17-posix-1.patchmkdir -v ../binutils-buildcd ../binutils-build../binutils-2.17/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --with-sysroot=${CLFS} \--disable-nls --enable-shared --disable-multilibmake configure-hostmakemake installcp -v ../binutils-2.17/include/libiberty.h ${CLFS}/usr/includeglibc-2.4-headerscp configure{,.orig}sed -e 's/3.4/3.[0-9]/g' configure.orig > configuretar -jxvf ../glibc-ports-2.4.tar.bz2mv -v glibc-ports-2.4 portsecho "" > ports/sysdeps/mips/mips32/Makefilesed -i ‘s/Wordsize.h>$/wordsize.h>\n#define __WORDSIZE 32/g’ bits/types.hmkdir -v ../glibc-buildcd ../glibc-buildecho "libc_cv_forced_unwind=yes" > config.cacheecho "libc_cv_c_cleanup=yes" >> config.cacheecho "libc_cv_mips_tls=yes" >> config.cacheecho "install_root=${CLFS}" > configparmsCC=gcc ../glibc-2.4/configure --prefix=/usr \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--with-headers=${CLFS}/usr/include --cache-file=config.cachemake install-headersinstall -dv ${CLFS}/usr/include/bitscp -v bits/stdio_lim.h ${CLFS}/usr/include/bitstouch ${CLFS}/usr/include/gnu/stubs.hcp -v ../glibc-2.4/ports/sysdeps/unix/sysv/linux/mips/nptl/bits/pthreadtypes.h \${CLFS}/usr/include/bitsgcc-4.1.1第一遍patch -Np1 -i ../gcc-4.1.1-posix-1.patchpatch -Np1 -i ../gcc-4.1.1-cross_search_paths-1.patchmkdir -v ../gcc-buildcd ../gcc-build../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --disable-shared \--enable-languages=cmake all-gccmake install-gccglibc-2.4patch -Np1 -i ../glibc-2.4-libgcc_eh-1.patchpatch -Np1 -i ../glibc-2.4-localedef_segfault-1.patchpatch -Np1 -i ../glibc-2.4-crosscompile_timezone_fix-1.patchpatch -Np1 -i ../glibc-2.4-iconv_fix-1.patchln -s nptl/sysdeps/unix/sysv/linux/i386 ports/sysdeps/unix/mkdir -v ../glibc-buildcd ../glibc-buildecho "libc_cv_forced_unwind=yes" > config.cacheecho "libc_cv_c_cleanup=yes" >> config.cacheecho "install_root=${CLFS}" > configparmsBUILD_CC="gcc" CC="${CLFS_TARGET}-gcc" \AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \../glibc-2.4/configure --prefix=/usr --libexecdir=/usr/lib/glibc \--host=${CLFS_TARGET} --build=${CLFS_HOST} \--disable-profile --enable-add-ons \--with-tls --enable-kernel=2.6.0 --with-__thread \--with-binutils=${CLFS}/cross-tools/bin --with-headers=${CLFS}/usr/include \--cache-file=config.cachemakemake installcat > ${CLFS}/etc/nsswitch.conf << "EOF"# Begin /etc/nsswitch.confpasswd: filesgroup: filesshadow: fileshosts: files dnsnetworks: filesprotocols: filesservices: filesethers: filesrpc: files# End /etc/nsswitch.confEOFTZDIR="${CLFS}/usr/share/zoneinfo" ${CLFS}/usr/bin/tzselectcp -v --remove-destination ${CLFS}/usr/share/zoneinfo/[xxx] \${CLFS}/etc/localtimecat > ${CLFS}/etc/ld.so.conf << "EOF"# Begin /etc/ld.so.conf/usr/local/lib/opt/lib# End /etc/ld.so.confEOF



gcc-4.1.1第二遍patch -Np1 -i ../gcc-4.1.1-posix-1.patchpatch -Np1 -i ../gcc-4.1.1-PR20425-1.patchpatch -Np1 -i ../gcc-4.1.1-cross_search_paths-1.patchmkdir -v ../gcc-buildcd ../gcc-build../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --enable-shared \--enable-languages=c,c++ --enable-__cxa_atexit \--enable-c99 --enable-long-long --enable-threads=posixmakemake installfile-4.17./configure --prefix=${CLFS}/cross-toolsmakemake installGroff-1.19.2PAGE=A4 ./configure --prefix=${CLFS}/cross-tools --without-xmakemake install工具鏈制作完成目標系統制作export CC="${CLFS_TARGET}-gcc"export CXX="${CLFS_TARGET}-g++"export AR="${CLFS_TARGET}-ar"export AS="${CLFS_TARGET}-as"export RANLIB="${CLFS_TARGET}-ranlib"export LD="${CLFS_TARGET}-ld"export STRIP="${CLFS_TARGET}-strip"echo export CC=\""${CC}\"" >> ~/.bashrcecho export CXX=\""${CXX}\"" >> ~/.bashrcecho export AR=\""${AR}\"" >> ~/.bashrcecho export AS=\""${AS}\"" >> ~/.bashrcecho export RANLIB=\""${RANLIB}\"" >> ~/.bashrcecho export LD=\""${LD}\"" >> ~/.bashrcecho export STRIP=\""${STRIP}\"" >> ~/.bashrcLinux-2.6.17.6cp arch/mips/configs/qemu_defconfig .configmake ARCH=mips CROSS_COMPILE=${CLFS_TARGET}- menuconfigmake ARCH=mips CROSS_COMPILE=${CLFS_TARGET}-make ARCH=mips CROSS_COMPILE=${CLFS_TARGET}- \INSTALL_MOD_PATH=${CLFS} modules_installcp vmlinux ${CLFS}/boot/clfskernel-2.6.17.6cp System.map ${CLFS}/boot/System.map-2.6.17.6cp .config ${CLFS}/boot/config-2.6.17.6(轉載請保持文章的完整性,請注明作者和出處)                               作者:沖天飛豹(youbest)                               Email:[email protected]                               2006年8月12日



gcc-4.1.1第二遍patch -Np1 -i ../gcc-4.1.1-posix-1.patchpatch -Np1 -i ../gcc-4.1.1-PR20425-1.patchpatch -Np1 -i ../gcc-4.1.1-cross_search_paths-1.patchmkdir -v ../gcc-buildcd ../gcc-build../gcc-4.1.1/configure --prefix=${CLFS}/cross-tools \--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \--with-sysroot=${CLFS} --disable-nls --enable-shared \--enable-languages=c,c++ --enable-__cxa_atexit \--enable-c99 --enable-long-long --enable-threads=posixmakemake installfile-4.17./configure --prefix=${CLFS}/cross-toolsmakemake installGroff-1.19.2PAGE=A4 ./configure --prefix=${CLFS}/cross-tools --without-xmakemake install工具鏈制作完成目標系統制作export CC="${CLFS_TARGET}-gcc"export CXX="${CLFS_TARGET}-g++"export AR="${CLFS_TARGET}-ar"export AS="${CLFS_TARGET}-as"export RANLIB="${CLFS_TARGET}-ranlib"export LD="${CLFS_TARGET}-ld"export STRIP="${CLFS_TARGET}-strip"echo export CC=\""${CC}\"" >> ~/.bashrcecho export CXX=\""${CXX}\"" >> ~/.bashrcecho export AR=\""${AR}\"" >> ~/.bashrcecho export AS=\""${AS}\"" >> ~/.bashrcecho export RANLIB=\""${RANLIB}\"" >> ~/.bashrcecho export LD=\""${LD}\"" >> ~/.bashrcecho export STRIP=\""${STRIP}\"" >> ~/.bashrcLinux-2.6.17.6cp arch/mips/configs/qemu_defconfig .configmake ARCH=mips CROSS_COMPILE=${CLFS_TARGET}- menuconfigmake ARCH=mips CROSS_COMPILE=${CLFS_TARGET}-make ARCH=mips CROSS_COMPILE=${CLFS_TARGET}- \INSTALL_MOD_PATH=${CLFS} modules_installcp vmlinux ${CLFS}/boot/clfskernel-2.6.17.6cp System.map ${CLFS}/boot/System.map-2.6.17.6cp .config ${CLFS}/boot/config-2.6.17.6(轉載請保持文章的完整性,請注明作者和出處)                               作者:沖天飛豹(youbest)                               Email:[email protected]                               2006年8月12日





Copyright © Linux教程網 All Rights Reserved