看過很多文章,都沒有明白怎樣製作一個檔案系統,在網上發現有這麼一篇好文章,這是幸運! 轉載之,希望讓更多的人受益。 (當然我在實踐的過程中,把有些不對的地方給改了過來,忘原作者不要介意) ++++++++++++++++++++++++++++++++++++++++ 作者:惆悵的桶(tongmvp) 日期:2008-2-22 著作權聲明:轉載請註明出處 ++++++++++++++++++++++++++++++++++++++++ 從零構建一個400K的嵌入式Linux根檔案系統UCFS 所謂根檔案系統,即可以作啟動盤的檔案系統。根檔案系統(以下在不引起歧義的地方簡稱檔案系統)主要包括etc/、bin/、sbin/、lib/、proc/等五個根目錄。建立根檔案系統使用了busybox工具,同時,為了保持交叉編譯器和檔案系統庫的一致性,以buildroot、uClibc和gcc等工具構建了一個交叉編譯器。檔案系統使用buildroot工具編譯的uClibc庫。使用該方法建立的檔案系統壓縮後可以達到400K左右。 1.1 利用buildroot製作交叉編譯器 1.1.1 buildroot簡介 作為嵌入式系統,最為緊缺的資源就是儲存空間。精簡嵌入式系統所使用的庫是減小儲存空間最常用的方法之一。GNU的Glibc是一個非常寵大而完整的庫,至少對於嵌入式系統來說,其體積顯得過於大了一些。uClibc的提出較好的解決了這樣一個問題。uClibc儘可能的相容Glibc,大多數應用程式可以在很小或完全不修改的情況下就可能使用uClibc替代glibc。通過uClibc來代替Glibc,可以在不改變應用程式功能的前提下,大大減少發布檔案的大小,無論應用程式以靜態連結來編譯,還是以動態連結形式編譯。 不過使用uClibc代替並不是簡單的設定一兩個參數就行了,通常需要使用一個不同的工具集(gcc/binutils等)來編譯代源碼。手工的構造這樣一個環境,對於大多數普通程式員來說,不一定是一件很簡單的事情,因此,uClibc的開發人員創造出一個叫做buildroot的工具集。 buildroot將自動構造編譯基於uClibc代碼的工具集和uClibc庫,並提供一個可配置的架構和一些構建一個基本系統的設定檔。使用者只需要通過配置菜單選擇了相應的目標軟體,buildroot就可以從構建基本工具集開始,一直到最後構建出目標系統所需要的東西,如嵌入式系統常用的基於ext2的initrd,jffs根檔案系統,壓縮的根目錄樹等,這些代碼都是基於uClibc而不是系統的Glibc的。Buildroot對主機系統的要求較小,通常只需要主機系統提供足以構建工具鏈(toolchain)的工具,如gcc/binutils等,當工具鏈編譯完成後,對目標系統需要的源碼的編譯過程與主機系統的開發工具集基本上就沒有什麼關係了。因此,不同的主機如果能夠通過第一步,編譯完成工具鏈,那麼編譯出來的目標系統的執行代碼就可以幾乎不存在由於系統引起的差異。這樣,開發人員就可能在各自喜歡的Linux發行版上進行開發,而不必擔心出現什麼相容性問題。 1.1.2 下載相關資源 下載http://buildroot.uclibc.org/downloads/old/buildroot-0.9.27.tar.gz,建立/home/br目錄,將buildroot-0.9.27.tar.gz拷貝到該目錄,執行下面的命令解壓縮,得到目錄buildroot。 tar –zxvf buildroot-0.9.27.tar.gz 進入buildroot目錄。buildroot預設情況情況下使用wget從互連網下載所需的相關資源,在這裡,建立dl目錄,作為資源的存放目錄。 cd buildroot mkdir dl 接下來,需要下載http://www.uclibc.org/downloads/uClibc-0.9.27.tar.bz2,並在http://buildroot.uclibc.org/downloads/buildroot-sources/下載ccache-2.3.tar.gz、binutils-2.15.91.0.2.tar.bz2、genext2fs_1.3.orig.tar.gz、linux-libc-headers-2.4.27.tar.bz2。最後還需下載http://ftp.gnu.org/gnu/gcc/gcc-3.3.4/gcc-3.3.4.tar.bz2,一共六個檔案,全部拷貝到剛才建立的dl目錄。 1.1.3 配置 返回buildroot目錄,運行make menuconfig命令配置buildroot,見:
圖 1-1 buildroot配置介面
Target Architecture(arm) --->選擇arm,因為目標板CPU為AT91RM9200,為ARM 920T系列。 Build options ---> ()wget command 因為所有的工具已經下載到dl本地目錄,故不需要從互連網下載資源,將此項清空。 [ ]Tar verbose ($BUILD_DIR/staging_dir) Toolchain and header file location?這個選項表明編譯產生的交叉編譯器所在目錄,不用修改。 (1) Number of jobs to run simultaneously。 Toolchain Options ---> --- Kernel Header Options Kernel Headers (Linux 2.4.27 kernel headers) ---> 注意核心標頭檔版本和目標板將使用的核心版本一致。我的目標板是2.4.19,使用了一個較為接近的2.4.27替代,目前看來沒有太大的問題。 --- uClibc Options [ ] Use daily snapshot of uClibc?是否使用最新版本的uClibc。 [ ] Enable local/gettext/i18n support? --- Binutils Options Bintuils Version (bintuils 2.15.91.0.2) ---> --- Gcc Options GCC compiler Version (gcc 3.3.4) --> ( ) Additional gcc options [ * ] Build/install c++ compiler and libstdc++> [ ] Build/install java compiler and libgcj? --- Cache Options [ * ] Enable ccache support? 不啟用ccache的支援,否則將來在製作交叉編譯器時可能因為符號連結而提出標頭檔路徑出錯的問題。 --- Gdb Options [ ] Build gdb degugger for the Target [ ] Build gdb server for the Target --- Common Toolchain Options [ ] Enable multilib support? [ ] Enable large file (files > 2GB) support? [ ] Use software floating point by default (-Os –pipe) Target Optimizations Package Selection for the target ---> 這一項沒有選擇任意一項,busybox我是手工完成的,並不打算讓buildroot自動構建。 Target Options ---> [ ] cr amfs root filesystem for the target device [ * ] ext2 root filesystem for the t arget device [ ] jffs2 root filesystem for the target device [ ] squashfs root filesystem for the target device 最後退出配置介面,並選擇儲存設定。 1.1.4 編譯 執行make命令編譯buildroot,在編譯過程中有三個提示,首選是詢問ARM版本,選擇920T,然後詢問端模式,選擇Little Endian,由於9200是帶有MMU的,所以詢問MMU時選擇Y。 編譯過程在我的VMWare虛擬中持續了大半個小時。 我們需要的交叉編譯器現在就在build_arm/staging_dir目錄下。這下面最關心的三個目錄:bin、lib、include。bin目錄包含了所有的交叉編譯器,我們關注的是以arm-linux-uclibc-開頭的這一組編譯器。lib目錄是uclibc編譯的結果,inlcude是2.4.27核心標頭檔。 3.3.4的交叉編譯器就算完成了。交叉編譯器的製作涉及的工具很多,編譯的時間很長,非常考驗一個人的耐心。下一步,將利用這個交叉工具鏈去編譯busybox。 1.2 利用busybox製作二進位工具 1.2.1 busybox簡介 BusyBox 是很多標準 Linux? 工具的一個單個可執行實現。BusyBox 包含了一些簡單的工具,例如 cat 和 echo,還包含了一些更大、更複雜的工具,例如 grep、find、mount 以及 telnet(不過它的選項比傳統的版本要少);有些人將 BusyBox 稱為 Linux 工具裡的瑞士軍刀。本文將探索 BusyBox 的目標,它是如何工作的,以及為什麼它對於記憶體有限的環境來說是如此重要。 BusyBox 的誕生BusyBox 最初是由 Bruce Perens 在 1996 年為 Debian GNU/Linux 安裝盤編寫的。其目標是在一張磁碟片上建立一個可引導的 GNU/Linux 系統,這可以用作安裝盤和急救盤。一張磁碟片可以儲存大約 1.4-1.7MB 的內容,因此這裡沒有多少空間留給 Linux 核心以及相關的使用者應用程式使用。 BusyBox 揭露了這樣一個事實:很多標準 Linux 工具都可以共用很多共同的元素。例如,很多基於檔案的工具(比如 grep 和 find)都需要在目錄中搜尋檔案的代碼。當這些工具被合并到一個可執行程式中時,它們就可以共用這些相同的元素,這樣可以產生更小的可執行程式。實際上, BusyBox 可以將大約 3.5MB 的工具封裝成大約 200KB 大小。這就為可引導的磁碟和使用 Linux 的嵌入式裝置提供了更多功能。我們可以對 2.4 和 2.6 版本的 Linux 核心使用 BusyBox。 為了讓一個可執行程式看起來就像是很多可執行程式一樣,BusyBox 為傳遞給 C 的 main 函數的參數開發了一個很少使用的特性。回想一下 C 語言的 main 函數的定義如下: int main( int argc, char *argv[] ) 在這個定義中,argc 是傳遞進來的參數的個數(參數數量),而 argv 是一個字串數組,代表從命令列傳遞進來的參數(參數向量)。argv 的索引 0 是從命令列調用的程式名。利用這個性質,我們可以建立一個到可執行程式的符號連結,在執行這個符號連結時,這個符號連結的名字就是argv[0]。 BusyBox 使用了符號連結以便使一個可執行程式看起來像很多程式一樣。對於 BusyBox 中包含的每個工具來說,都會這樣建立一個符號連結,這樣就可以使用這些符號連結來調用 BusyBox 了。BusyBox然後可以通過 argv[0] 來調用內部工具。 1.2.2 下載資源 下載http://www.busybox.net/downloads/busybox-1.00.tar.bz2,建立/home/busybox目錄,將busybox-1.00.tar.bz2拷貝到該目錄,執行tar –jxvf busybox-1.00.tar.bz2解壓縮,得到busybox-1.00目錄。進入該目錄,下一步就是配置busybox並編譯和安裝了。 1.2.3 配置和安裝 在busybox-1.00目錄中執行make menuconfig命令進入busybox的配置介面,見:
圖 1-2 busybox配置介面
由於選項較多,只羅列主要選項,每有提高的採用預設選項: General Configuration ---> Buffer allocation policy(Allocate on the Stack) ---> [ * ] Show verbose applet usage messages [ * ] Support for devfs [ * ] Use the devpts filesystem for Unix98 PTYs Build Options ---> [ ] Build BusyBox as a static binary (no share libs) 這一項不選,即採用動態庫德方式,可 以節省幾百K的空間。 [ * ] Do you want to build BusyBox with a Cross Compiler? (/home/br/buildroot/build_arm/staging_dir/bin/arm-linux-uclibc-) Cross Compiler 指定交叉編譯器,即為利用buildroot構建的交叉編譯器路徑。 [ * ] Don’t use /usr 這一項一定要選中,不然會覆蓋/usr下面的庫。 (./_install) BusyBox installation prefix 安裝路徑,執行make install後會在busybox-1.00目錄下產生_install目錄,包含了busybox編譯結果和相關的工具符號串連。 Archival Utilities ---> 主要涉及文檔壓縮和解壓縮的相關工具,保持預設選項即可。 Editors ---> 去掉vi,基本上不再嵌入式目標板上運行vi編輯器。 Finding Utilities ---> Init Utilities ---> 一定要選中init選項,其它保持預設。 Login/Password Management Utilities ---> 選中gettty,事實上,還需要mingetty,不過busybox不支援,只有後面手工編譯並加入到檔案系統中。 Miscellaneous Utilities ---> Linux Module Utilities ---> 動態模組載入相關,動態載入模組給應用程式調試帶來很大的方便,所以選擇支援,因為核心是2.4版本,所以該項選中以下選項: [ * ] insmod [ * ] Support version 2.2.x to 2.4.x Linux kernels [ * ] lsmod [ * ] modprobe [ * ] rmmod [ * ] Support tainted module checking with new kernels Another Bourne-like Shell ---> 選中ash作為預設的bash,這可以節省很多空間。 Linux System Utilities ---> 為了支援NFS,注意將以下三項選中 [ * ] mount [ * ] Support mounting NFS file system [ * ] umount loop裝置使用較多,這裡也選中 [ * ] Support for loop devices Debugging Options ---> 不需要偵錯符號 配置結束後儲存設定,退出配置介面。 1.2.4 編譯安裝 執行make編譯busybox,編譯結束後執行make install,則會在busybox-1.00目錄下產生_install目錄,其中又包含了bin和sbin兩個子目錄。兩個子目錄中除了busybox檔案外,其他均是指向該檔案的符號串連。 到這一步,busybox已經編譯完了,接下來就是構建根檔案系統,因為該檔案系統是基於uclibc構建的,我將其稱之為ucfs。 1.3 構建ucfs 1.3.1 利用loop裝置建立檔案系統 進入/tmp目錄,並建立/mnt/ucfs目錄作為將來的掛載位置。執行dd if=/dev/zero of=ucfs bs=1k count=15360,建立一個15M的檔案,該檔案全部被初始化為0。如果反覆在一個檔案系統上執行增加或刪除操作,會使本來沒有使用的部分也難以壓縮,將未使用部分初始化為0能夠使該部分被壓縮。 使用losetup命令將loop裝置和ucfs檔案關聯:losetup –e none /dev/loop0 ucfs。如果loop0已被使用,可以使用loop1,loop2等。 在loop裝置上建立ext2檔案系統:mke2fs -m 0 /dev/loop0 15360。-m 0的作用是不為root保留使用空間,從而提高檔案系統的利用率。 注意:如果找不到losetup和mke2fs命令的話,請在前面加上/ sbin/n 就可以了。 負載檔案系統:mount -t ext2 /dev/loop0 /mnt/ucfs。 接下來進入/mnt/ucfs目錄,可以看到裡面已經有了一個lost+found目錄。在/mnt/ucfs目錄中添加相關的檔案和目錄(接下來馬上講解),完成根檔案系統的構建。 1.3.2 安裝二進位工具、庫及其他 在上一小節最後提高的卸載/dev/loop0之前,首先需要在/mnt/ucfs中添加用於製作根檔案系統的目錄及相關檔案。先拷貝二進位工具,即busybox工具集。cp –a /home/busybox/busybox-1.00/_install/* /mnt/ucfs,將busybox和相關的符號串連拷貝到ucfs,觀察/mnt/ucfs,增加了bin和sbin目錄,刪除linuxrc符號串連。 接下來,拷貝交叉編譯器中的uclibc庫。進入交叉編譯器的lib目錄,cd /home/br/buildroot/build_arm/staging_dir/lib。然後拷貝必要的庫。cp -a *-*.so /mnt/ucfs/lib,cp -a *.so.[*0-9] /mnt/ucfs/lib。回到/mnt/ucfs/lib目錄,刪除libstdc++,暫時不用c++的標準庫, rm –f libstdc++*。 接下來,利用busybox的樣本來構建/etc目錄。進入/home/busybox/busybox-1.00/example/bootfloppy目錄。拷貝etc目錄到/mnt/ucfs,cp –r /etc /mnt/ucfs。關於建立根檔案系統,可以仔細閱讀bootfloppy.txt檔案,很有參考價值。在這裡,需要修改busybox預設建立的inittab檔案,vi /mnt/ucfs/etc/inittab,將最後兩行刪除,只保留以下兩行: ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh 最後還需建立空目錄,/mnt/ucfs/proc。至此,根檔案系統製作完畢。最後離開/mnt/ucfs以便卸載loop0裝置。執行umount /dev/loop0和losetup –d /dev/loop0,使修改儲存到ucfs。這個ucfs由gzip壓縮後就可以作為系統的根檔案系統了。使用gzip –v9 ucfs壓縮後,ucfs.gz只有407304位元組,不到400K! 最後來看一看成果,見。大功告成!
圖 1-3 自製檔案系統啟動介面
|