歡迎光臨
每天分享高質量文章

定製嵌入式 Linux 發行版 | Linux 中國

如何構建一個針對特定用途的交叉編譯應用程式的自定義發行版呢? 正如 Michael J. Hammel 在這裡解釋的那樣,它並不像你想象的那麼難。
— Michael J.hammel


本文導航
編譯自 | http://www.linuxjournal.com/content/custom-embedded-linux-distributions 
 作者 | Michael J.hammel
 譯者 | qhwdw

便宜的物聯網板的普及意味著它不僅會控制應用程式,還會控制整個軟體平臺。 那麼,如何構建一個針對特定用途的交叉編譯應用程式的自定義發行版呢? 正如 Michael J. Hammel 在這裡解釋的那樣,它並不像你想象的那麼難。

為什麼要定製?

以前,許多嵌入式專案都使用現成的發行版,然後出於種種原因,再將它們剝離到只剩下基本的必需的東西。首先,移除不需要的包以減少占用的儲存空間。在啟動時,嵌入式系統一般不需要大量的儲存空間以及可用儲存空間。在嵌入式系統運行時,可能從非易失性記憶體中拷貝大量的操作系統檔案到記憶體中。第二,移除用不到的包可以降低可能的攻擊面。如果你不需要它們就沒有必要把這些可能有漏洞的包掛在上面。最後,移除用不到包可以降低發行版管理的開銷。如果在包之間有依賴關係,意味著任何一個包請求從上游更新,那麼它們都必須保持同步。那樣可能就會出現驗證噩夢。

然而,從一個現有的發行版中去移除包並不像說的那樣容易。移除一個包可能會打破與其它包保持的各種依賴關係,以及可能在上游的發行版管理中改變依賴。另外,由於一些包原生集成在引導或者運行時行程中,它們並不能輕易地簡單地移除。所有這些都是專案之外的平臺的管理,並且有可能會導致意外的開發延遲。

一個流行的選擇是使用上游發行版供應商提供的構建工具去構建一個定製的發行版。無論是 Gentoo 還是 Debian 都提供這種自下而上的構建方式。這些構建工具中最為流行的可能是 Debian 的 debootstrap 實用程式。它取出預構建的核心組件並允許用戶去精選出它們感興趣的包來構建用戶自己的平臺。但是,debootstrap 最初僅在 x86 平臺上可用,雖然,現在有了 ARM(也有可能會有其它的平臺)選項。debootstrap 和 Gentoo 的 catalyst 仍然需要從本地專案中將依賴管理移除。

一些人認為讓別人去管理平臺軟體(像 Android 一樣)要比自己親自管理容易的多。但是,那些發行版都是多用途的,當你在一個輕量級的、資源有限的物聯網設備上使用它時,你可能會再三考慮從你手中被拿走的任何資源。

系統引導的基石

一個定製的 Linux 發行版要求許多軟體組件。其中第一個就是工具鏈toolchain。工具鏈是用於編譯軟體的一套工具集。包括(但不限於)一個編譯器、聯結器、二進制操作工具以及標準的 C 庫。工具鏈是為一個特定的標的硬體設備專門構建的。如果一個構建在 x86 系統上的工具鏈想要用於樹莓派,那麼這個工具鏈就被稱為交叉編譯工具鏈。當在記憶體和儲存都十分有限的小型嵌入式設備上工作時,最好是使用一個交叉編譯工具鏈。需要註意的是,即便是使用像 JavaScript 這樣的需要運行在特定平臺的腳本語言為特定用途編寫的應用程式,也需要使用交叉編譯工具鏈編譯。

圖 1. 編譯依賴和引導順序

交叉編譯工具鏈用於為標的硬體構建軟體組件。需要的第一個組件是引導加載程式bootloader。當計算機主板加電之後,處理器(可能有差異,取決於設計)嘗試去跳轉到一個特定的記憶體位置去開始運行軟體。那個記憶體位置就是儲存引導加載程式的地方。硬體可能有內置的引導加載程式,它可能直接從它的儲存位置或者可能在它運行前首先拷貝到記憶體中。也可能會有多個引導加載程式。例如,第一階段的引導加載程式可能位於硬體的 NAND 或者 NOR 閃存中。它唯一的功能是設置硬體以便於執行第二階段的引導加載程式——比如,儲存在 SD 卡中的可以被加載並運行的引導加載程式。

引導加載程式能夠從硬體中取得足夠的信息,將 Linux 加載到記憶體中並跳轉到正確的位置,將控制權有效地移交到 Linux。Linux 是一個操作系統。這意味著,在這種設計中,它除了監控硬體和向上層軟體(也就是應用程式)提供服務外,它實際上什麼都不做。Linux 內核[1] 中通常是各種各樣的韌體塊。那些預編譯的軟體物件,通常包含硬體平臺使用的設備的專用 IP(知識資產)。當構建一個定製發行版時,在開始編譯內核之前,它可能會要求獲得一些 Linux 內核原始碼樹沒有提供的必需的韌體塊。

