嵌入式 linux 根文件系統原理和製作方法

  1. 根文件系統原理

1.1 爲什麼需要根文件系統

一套 linux 體系,只有內核本身是不能工作的,必須要 rootfs 上的 etc 目錄下的配置文件、/bin /sbin 等目錄下的 shell 命令,還有 /lib 目錄下的庫文件等 ···)相配合才能工作 。

1.2 根文件系統的實質

存儲設備(塊設備,像硬盤、flash 等)是分塊(扇區)的,物理上底層去訪問存儲設備時是按照塊號(扇區號)來訪問的。

文件系統是一些代碼,是一套軟件,這套軟件的功能就是對存儲設備的扇區進行管理,將這些扇區的訪問變成了對目錄和文件名的訪問。我們在上層按照特定的目錄和文件名去訪問一個文件時,文件系統會將這個目錄 + 文件名轉換成對扇區號的訪問。不同的文件系統的差異就在於對這些扇區的管理策略和方法不同,譬如壞塊管理、碎片管理。

1.3 根文件系統的形式

以文件夾形式構成的文件系統:

鏡像文件形式的根文件系統主要目的是用來燒錄到塊設備上,設備上的內核啓動後去掛載它。鏡像文件形式的根文件系統是由文件夾形式的根文件系統使用專用的鏡像製作工具製作而成的。

最初在開發主機中隨便 mkdir 創建了一個空文件夾,然後向其中添加一些必要的文件(包括 etc 目錄下的運行時配置文件、/bin 等目錄下的可執行程序、/lib 目錄下的庫文件等 ···)後就形成了一個文件夾形式的 rootfs。然後這個文件夾形式的 rootfs 可以被 kernel 通過 nfs 方式來遠程掛載使用,但是不能用來燒錄塊設備。我們爲了將這個 rootfs 燒錄到塊設備中於是用一些專用的軟件工具將其製作成可供燒錄的一定格式的根文件系統鏡像。

文件夾形式的 rootfs 是沒有格式的,製作成鏡像後就有了一定的 rootfs 格式了,格式是由我們的鏡像製作過程和製作工具來決定的。每一種格式的鏡像製作工具的用法都不同。

1.4 自己製作簡單的根文件系統

1.4.1 動手製作 ext3 格式的根文件系統

mke2fs 是一個應用程序,在 ubuntu 中默認是安裝了的。這個應用程序就是用來製作 ext2、ext3、ext4 等格式的根文件系統的。一般用來製作各種不同格式的 rootfs 的應用程序的名字都很相似,類似於 mkfs.xxx(譬如用來製作 ext2 格式的 rootfs 的工具叫 mkfs.ext2、用來製作 jffs2 格式的 rootfs 的工具就叫 mkfs.jffs2)。ubuntu14.04 中的 mkfs.ext2 等都是 mke2fs 的符號鏈接而已。

  1. 創建 rootfs.ext2 文件並且將之掛載到一個目錄下方便訪問它 《參考資料:http://blog.csdn.net/zhengmeifu/article/details/24174513》
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=2048
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 2048
mount -t ext2 /dev/loop1 ./rootfs/
  1. 我們向鏡像中寫入一個普通文件 linuxrc。這個文件就會成爲我們製作的鏡像中的 / linuxrc。內核掛載了這個鏡像後就會嘗試去執行 / linuxrc。然後執行時必然會失敗。我們將來實驗看到的現象就應該是:掛載成功,執行 / linuxrc 失敗。

  2. 將來真正去做有用的 rootfs 時,就要在這一步添加真正可以執行的 linuxrc 程序,然後還要添加別的 /lib 目錄下的庫文件,/etc 目錄下的配置文件等。

  3. 卸載掉,然後鏡像就做好了。

umount /dev/loop1
losetup -d /dev/loop1

1.4.2 nfs 方式啓動 rootfs

