紅聯Linux門戶
Linux幫助

定制嵌入式Linux發行版

發布時間:2018-02-09 11:47:39來源:qhwdw作者:linux.cn
便宜的物聯網板的普及意味著它不僅會控制應用程序,還會控制整個軟件平臺。那么,如何構建一個針對特定用途的交叉編譯應用程序的自定義發行版呢?正如 Michael J. Hammel 在這里解釋的那樣,它并不像你想象的那么難。
 
為什么要定制?
以前,許多嵌入式項目都使用現成的發行版,然后出于種種原因,再將它們剝離到只剩下基本的必需的東西。首先,移除不需要的包以減少占用的存儲空間。在啟動時,嵌入式系統一般不需要大量的存儲空間以及可用存儲空間。在嵌入式系統運行時,可能從非易失性內存中拷貝大量的操作系統文件到內存中。第二,移除用不到的包可以降低可能的攻擊面。如果你不需要它們就沒有必要把這些可能有漏洞的包掛在上面。最后,移除用不到包可以降低發行版管理的開銷。如果在包之間有依賴關系,意味著任何一個包請求從上游更新,那么它們都必須保持同步。那樣可能就會出現驗證噩夢。
然而,從一個現有的發行版中去移除包并不像說的那樣容易。移除一個包可能會打破與其它包保持的各種依賴關系,以及可能在上游的發行版管理中改變依賴。另外,由于一些包原生集成在引導或者運行時進程中,它們并不能輕易地簡單地移除。所有這些都是項目之外的平臺的管理,并且有可能會導致意外的開發延遲。
一個流行的選擇是使用上游發行版供應商提供的構建工具去構建一個定制的發行版。無論是 Gentoo 還是 Debian 都提供這種自下而上的構建方式。這些構建工具中最為流行的可能是 Debian 的 debootstrap 實用程序。它取出預構建的核心組件并允許用戶去精選出它們感興趣的包來構建用戶自己的平臺。但是,debootstrap 最初僅在 x86 平臺上可用,雖然,現在有了 ARM(也有可能會有其它的平臺)選項。debootstrap 和 Gentoo 的 catalyst 仍然需要從本地項目中將依賴管理移除。
一些人認為讓別人去管理平臺軟件(像 Android 一樣)要比自己親自管理容易的多。但是,那些發行版都是多用途的,當你在一個輕量級的、資源有限的物聯網設備上使用它時,你可能會再三考慮從你手中被拿走的任何資源。
 
系統引導的基石
一個定制的 Linux 發行版要求許多軟件組件。其中第一個就是工具鏈。工具鏈是用于編譯軟件的一套工具集。包括(但不限于)一個編譯器、鏈接器、二進制操作工具以及標準的 C 庫。工具鏈是為一個特定的目標硬件設備專門構建的。如果一個構建在 x86 系統上的工具鏈想要用于樹莓派,那么這個工具鏈就被稱為交叉編譯工具鏈。當在內存和存儲都十分有限的小型嵌入式設備上工作時,最好是使用一個交叉編譯工具鏈。需要注意的是,即便是使用像 JavaScript 這樣的需要運行在特定平臺的腳本語言為特定用途編寫的應用程序,也需要使用交叉編譯工具鏈編譯。
定制嵌入式Linux發行版
圖 1.編譯依賴和引導順序
交叉編譯工具鏈用于為目標硬件構建軟件組件。需要的第一個組件是引導加載程序。當計算機主板加電之后,處理器(可能有差異,取決于設計)嘗試去跳轉到一個特定的內存位置去開始運行軟件。那個內存位置就是保存引導加載程序的地方。硬件可能有內置的引導加載程序,它可能直接從它的存儲位置或者可能在它運行前首先拷貝到內存中。也可能會有多個引導加載程序。例如,第一階段的引導加載程序可能位于硬件的 NAND 或者 NOR 閃存中。它唯一的功能是設置硬件以便于執行第二階段的引導加載程序——比如,存儲在 SD 卡中的可以被加載并運行的引導加載程序。
引導加載程序能夠從硬件中取得足夠的信息,將 Linux 加載到內存中并跳轉到正確的位置,將控制權有效地移交到 Linux。Linux 是一個操作系統。這意味著,在這種設計中,它除了監控硬件和向上層軟件(也就是應用程序)提供服務外,它實際上什么都不做。Linux 內核 中通常是各種各樣的固件塊。那些預編譯的軟件對象,通常包含硬件平臺使用的設備的專用 IP(知識資產)。當構建一個定制發行版時,在開始編譯內核之前,它可能會要求獲得一些 Linux 內核源代碼樹沒有提供的必需的固件塊。
應用程序保存在根文件系統中,這個根文件系統是通過編譯構建的,它集合了各種軟件庫、工具、腳本以及配置文件。總的來說,它們都提供各種服務,比如,網絡配置和 USB 設備掛載,這些都是將要運行的項目應用程序所需要的。
總的來說,一個完整的系統構建要求下列的組件:
1.一個交叉編譯工具鏈
2.一個或多個引導加載程序
3.Linux 內核和相關的固件塊
4.一個包含庫、工具以及實用程序的根文件系統
5.定制的應用程序
 