應用程式儲存在根檔案系統中,這個根檔案系統是通過編譯構建的,它集合了各種軟體庫、工具、腳本以及配置檔案。總的來說,它們都提供各種服務,比如,網絡配置和 USB 設備掛載,這些都是將要運行的專案應用程式所需要的。

總的來說,一個完整的系統構建要求下列的組件:

☉ 一個交叉編譯工具鏈
☉ 一個或多個引導加載程式
☉ Linux 內核和相關的韌體塊
☉ 一個包含庫、工具以及實用程式的根檔案系統
☉ 定製的應用程式

使用適當的工具開始構建

交叉編譯工具鏈的組件可以手工構建,但這是一個很複雜的過程。幸運的是,現有的工具可以很容易地完成這一過程。構建交叉編譯工具鏈的最好工具可能是 Crosstool-NG[2],這個工具使用了與 Linux 內核相同的 kconfig 選單系統來構建工具鏈的每個細節和方面。使用這個工具的關鍵是,為標的平臺找到正確的配置項。配置項通常包含下列內容:

☉ 標的架構,比如,是 ARM 還是 x86。
☉ 位元組順序:小端位元組順序(一般情況下,Intel 採用這種順序)還是大端位元組順序(一般情況下,ARM 或者其它的平臺採用這種順序)。
☉ 編譯器已知的 CPU 型別,比如,GCC 可以使用 -mcpu 或 --with-cpu
☉ 支持的浮點型別,如果有的話,比如,GCC 可以使用 -mfpu 或 --with-fpu
☉ 二進制實用工具binutils、C 庫以及 C 編譯器的特定版本信息。

圖 2. Crosstool-NG 配置選單

前四個一般情況下可以從處理器製造商的文件中獲得。對於較新的處理器,它們可能不容易找到,但是,像樹莓派或者 BeagleBoards(以及它們的後代和分支),你可以在像 嵌入式 Linux Wiki[3] 這樣的地方找到相關信息。

二進制實用工具、C 庫、以及 C 編譯器的版本,將與任何第三方提供的其它工具鏈分開。首先,它們中的每一個都有多個提供者。Linaro 為最新的處理器型別提供了最先進的版本,同時致力於將該支持合併到像 GNU C 庫這樣的上游專案中。儘管你可以使用各種提供者的工具,你可能依然想去使用現成的 GNU 工具鏈或者相同的 Linaro 版本。

在 Crosstool-NG 中的另外的重要選擇是 Linux 內核的版本。這個選擇將得到用於各種工具鏈組件的頭檔案essay-headers,但是它沒有必要一定與你在標的硬體上將要引導的 Linux 內核相同。選擇一個不比標的硬體的內核更新的 Linux 內核是很重要的。如果可能的話,儘量選擇一個比標的硬體使用的內核更老的長周期支持(LTS)的內核。

對於大多數不熟悉構建定製發行版的開發者來說,工具鏈的構建是最為複雜的過程。幸運的是,大多數硬體平臺的二進制工具鏈都可以想辦法得到。如果構建一個定製的工具鏈有問題,可以在線搜索像 嵌入式 Linux Wiki[3] 這樣的地方去查找預構建工具鏈。

引導選項

在構建完工具鏈之後,接下來的工作是引導加載程式。引導加載程式用於設置硬體,以便於越來越複雜的軟體能夠使用這些硬體。第一階段的引導加載程式通常由標的平臺製造商提供,它通常被燒錄到類似於 EEPROM 或者 NOR 閃存這類的在硬體上的儲存中。第一階段的引導加載程式將使設備從這裡(比如,一個 SD 儲存卡)開始引導。樹莓派的引導加載程式就是這樣的,它樣做也就沒有必要再去創建一個定製引導加載程式。

儘管如此,許多專案還是增加了第二階段的引導加載程式,以便於去執行一個多樣化的任務。在無需使用 Linux 內核或者像 plymouth 這樣的用戶空間工具的情況下提供一個啟動動畫,就是其中一個這樣的任務。一個更常見的第二階段引導加載程式的任務是去提供基於網絡的引導或者使連接到 PCI 上的磁盤可用。在那種情況下,一個第三階段的引導加載程式,比如 GRUB,可能才是讓系統運行起來所必需的。

最重要的是,引導加載程式加載 Linux 內核並使它開始運行。如果第一階段引導加載程式沒有提供一個在啟動時傳遞內核引數的機制,那麼,在第二階段的引導加載程式中就必須要提供。

有許多的開源引導加載程式可以使用。U-Boot 專案[4] 通常用於像樹莓派這樣的 ARM 平臺。CoreBoot 一般是用於像 Chromebook 這樣的 x86 平臺。引導加載程式是特定於標的硬體專用的。引導加載程式的選擇總體上取決於專案的需求以及標的硬體(可以去網絡上在線搜索開源引導加載程式的串列)。