nfs 是一種網絡通訊協議,由服務器和客戶端構成。利用 nfs 協議可以做出很多直接性應用,我們這裏使用 nfs 主要是做 rootfs 掛載。開發板中運行 kernel 做 nfs 客戶端,主機 ubuntu 中搭建 nfs 服務器。在主機 ubuntu 的 nfs 服務器中導出我們製作的文件夾形式的 rootfs 目錄,則在客戶端中就可以去掛載這個文件夾形式的 rootfs 進而去啓動系統。

配置內核以支持 nfs 作爲 rootfs,設置 nfs 啓動方式的 bootargs,在 menuconfig 中配置支持 nfs 啓動方式。

nfs 方式啓動相當於開發板上的內核遠程掛載到主機上的 rootfs,nfs 方式啓動不用製作 rootfs 鏡像。nfs 方式不適合真正的產品,一般作爲產品開發階段調試使用。

setenv bootargs root=/dev/nfs nfsroot=192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs ip=192.168.1.88:192.168.1.104:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200
mount -t nfs -o nolock 192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs  /opt

1.4.3 關於 linuxrc

/linuxrc 如果是靜態編譯連接的那麼直接可以運行;如果是動態編譯連接的那麼我們還必須給他提供必要的庫文件才能運行。但是因爲我們 /linuxrc 這個程序是由內核直接調用執行的,因此用戶沒有機會去導出庫文件的路徑,因此實際上這個 /linuxrc 沒法動態連接,一般都是靜態連接的。

用戶界面等很多事並不是在 /linuxrc 程序中負責的,用戶界面有自己專門的應用程序,但是用戶界面的應用程序是直接或者間接的被 /linuxrc 調用執行的。用戶界面程序和其他的應用程序就是進程 2、3、4·····,這就是我們說的進程 1(init 進程,也就是 /linuxrc)是其他所有應用程序進程的祖宗進程。

busybox 這個程序開發出來就是爲了在嵌入式環境下構建 rootfs 使用的,也就是說他就是專門開發的 init 進程應用程序。

busybox 爲當前系統提供了一整套的 shell 命令程序集。譬如 vi、cd、mkdir、ls 等。在桌面版的 linux 發行版(譬如 ubuntu、redhat、centOS 等)中 vi、cd、ls 等都是一個一個的單獨的應用程序。但是在嵌入式 linux 中,爲了省事我們把 vi、cd 等所有常用的 shell 命令集合到一起構成了一個 shell 命令包,起名叫 busybox。

1.4.4 rootfs 中的其他目錄

在 linux 中一切皆是文件,因此一個硬件設備也被虛擬化成一個設備文件來訪問,在 linux 系統中 / dev/xxx 就表示一個硬件設備,我們要操作這個硬件時就是 open 打開這個設備文件,然後 read/write/ioctl 操作這個設備,最後 close 關閉這個設備。在最小 rootfs 中 /dev 目錄也是不可少的,這裏面有一兩個設備文件是 rootfs 必須的。

在最小 rootfs 中也是不可省略的,但是這兩個只要創建了空文件夾即可,裏面是沒東西的,也不用有東西。這兩個目錄也是和驅動有關的。屬於 linux 中的虛擬文件系統。

  1. 用 busybox 製作一個簡單的 rootfs

2.1 移植 busybox 到開發板

busybox 是一個開源項目,所以源代碼可以直接從網上下載。版本差異不大,版本新舊無所謂。下載 busybox 可以去 linuxidc 等鏡像網站,也可以去 www.busybox.net 官方網站下載。

ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin//arm-none-linux-gnueabi-
Busybox Settings--->
 Build Options--->
  [*]Build BusyBox as a static binary(no shared libs)

Busybox Library Tuning--->
 [*]vi-style line editing commands
 [*]Fancy shell prompts

Linux Module Utilities--->
 [ ]Simplified modutils
 [*]insmod
 [*]rmmod
 [*]lsmod
 [*]modprobe
 [*]depmod