使用適當的工具開始構建
交叉編譯工具鏈的組件可以手工構建,但這是一個很復雜的過程。幸運的是,現有的工具可以很容易地完成這一過程。構建交叉編譯工具鏈的最好工具可能是 Crosstool-NG,這個工具使用了與 Linux 內核相同的 kconfig 菜單系統來構建工具鏈的每個細節和方面。使用這個工具的關鍵是,為目標平臺找到正確的配置項。配置項通常包含下列內容:
1.目標架構,比如,是 ARM 還是 x86。
2.字節順序:小端字節順序(一般情況下,Intel 采用這種順序)還是大端字節順序(一般情況下,ARM 或者其它的平臺采用這種順序)。
3.編譯器已知的 CPU 類型,比如,GCC 可以使用 -mcpu 或 --with-cpu。
4.支持的浮點類型,如果有的話,比如,GCC 可以使用 -mfpu 或 --with-fpu。
5.二進制實用工具、C 庫以及 C 編譯器的特定版本信息。
定制嵌入式Linux發行版
圖 2.Crosstool-NG 配置菜單
前四個一般情況下可以從處理器制造商的文檔中獲得。對于較新的處理器,它們可能不容易找到,但是,像樹莓派或者 BeagleBoards(以及它們的后代和分支),你可以在像 嵌入式 Linux Wiki(https://elinux.org/Main_Page) 這樣的地方找到相關信息。
二進制實用工具、C 庫、以及 C 編譯器的版本,將與任何第三方提供的其它工具鏈分開。首先,它們中的每一個都有多個提供者。Linaro 為最新的處理器類型提供了最先進的版本,同時致力于將該支持合并到像 GNU C 庫這樣的上游項目中。盡管你可以使用各種提供者的工具,你可能依然想去使用現成的 GNU 工具鏈或者相同的 Linaro 版本。
在 Crosstool-NG 中的另外的重要選擇是 Linux 內核的版本。這個選擇將得到用于各種工具鏈組件的頭文件,但是它沒有必要一定與你在目標硬件上將要引導的 Linux 內核相同。選擇一個不比目標硬件的內核更新的 Linux 內核是很重要的。如果可能的話,盡量選擇一個比目標硬件使用的內核更老的長周期支持(LTS)的內核。
對于大多數不熟悉構建定制發行版的開發者來說,工具鏈的構建是最為復雜的過程。幸運的是,大多數硬件平臺的二進制工具鏈都可以想辦法得到。如果構建一個定制的工具鏈有問題,可以在線搜索像 嵌入式 Linux Wiki(https://elinux.org/Main_Page) 這樣的地方去查找預構建工具鏈。
 
引導選項
在構建完工具鏈之后,接下來的工作是引導加載程序。引導加載程序用于設置硬件,以便于越來越復雜的軟件能夠使用這些硬件。第一階段的引導加載程序通常由目標平臺制造商提供,它通常被燒錄到類似于 EEPROM 或者 NOR 閃存這類的在硬件上的存儲中。第一階段的引導加載程序將使設備從這里(比如,一個 SD 存儲卡)開始引導。樹莓派的引導加載程序就是這樣的,它樣做也就沒有必要再去創建一個定制引導加載程序。
盡管如此,許多項目還是增加了第二階段的引導加載程序,以便于去執行一個多樣化的任務。在無需使用 Linux 內核或者像 plymouth 這樣的用戶空間工具的情況下提供一個啟動動畫,就是其中一個這樣的任務。一個更常見的第二階段引導加載程序的任務是去提供基于網絡的引導或者使連接到 PCI 上的磁盤可用。在那種情況下,一個第三階段的引導加載程序,比如 GRUB,可能才是讓系統運行起來所必需的。
最重要的是,引導加載程序加載 Linux 內核并使它開始運行。如果第一階段引導加載程序沒有提供一個在啟動時傳遞內核參數的機制,那么,在第二階段的引導加載程序中就必須要提供。
有許多的開源引導加載程序可以使用。U-Boot 項目 通常用于像樹莓派這樣的 ARM 平臺。CoreBoot 一般是用于像 Chromebook 這樣的 x86 平臺。引導加載程序是特定于目標硬件專用的。引導加載程序的選擇總體上取決于項目的需求以及目標硬件(可以去網絡上在線搜索開源引導加載程序的列表)。
 
現在到了 Linux 登場的時候
引導加載程序將加載 Linux 內核到內存中,然后去運行它。Linux 就像一個擴展的引導加載程序:它進行進行硬件設置以及準備加載高級軟件。內核的核心將設置和提供在應用程序和硬件之間共享使用的內存;提供任務管理器以允許多個應用程序同時運行;初始化沒有被引導加載程序配置的或者是已經配置了但是沒有完成的硬件組件;以及開啟人機交互界面。內核也許不會配置為在自身完成這些工作,但是,它可以包含一個嵌入的、輕量級的文件系統,這類文件系統大家熟知的有 initramfs 或者 initrd,它們可以獨立于內核而創建,用于去輔助設置硬件。
內核操作的另外的事情是去下載二進制塊(通常稱為固件)到硬件設備。固件是用特定格式預編譯的對象文件,用于在引導加載程序或者內核不能訪問的地方去初始化特定硬件。許多這種固件對象可以從 Linux 內核源倉庫中獲取,但是,還有很多其它的固件只能從特定的硬件供應商處獲得。例如,經常由它們自己提供固件的設備有數字電視調諧器或者 WiFi 網卡等。
固件可以從 initramfs 中加載,也或者是在內核從根文件系統中啟動 init 進程之后加載。但是,當你去創建一個定制的 Linux 發行版時,創建內核的過程常常就是獲取各種固件的過程。
 
輕量級核心平臺
Linux 內核做的最后一件事情是嘗試去運行一個被稱為 init 進程的專用程序。這個專用程序的名字可能是 init 或者 linuxrc 或者是由加載程序傳遞給內核的名字。init 進程保存在一個能夠被內核訪問的文件系統中。在 initramfs 這種情況下,這個文件系統保存在內存中(它可能是被內核自己放置到那里,也可能是被引導加載程序放置在那里)。但是,對于運行更復雜的應用程序,initramfs 通常并不夠完整。因此需要另外一個文件系統,這就是眾所周知的根文件系統。
定制嵌入式Linux發行版
圖 3.構建 root 配置菜單
initramfs 文件系統可以使用 Linux 內核自身構建,但是更常用的作法是,使用一個被稱為 BusyBox 的項目去創建。BusyBox 組合許多 GNU 實用程序(比如,grep 或者 awk)到一個單個的二進制文件中,以便于減小文件系統自身的大小。BusyBox 通常用于去啟動根文件系統的創建過程。
但是,BusyBox 是特意輕量化設計的。它并不打算提供目標平臺所需要的所有工具,甚至提供的工具也是經過功能簡化的。BusyBox 有一個“姊妹”項目叫做 Buildroot,它可以用于去得到一個完整的根文件系統,提供了各種庫、實用程序,以及腳本語言。像 Crosstool-NG 和 Linux 內核一樣,BusyBox 和 Buildroot 也都允許使用 kconfig 菜單系統去定制配置。更重要的是,Buildroot 系統自動處理依賴關系,因此,選定的實用程序將會保證該程序所需要的軟件也會被構建并安裝到 root 文件系統。
Buildroot 可以用多種格式去生成一個根文件系統包。但是,需要重點注意的是,這個文件系統是被歸檔的。單個的實用程序和庫并不是以 Debian 或者 RPM 格式打包進去的。使用 Buildroot 將生成一個根文件系統鏡像,但是它的內容不是單獨的包。即使如此,Buildroot 還是提供了對 opkg 和 rpm 包管理器的支持的。這意味著,雖然根文件系統自身并不支持包管理,但是,安裝在根文件系統上的定制應用程序能夠進行包管理。
 
交叉編譯和腳本化
Buildroot 的其中一個特性是能夠生成一個臨時樹。這個目錄包含庫和實用程序,它可以被用于去交叉編譯其它應用程序。使用臨時樹和交叉編譯工具鏈,使得在主機系統上而不是目標平臺上對 Buildroot 之外的其它應用程序編譯成為可能。使用 rpm 或者 opkg 包管理軟件之后,這些應用程序可以在運行時使用包管理軟件安裝在目標平臺的根文件系統上。
大多數定制系統的構建都是圍繞著用腳本語言構建應用程序的想法去構建的。如果需要在目標平臺上運行腳本,在 Buildroot 上有多種可用的選擇,包括 Python、PHP、Lua 以及基于 Node.js 的 JavaScript。對于需要使用 OpenSSL 加密的應用程序也提供支持。
 
接下來做什么
Linux 內核和引導加載程序的編譯過程與大多數應用程序是一樣的。它們的構建系統被設計為去構建一個專用的軟件位。Crosstool-NG 和 Buildroot 是元構建。元構建是將一系列有自己構建系統的軟件集合封裝為一個構建系統。可靠的元構建包括 Yocto 和 OpenEmbedded。Buildroot 的好處是可以將更高級別的元構建進行輕松的封裝,以便于將定制 Linux 發行版的構建過程自動化。這樣做之后,將會打開 Buildroot 指向到項目專用的緩存倉庫的選項。使用緩存倉庫可以加速開發過程,并且可以在無需擔心上游倉庫變化的情況下提供構建快照。
一個實現高級構建系統的示例是 PiBox(https://www.piboxproject.com/)。PiBox 就是封裝了在本文中討論的各種工具的一個元構建。它的目的是圍繞所有工具去增加一個通用的 GNU Make 目標架構,以生成一個核心平臺,這個平臺可以構建或分發其它軟件。PiBox 媒體中心和 kiosk 項目是安裝在核心平臺之上的應用層軟件的實現,目的是用于去產生一個構建平臺。Iron Man 項目(http://redmine.graphics-muse.org/projects/ironman/wiki/Getting_Started) 是為了家庭自動化的目的而擴展了這種應用程序,它集成了語音管理和物聯網設備的管理。
但是,PiBox 如果沒有這些核心的軟件工具,它什么也做不了。并且,如果不去深入了解一個完整的定制發行版的構建過程,那么你將無法正確運行 PiBox。而且,如果沒有 PiBox 開發團隊對這個項目的長期奉獻,也就沒有 PiBox 項目,它完成了定制發行版構建中的大量任務。
 
嵌入式linux用xdelta實現程序的遠程升級:http://www.4179693.live/linux/31673.html
嵌入式Linux移植rz和sz命令:http://www.4179693.live/linux/30816.html
嵌入式Linux開打core dumps調試功能:http://www.4179693.live/linux/30480.html
嵌入式Linux下中文字體顯示:http://www.4179693.live/linux/27283.html
如何定制嵌入式Linux發布版:http://www.4179693.live/linux/26648.html
601268股票行情中心