文章目錄
1. 根檔案系統布局
嵌入式 Linux 根檔案系統布局,建議還是按照FHS标準來安排,事實上大多數嵌入式Linux都是這樣做的。但是,嵌入式系統可能并不需要桌面/伺服器那樣龐大系統的全部目錄,可以酌情對系統進行精簡,以簡化Linux的使用。如嵌入式Linux檔案系統中通常不會放置核心源碼,因而存的 常不會放置核心源碼,因而存的 常不會放置核心源碼,因而存放源碼的 /usr/src目錄是不必要的, 甚至連頭檔案也不需要,即/usr/include目錄也不必要;但是 /bin、/dev 、/etc、/lib 、/proc 、/sbin、/usr幾個目錄是不可或缺的。
是以,允許嵌入式 Linux 對系統目錄結構進行精簡,以适應具體用場合的需求,一個典型的嵌入式Linux根檔案系統目錄如下所示:
典型嵌入式Linux根檔案系統目錄
目錄
内容
bin
系統指令和工具
dev
系統裝置檔案
etc
系統初始化腳本和配置檔案
lib
系統運作庫檔案
proc
proc檔案系統
sbin
系統管理者指令和工具
sys
sysfs檔案系統
tmp
臨時檔案
usr
使用者指令和工具,下分usr/bin和usr/sbin目錄
var
系統運作産生的可變資料
要建構一個可用的Linux根檔案系統,需要的二進制和庫都不少,完全從零開始也是不現實的,推薦參考其它現有可用的檔案系統,在原基礎上按需修改;或者使用檔案系統制作工具如 BusyBox 來實作檔案系統的生成。
2. 使用BusyBox生成二進制工具
2-1. 擷取BusyBox源碼
Busybox的官方源碼下載下傳路徑為:https://busybox.net/downloads/。
目前最新版本為busybox-1.29.3.tar.bz2。
2-2. 配置BusyBox
解壓源碼,進入根目錄
$ tar jxvf busybox-1.29.3.tar.bz2
$ cd busybox-1.29.3/
首先,執行
$ make menuconfig
進入圖形化配置界面
2-2-1. 選擇編譯靜态庫
進入
Settings --->
使用空格鍵選擇編譯靜态庫
--- Build Options
[*] Build static binary (no shared libs)
如圖:
2-2-2. 選擇交叉編譯工具鍊
在
Settings --->
設定項下,填寫交叉編譯工具鍊字首
2-2-3. 選擇安裝目錄
在
Settings --->
設定項下,找到
--- Installation Options ("make install" behavior)
What kind of applet links to install (as soft-links) --->
(./_install) Destination path for 'make install' (NEW)
預設為目前目錄下目錄,這裡我使用預設_install目錄
2-2-4. 編譯安裝
退出儲存後,執行編譯
$ make
大概幾分鐘後編譯完成,執行
$ make install
很快就會安裝完成
進入_install目錄,檢視生成的檔案
建立一個目錄用來存放制作的根檔案系統,可以命名為rootfs。将利用BusyBox生成的二進制檔案及目錄,即_install目錄下的所有檔案及目錄複制到rootfs目錄下。
3. 建構根檔案系統
使用BusyBox編譯後,僅有 bin、sbin、usr這 3個目錄和軟連結linuxrc,目錄裡都是二進制指令工具,這還不足以構成 一個可用的根檔案系統,必須進行其它完善工作,才能建構一個可用的根檔案系統。
3-1. 完善目錄結構
根據典型嵌入式Linux根檔案系統目錄,在rootfs目錄中建立其他目錄
$ mkdir dev etc lib proc sys tmp var
3-2. 添加C運作庫檔案
庫檔案可直接從交叉工具鍊擷取,一般在工具鍊的libc/lib/目錄下。我這裡是在ubuntu下安裝的Linaro的交叉工具鍊
庫檔案是在/usr/arm-linux-gnueabihf/lib/目錄下,拷貝動态連結庫檔案到新制作的根檔案系統根目錄下/lib目錄裡
這裡隻是拷貝動态連結庫。一般開發程式使用動态編譯需要闆子上動态庫的支援才能運作,是以拷貝動态庫。而靜态庫一般在靜态編譯的時候用到,由于交叉編譯的工作放在了PC上是以闆子上不需要靜态庫,是以沒有必要拷貝,這樣還可以減小根檔案系統的體積。
一般使用gcc編譯後的可執行檔案、目标檔案和動态庫都帶有調試資訊和符号資訊,這些在調試的時候用到,但是卻增大了檔案的大小。通常在PC上調試,或者調試時使用這些帶有調試資訊和符号資訊的庫檔案,程式釋出後使用去掉這些資訊的庫檔案,可以大大縮小根檔案系統的體積。這裡我們去掉這些資訊,方法是使用strip工具:
$ arm-linux-gnueabihf-strip ./*
3-3. 添加初始化配置腳本
初始化配置腳本放在在/etc目錄下,用于系統啟動所需的初始化配置腳本。BusyBox提供了一些初始化範例腳本,在examples/bootfloppy/etc/目錄下。将這些配置檔案複制到 ”目錄下。将這些配置檔案複制到 ”目錄下。将這些配置檔案複制到新制作的根檔案系統etc目錄下
cp -ra ../busybox/busybox-1.29.3/examples/bootfloppy/etc/* etc/
添加後如圖所示:
3-3-1. 修改/etc/inittab檔案
/etc/inittab檔案是init程序解析的配置檔案,通過這個配置檔案決定執行哪個程序,何時執行。
将檔案修改為
# 系統啟動時
::sysinit:/etc/init.d/rcS
# 系統啟動按下Enter鍵時
::askfirst:-/bin/sh
# 按下Ctrl+Alt+Del鍵時
::ctrlaltdel:/sbin/reboot
# 系統關機時
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
# 系統重新開機時
::restart:/sbin/init
以上内容定義了系統啟動時,關機時,重新開機時,按下Ctrl+Alt+Del鍵時執行的程序。
3-3-2. 修改/etc/init.d/rcS檔案
#! /bin/sh
# 挂載 /etc/fstab 中定義的所有檔案系統
/bin/mount -a
# 挂載虛拟的devpts檔案系統用于用于僞終端裝置
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 使用mdev動态管理u盤和滑鼠等熱插拔裝置
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
# 掃描并建立節點
/sbin/mdev -s
3-3-3. 修改/etc/fstab檔案
/etc/fstab檔案存放的是檔案系統資訊。在系統啟動後執行/etc/init.d/rcS檔案裡/bin/mount -a指令時,自動挂載這些檔案系統。
内容如下
# proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
注:這裡我們挂載的檔案系統有三個proc、sysfs和tmpfs,在核心中proc和sysfs預設都支援,而tmpfs是沒有支援的,我們需要添加tmpfs的支援。
3-3-4. 修改/etc/profile檔案
/etc/profile檔案作用是設定環境變量,每個使用者登入時都會運作它。
将檔案内容修改為
# 主機名
export HOSTNAME=zyz
# 使用者名
export USER=root
# 使用者目錄
export HOME=/root
# 終端預設提示符
export PS1="[[email protected]$HOSTNAME:$PWD]# "
# 環境變量
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
# 動态庫路徑
export LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
因為指定了root使用者的家目錄為/root,是以需要建立該目錄,否則執行cd ~時會失敗
$ mkdir root
登入系統後效果為
...
Please press Enter to activate this console.
[[email protected]:/]#
[[email protected]:/]# cd ~
[[email protected]:/root]#
[[email protected]:/root]# echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin
至此,根檔案系統就基本建構好了。
4. 制作根檔案系統鏡像
4-1. 根檔案系統類型
如果檔案系統已經布局完成, 則可以發到目标中了。通常會制作一個鏡像然後通過某種方式固化到目标系統中,具體采用什麼樣的形釋出需要根據資源狀況、核心情況和系統需求等方面進行裁決:
硬體方面,至少需要考慮主存儲媒體的類型和大小如Flash是NOR Flash還是NAND Flash,RAM的大小等。
核心方面, 則需考慮所裁剪後的支援哪些檔案系統采用種最合适, 能滿足性、速度等要求。
系統需求方面,要考慮運作速度、是否可寫壓縮等因素。
常見的可用于根檔案系統類型有ramdisk 、cramfs、jffs2 、yaffs/yaffs2和 ubifs等,各類型的特性如表所列。
類型
媒體
是否壓縮
是否可寫
掉電儲存
存在于RAM中
Ramdisk
是
是
否
是
cramfs
是
否
-
否
jffs2
NOR Flash
是
是
是
否
yaffs/yaffs2
NAND Flash
否
是
是
否
ubifs
NAND Flash
否
是
是
否
盡管檔案系統固件以某一種檔案系統的鏡像釋出,但是整個檔案系統實際上還是并存多種邏輯檔案系統的。例如,一個系統根檔案系統以ubifs挂載,但是/dev目錄卻是以tmpfs挂載的、/sys目錄挂載的是sysfs檔案系統。
現在,似乎ubifs是一種趨勢。
4-2. 制作UBIFS根檔案系統鏡像
Linux下制作UBIFS的指令有兩個,mkfs.ubifs和ubinize。
mkfs.ubifs,将一個目錄制作為UBIFS檔案系統。使用範例
$ mkfs.ubifs -m 2048 -e 128KiB -c 4096 -r ./rootfs -o rootfs.ubifs
其中
-r, -d, --root=DIR build file system from directory DIR(目錄)
-m, --min-io-size=SIZE minimum I/O unit size(最小輸入輸出單元大小)
-e, --leb-size=SIZE logical erase block size(邏輯擦除塊大小)
-c, --max-leb-cnt=COUNT maximum logical erase block count(最大邏輯擦除塊數目)
-o, --output=FILE output to FILE(輸出檔案)
是以制作ubifs鏡像檔案,需要知道3個關鍵參數,即最小輸入輸出單元大小,邏輯擦除塊大小,最大邏輯擦除塊數目,其中最大邏輯擦除塊數目可由Flash分區大小和邏輯擦除塊大小計算出來,這些資訊可以通過u-boot指令檢視
=> mtdparts default
=> ubi part rootfs
ubinize,将mkfs.ubifs制作的UBIFS檔案系統制作成含有卷标的可以直接燒寫在Flash上的鏡像。使用範例
$ ubinize -m 2048 -p 128KiB ubinize.cfg -o rootfs_ubifs.img
其中
-o, --output=output file name(輸出檔案)
-p, --peb-size=size of the physical eraseblock of the flash(實體擦除塊大小)
this UBI image is created for in bytes,
kilobytes (KiB), or megabytes (MiB)
(mandatory parameter)
-m, --min-io-size=minimum input/output unit size of the flash
in bytes
這裡需要兩個參數實體擦除塊大小和最小輸入輸出單元大小。
ubinize.cfg是配置檔案,内容如下
[ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_size=1024MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
說明
[ubifs]
mode=ubi
image=rootfs.ubifs # mkfs.ubi生成的源鏡像
vol_id=0 # 卷号
vol_size=1024MiB # 卷大小,一般要設定的比分區大,防止有壞塊
vol_type=dynamic # 卷類型,動态卷
vol_name=rootfs # 卷名,rootfs
vol_flags=autoresize # 自動大小
至此,根檔案系統就制作好了,rootfs_ubifs.img可以燒寫到flash使用。