Linux System Utilities--->[*]mdev
 [*]Support /etc/mdev.conf
 [*]Support subdirs/symlinks
 [*]Support regular expressions substitutions when renaming dev
 [*]Support command execution at device addition/removal
 [*]Support loading of firmwares

make 編譯,如果有錯誤解決之,make install 執行的時候其實是在執行 busybox 頂層目錄下的一個目標 install。

make install 在所有的 linux 下的軟件中作用都是安裝軟件。在傳統的 linux 系統中安裝軟件時都是選擇源代碼方式安裝的。我們下載要安裝的軟件源代碼,然後配置、編譯、安裝。make install 的目的就是將編譯生成的可執行程序及其依賴的庫文件、配置文件、頭文件安裝到當前系統中指定(一般都可以自己指定安裝到哪個目錄下,如果不指定一般都有個默認目錄)的目錄下。

之前建立了一個空的文件夾然後自己 touch linuxrc 隨便創建了一個不能用的 /linuxrc 然後去 nfs 掛載 rootfs,實驗結果是:掛載成功,執行 /linuxrc 失敗。現在我們移植了 busybox 後 /linuxrc 就可以用了,然後再次去 nfs 掛載這個 rootfs。預計看到的效果是:掛載成功,執行 / linuxrc 也能成功。

uboot 的 bootargs 設置成:

setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200

掛載成功,執行 /linuxrc(也就是 busybox)成功,但是因爲找不到 /etc/init.d/rcS 和 /dev/tty2 等文件所以一直在打印錯誤提示信息,但是其實有進入命令行。

2.2 inittab 詳解

將一個典型的 inittab 文件複製到我們製作的 rootfs 的根目錄下的 /etc/ 目錄下,再次啓動內核掛載這個 rootfs 看效果,實驗現象是成功啓動並且掛載 rootfs 進入了控制檯命令行。當前製作的最小 rootfs 成功了。

inittab 的工作原理就是被 /linuxrc(也就是 busybox)執行時所調用起作用。

inittab 在 /etc 目錄下,所以屬於一個運行時配置文件,是文本格式的(內容是由一系列的遵照一個格式組織的字符組成的),實際工作的時候 busybox 會(按照一定的格式)解析這個 inittab 文本文件,然後根據解析的內容來決定要怎麼工作。

busybox 究竟如何完成解析並且解析結果如何去工作(busybox 中實現 /etc/inittab 的原理)並不是我們的目標,我們的重點是 inittab 的格式究竟怎樣的?我們看到一個 inittab 後怎麼去分析這個 inittab 對啓動的影響。inittab 的格式在 busybox 中定義的。

第一個:# 開始的行是註釋 第二個:冒號在裏面是分隔符,分隔開各個部分。第三個:inittab 內容是以行爲單位的,行與行之間沒有關聯,每行都是一個獨立的配置項,每一個配置項表示一個具體的含義。第四個:每一行的配置項都是由 3 個冒號分隔開的 4 個配置值共同確定的。這四個配置值就是 id:runlevels:action:process。值得注意的是有些配置值可以空缺,空缺後冒號不能空缺,所以有時候會看到連續 2 個冒號。第五個:每一行的配置項中 4 個配置值中最重要的是 action 和 process,action 是一個條件 / 狀態,process 是一個可被執行的程序的 pathname。合起來的意思就是:當滿足 action 的條件時就會執行 process 這個程序。

理解 inittab 的關鍵就是明白 “當滿足 action 的條件時就會執行 process 這個程序。” 分析 busybox 的源代碼就會發現,busybox 最終會進入一個死循環,在這個死循環中去反覆檢查是否滿足各個 action 的條件,如果某個 action 的條件滿足就會去執行對應的 process。

  1. busybox 源碼分析

3.1 分析 busybox 啓動狀況

分析一個程序,不管多龐大還是小,最好的路線都是按照程序運行時的邏輯順序來。所以找到一個程序的入口至關重要。主函數 main 函數就是整個程序的入口,這種情況適應於操作系統下工作的應用程序的情況。