現在到了 Linux 登場的時候

引導加載程式將加載 Linux 內核到記憶體中,然後去運行它。Linux 就像一個擴展的引導加載程式:它進行進行硬體設置以及準備加載高級軟體。內核的核心將設置和提供在應用程式和硬體之間共享使用的記憶體;提供任務管理器以允許多個應用程式同時運行;初始化沒有被引導加載程式配置的或者是已經配置了但是沒有完成的硬體組件;以及開啟人機交互界面。內核也許不會配置為在自身完成這些工作,但是,它可以包含一個嵌入的、輕量級的檔案系統,這類檔案系統大家熟知的有 initramfs 或者 initrd,它們可以獨立於內核而創建,用於去輔助設置硬體。

內核操作的另外的事情是去下載二進制塊(通常稱為韌體)到硬體設備。韌體是用特定格式預編譯的物件檔案,用於在引導加載程式或者內核不能訪問的地方去初始化特定硬體。許多這種韌體物件可以從 Linux 內核源倉庫中獲取,但是,還有很多其它的韌體只能從特定的硬體供應商處獲得。例如,經常由它們自己提供韌體的設備有數字電視調諧器或者 WiFi 網卡等。

韌體可以從 initramfs 中加載,也或者是在內核從根檔案系統中啟動 init 行程之後加載。但是,當你去創建一個定製的 Linux 發行版時,創建內核的過程常常就是獲取各種韌體的過程。

輕量級核心平臺

Linux 內核做的最後一件事情是嘗試去運行一個被稱為 init 行程的專用程式。這個專用程式的名字可能是 init 或者 linuxrc 或者是由加載程式傳遞給內核的名字。init 行程儲存在一個能夠被內核訪問的檔案系統中。在 initramfs 這種情況下,這個檔案系統儲存在記憶體中(它可能是被內核自己放置到那裡,也可能是被引導加載程式放置在那裡)。但是,對於運行更複雜的應用程式,initramfs 通常並不夠完整。因此需要另外一個檔案系統,這就是眾所周知的根檔案系統。

圖 3. 構建 root 配置選單

initramfs 檔案系統可以使用 Linux 內核自身構建,但是更常用的作法是,使用一個被稱為 BusyBox[5] 的專案去創建。BusyBox 組合許多 GNU 實用程式(比如,grep 或者 awk)到一個單個的二進制檔案中,以便於減小檔案系統自身的大小。BusyBox 通常用於去啟動根檔案系統的創建過程。

但是,BusyBox 是特意輕量化設計的。它並不打算提供標的平臺所需要的所有工具,甚至提供的工具也是經過功能簡化的。BusyBox 有一個“姊妹”專案叫做 Buildroot[6],它可以用於去得到一個完整的根檔案系統,提供了各種庫、實用程式,以及腳本語言。像 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 是元構建metabuild。元構建是將一系列有自己構建系統的軟體集合封裝為一個構建系統。可靠的元構建包括 Yocto[7] 和 OpenEmbedded[8]。Buildroot 的好處是可以將更高級別的元構建進行輕鬆的封裝,以便於將定製 Linux 發行版的構建過程自動化。這樣做之後,將會打開 Buildroot 指向到專案專用的快取倉庫的選項。使用快取倉庫可以加速開發過程,並且可以在無需擔心上游倉庫變化的情況下提供構建快照。

一個實現高級構建系統的示例是 PiBox[9]。PiBox 就是封裝了在本文中討論的各種工具的一個元構建。它的目的是圍繞所有工具去增加一個通用的 GNU Make 標的架構,以生成一個核心平臺,這個平臺可以構建或分發其它軟體。PiBox 媒體中心和 kiosk 專案是安裝在核心平臺之上的應用層軟體的實現,目的是用於去產生一個構建平臺。Iron Man 專案[10] 是為了家庭自動化的目的而擴展了這種應用程式,它集成了語音管理和物聯網設備的管理。

但是,PiBox 如果沒有這些核心的軟體工具,它什麼也做不了。並且,如果不去深入瞭解一個完整的定製發行版的構建過程,那麼你將無法正確運行 PiBox。而且,如果沒有 PiBox 開發團隊對這個專案的長期奉獻,也就沒有 PiBox 專案,它完成了定製發行版構建中的大量任務。


via: http://www.linuxjournal.com/content/custom-embedded-linux-distributions

作者:Michael J.Hammel[12] 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

LCTT 譯者

qhwdw ? ? ? ? ?
共計翻譯:64 篇
貢獻時間:102 天


推薦文章

< 左右滑動查看相關文章 >

點擊圖片、輸入文章 ID 或識別二維碼直達

赞(0)

分享創造快樂