在 uboot 和 linux kernel 這兩個大的 C 語言的項目中,main 函數都沒有,都不是入口。在我們這種裸機程序中入口不是 main 函數,而是由連接腳本來指定的。

busybox 是 linux 啓動起來後工作的一個應用程序,因此其中必然有 main 函數,而且 main 就是入口。

3.2 busybox 中 main 函數全解析

busybox 入口就是 main 函數,其中有很多個 main 但是隻有一個起作用了,其他的是沒起作用的。真正的 busybox 工作時的入口是 libbb/appletlib.c 中的 main 函數。

busybox 中有很多 xxx_main 函數,這些 main 函數每一個都是 busybox 支持的一個命令的真正入口。例如 ls_main 函數就是 busybox 當作 ls 函數使用時的入口程序。ls 或者 cd 等命令其實都是 busybox 一個程序,但是實際執行時的效果卻是各自的效果。

busybox 每次執行時都是先執行其 main,在 main 函數中識別(靠 main 函數的傳參 argv[0] 來識別)我們真正要執行的函數(譬如 ls)然後去調用相應的 xxx_main(譬如 ls_main)來具體實現這個命令。

3.3 inittab 解析與執行

inittab 的解析是在 busybox/init/init.c/init_main 函數中。執行邏輯是:先通過 parse_inittab 函數解析 /etc/inittab(解析的重點是將 inittab 中的各個 action 和 process 解析出來),然後後面先直接執行 sysinit 和 wait 和 once(注意這裏只執行一遍),然後在 while(1) 死循環中去執行 respwan 和 askfirst。

3.4 busybox 的體積優勢原理

busybox 實際上就是把 ls、cd、mkdir 等很多個 linux 中常用的 shell 命令集成在一起了。集成在一起後有一個體積優勢:就是 busybox 程序的大小比 busybox 中實現的那些命令的大小加起來要小很多。

busybox 體積變小的原因主要有 2 個:

busybox 的體積優勢是嵌入式系統本身的要求和特點造成的。

  1. rcS 文件分析與實戰

4.1 rcS 文件介紹

/etc/init.d/rcS 文件是 linux 的運行時配置文件中最重要的一個,其他的一些配置都是由這個文件引出來的。這個文件可以很複雜也可以很簡單,裏面可以有很多的配置項。

首先從 shell 腳本的語法角度分析,這一行定義了一個變量 PATH,值等於後面的字符串,後面用 export 導出了這個 PATH,那麼 PATH 就變成了一個環境變量。

PATH 這個環境變量是 linux 系統內部定義的一個環境變量,含義是操作系統去執行程序時會默認到 PATH 指定的各個目錄下去尋找。如果找不到就認定這個程序不存在,如果找到了就去執行它。將一個可執行程序的目錄導出到 PATH,可以讓我們不帶路徑來執行這個程序。

因爲我們希望一旦進入命令行下時,PATH 環境變量中就有默認的 /bin /sbin /usr/bin /usr/sbin 這幾個常見的可執行程序的路徑,這樣我們進入命令行後就可以 ls、cd 等直接使用了。

爲什麼 rcS 文件還沒添加,系統啓動就有了 PATH 中的值?原因在於 busybox 自己用代碼硬編碼爲我們導出了一些環境變量,其中就有 PATH。

runlevel 也是一個 shell 變量,並且被導出爲環境變量,runlevel=S 表示將系統設置爲單用戶模式。

umask 是 linux 的一個命令,作用是設置 linux 系統的 umask 值。umask 值決定當前用戶在創建文件時的默認權限。

mount -a 是掛載所有的應該被掛載的文件系統,在 busybox 中 mount -a 時 busybox 會去查找一個文件 /etc/fstab 文件,這個文件按照一定的格式列出來所有應該被掛載的文件系統(包括了虛擬文件系統)

mdev 是 udev 的嵌入式簡化版本,udev/mdev 是用來配合 linux 驅動工作的一個應用層的軟件,udev/mdev 的工作就是配合 linux 驅動生成相應的 /dev 目錄下的設備文件。

在 rcS 文件中沒有啓動 mdev 的時候,/dev 目錄下啓動後是空的。在 rcS 文件中添加上 mdev 有關的 2 行配置項後,再次啓動系統後發現 /dev 目錄下生成了很多的設備驅動文件。(4)/dev 目錄下的設備驅動文件就是 mdev 生成的,這就是 mdev 的效果和意義。

hostname 是 linux 中的一個 shell 命令。命令(hostname xxx)執行後可以用來設置當前系統的主機名爲 xxx,直接 hostname 不加參數可以顯示當前系統的主機名。

/bin/hostname -F /etc/sysconfig/HOSTNAME -F 來指定了一個主機名配置文件(這個文件一般文件名叫 hostname 或者 HOSTNAME)

有時候我們希望開機後進入命令行時 ip 地址就是一個指定的 ip 地址(譬如 192.168.1.30),這時候就可以在 rcS 文件中 ifconfig eth0 192.168.1.88

4.2 rcS 文件測試問題記錄

發現 rcS 文件明明存在但是卻提示不存在,問題原因就是 rcS 文件在 windows 下創建的,行尾換行符爲 '\r\n',多了點東西。但是因爲 ubuntu 中的 vi 對行尾做了優化,所以在 ubuntu 中是看不出來多了東西的。但是在 securecrt 下一看就發現每一行末尾多出來了一個 ^M。

這個情況表明:shell 腳本文件如果格式不對,運行時可能會被提示文件不存在。有時候一個應用程序執行時也會提示文件不存在,問題可能是這個程序所調用的一個動態鏈接庫找不到。

測試結果:PATH 本來在 busybox 中就已經用代碼導出過了,所以 rcS 中再次導出沒有任何明顯的現象,因此看不出什麼差別。runlevel 實際執行結果一直是 unknown,問題在於 busybox 並不支持 runlevel 這個特性。

umask 是 022 的時候,默認 touch 創建一個文件的權限是 644 umask 是 044 的時候,默認 touch 創建一個文件的權限是 622 umask 是 444 的時候,默認 touch 創建一個文件的權限是 222

總結:umask 的規律就是:umask 值和默認創建文件的權限值加起來是 666。

掛載時全部出錯:

mount: mounting proc on /proc failed: No such file or directory
mount: mounting sysfs on /sys failed: No such file or directory
mount: mounting tmpfs on /var failed: No such file or directory
mount: mounting tmpfs on /tmp failed: No such file or directory
mount: mounting tmpfs on /dev failed: No such file or directory

原因是因爲根文件系統中找不到掛載點。所謂掛載點就是我們要將目標文件系統(當然這裏都是虛擬文件系統)掛載到當前文件系統中的某一個目錄中,這個目錄就是掛載點。

解決方案就是自己在製作的 rootfs 根目錄下創建這些掛載點目錄即可。驗證是否掛載成功,可以看掛載時輸出信息;還可以啓動後去看 proc 和 sys 文件夾,如果有文件出現則證明掛載成功了,如果沒東西就證明失敗了。

4.3 開機自啓動與主流 rcS 格式介紹

機自啓動指的是讓一些應用程序能夠開機後自動執行,開機自啓動的實現原理就是在開機會自動執行的腳本 rcS 中添加上執行某個程序的語句代碼即可。

程序運行時佔用了當前的控制檯,因此這個程序不結束我們都無法使用控制檯,這就叫前臺運行。默認執行程序就是前臺運行的。

後臺運行就是讓這個程序運行,並且同時讓出控制檯。這時候運行的程序還能照常運行而且還能夠不影響當前控制檯的使用。讓一個程序後臺運行的方法就是 ./xxx &。開機裝載驅動等其他開機自動執行

分析 inittab 發現:sysinit 執行 rcS,shutdown 時執行 rcK。

分析 /etc/init.d/rcS 和 rcK 文件發現,rcS 和 rcK 都是去遍歷執行 /etc/init.d/ 目錄下的 S 開頭的腳本文件,區別是 rcS 傳參是 start,rcK 傳參是 stop。

由此可以分析出來,正式產品中的 rcS 和 rcK 都是一個引入,而不是真正幹活的。真正幹活的配置腳本是 /etc/init.d/S??*。這些文件中肯定有一個判斷參數是 start 還是 stop,然後 start 時去做一些初始化,stop 時做一些清理工作。

  1. 添加動態鏈接庫

自己寫一個 helloworld 程序,然後交叉編譯連接,然後丟到開發板根文件系統中,開機後去運行。C 程序如果使用 gcc 來編譯則可以在主機 ubuntu 中運行,但是不能在開發板運行。要在開發板運行需要用 arm-linux-gcc 來交叉編譯,但是這時候就不能在主機 ubuntu 中運行了。可以用 file xx 命令來查看一個 elf 可執行程序是哪個架構的。

靜態鏈接:arm-linux-gcc hello.c -o hello_satic -static

靜態編譯連接後生成的 hello_satic 可以直接在開發板上運行。

動態鏈接:arm-linux-gcc hello.c -o hello_dynamic

實驗結果:-sh: ./hello_dynamic: not found 運行時提示找不到程序。

原因是動態連接的 hello 程序中調用到了 printf 函數,而 printf 函數在動態連接時要在運行時環境(開發板的 rootfs)中去尋找對應的庫文件(開發板 rootfs 中部署的動態鏈接庫中包含了 printf 函數的那個庫文件)。如果找到了則 printf 函數就會被成功解析,然後 hello_dynamic 程序就會被執行;如果找不到則程序就不能被執行,命令行會提示錯誤信息

-sh: ./hello_dynamic: not found

解決方案:將 arm-linux-gcc 的動態鏈接庫文件複製到開發板 rootfs 的 /lib 目錄下即可解決。

現在使用的 arm-2009q3 這個交叉編譯工具鏈的動態鏈接庫在 /usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib 目錄下。其他的一些交叉編譯工具鏈中動態鏈接庫的目錄不一定在這裏,要去找一下。找的方法就是 find 命令,find -name *libm.so*

複製動態鏈接庫到 roots/lib 目錄下。複製時要注意參數用 -rdf,主要目的就是符號鏈接複製過來還是符號鏈接。

複製命令:

cp lib/ /home/SummerGift/work/samsung_kernel/rootfs/rootfs -r

拷貝動態鏈接庫到根文件系統之後,再去測試 ./hello_dynamic 就可以直接運行了。

動態鏈接庫 so 文件中包含了調試符號信息,這些符號信息在運行時是沒用的(調試時用的),這些符號會佔用一定空間。在傳統的嵌入式系統中 flash 空間是有限的,爲了節省空間常常把這些符號信息去掉。這樣節省空間並且不影響運行。

去掉符號命令:arm-none-linux-gnueabi-strip *so*

使用該命令後發現庫文件由 3.8M 變成了 3.0M,節省了 0.8M 的空間。

  1. 製作 ext2 格式的鏡像並燒錄啓動

設置 bootargs 爲 nfs 啓動方式,然後從主機 ubuntu 中做好的文件夾格式的 rootfs 去啓動,然後看啓動效果,作爲將來的參照物。

dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 10240
mount -t ext2 /dev/loop1 ./ext2_rootfs/

向 ./rootfs 中複製內容,用cp ../rootfs/* ./ -rf

umount /dev/loop1

losetup -d /dev/loop1

完成後得到的 rootfs.ext2 就是我們做好的 rootfs 鏡像。拿去燒錄即可。

使用 fastboot 燒錄製作好的 rootfs.ext2 到開發板 inand 中

fastboot flash system rootfs.ext2

燒錄完成後重啓系統,設置 bootargs 爲:

set bootargs console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext2

啓動後發現現象和之前 nfs 方式啓動掛載 rootfs 後一樣的,至此 rootfs 製作實驗圓滿完成。

  1. 常見 BSP 結構

7.1 嵌入式 linux 產品的 bsp 介紹

大部分的 ARM 架構的 linux 平臺的 bsp 的內容和結構都是相似的,bsp 一般是芯片廠家 / 板卡廠家提供的。

xboot 和 uboot 是 X210 支持的 2 個 bootloader 源代碼。kernel 文件夾中是內核源代碼,buildroot 文件夾是用來構建根文件系統的文件夾。tools 裏是一些有用工具。

7.2 mk 腳本

mk 腳本是用來管理和編譯整個 bsp 的。

mk 腳本的主要作用是編譯 bsp 中的所有的源代碼(包括 bootloader、kernel、rootfs 等),但是我們可以完整編譯也可以部分編譯,我們通過執行 mk 後面加不同的參數來指定 mk 腳本去編譯相應的部分。

mk -a 即可編譯所有的bsp源代碼
mk -x 即可只編譯xboot
mk -ui 即可只編譯uboot針對inand版本開發板的源代碼
mk -r   即可只編譯buildroot,-r只是得到了文件夾形式的rootfs,並沒有將其製作成鏡像文件。
mk -re 即可編譯buildroot並且製作得到ext3格式的rootfs鏡像
mk -rj 即可編譯buildroot並且製作得到jffs2格式的rootfs鏡像

注:./mk和 mk 都是執行 mk 這個腳本文件,區別在於 ./mk 是帶路徑的,mk 是不帶路徑的。還有 source mk,這個和前兩個的區別是 source 執行時不需要 mk 文件具有可執行權限,而前面兩種要求 mk 必須在當前用戶下具有可執行權限。

7.3 mk 文件分析

shell 腳本程序分爲:變量定義、函數、代碼。shell 腳本程序的結構非常類似於 C 語言程序。

shell 程序和 C 語言程序很大的一個差別就是 shell 沒有 main 函數,shell 腳本執行時也是先執行主函數的,不過主函數沒有放在一個類似於 main 這樣的函數中,而是直接放在全局下的一些代碼。

shell 程序執行時首先執行變量定義,然後執行主函數,其他函數在主函數代碼中被調用執行。

如果直接./mk 並不傳參,則 $1 爲空,這時候按照一套默認的配置來編譯。

  1. buildroot 使用方法

8.1 buildroot 介紹

之前自己從零開始構建根文件系統,一路下來事情還挺多,步驟比較麻煩。

交叉編譯工具鏈 arm-linux-gcc,我們目前都是從 soc 官方直接拿來使用的,官方的工具鏈從何而來?實際上交叉編譯工具鏈都是由 gcc 配置編譯生成的,這個配置編譯過程比較複雜,一般人自己去配置編譯得到自己的交叉編譯工具鏈是比較麻煩的,所以經常都是用別人最好的。

buildroot 就是一個集成包,這個包裏集成了交叉編譯工具鏈的製作,以及整個 rootfs 的配置編譯過程。也就是說,使用 buildroot 可以很簡便的得到一個做好的文件夾形式的根文件系統。

buildroot 將很多東西集成進來後,移植了 linux kernel 的 make xxx_defconfig+make menuconfig的 2 步配置法,我們可以在 buildroot 的配置界面下完成集成在裏邊的所有東西的配置,然後直接 make 就可以最終得到文件夾形式的 rootfs。

8.2 使用 buildroot 構建根文件系統

編譯 buildroot 的錯誤解決方案(環境爲 ubuntu14.04)

make xxx_defconfig
make menuconfig
make
sudo apt-get install g++ bison flex texinfo git hgsubversion whois

編譯後生成的文件夾格式的 rootfs 在 buildroot/output/images/rootfs.tar。我們將其複製到了根目錄下的 release 目錄下去,這個文件就是一個完整的可以工作的文件夾形式的 rootfs。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6i5O_0LdzmwmdgjqCFT-4w