有許多嵌入式Linux發行版可以使用,它們都具有良好的功能,但要犧牲映像大小,有些映像可能會達到4GB。有時,我們希望嵌入式系統僅支持系統所需的最小軟件包來支持Linux,例如運行沒有圖形界面的小型FTP服務器。
為了實現獲得自定義映像的目的,我們可以通過一些用於基於Linux嵌入式系統的構建工具來自動化並促進構建發行版。今天,已有的一些開源項目包括Yocto和Buildroot。
在此博客文章中,我們將評論如何使用Buildroot以及如何使用它為RaspberryPi3創建自定義圖像。整個示例在此處提供。
Buildroot
Buildroot是用於自動創建嵌入式Linux發行版的工具。它建立了電路板架構的代碼,因此通過對Makefile的概述來進行設置。除了開源之外,它還根據GPL-2.0或更高版本獲得許可。
如何安裝
在開始安裝Buildroot之前,讓我們假設您已經準備好用於構建C項目的Linux環境,以及用於git,svn和rsync的工具。
您可以通過Buildroot官方文檔獲得有關需求的更多信息。
為了安裝Buildroot,我們將通過Github克隆存儲庫:
$ git clone https://github.com/buildroot/buildroot.git buildroot
分析Buildroot
進入Buildroot目錄後,我們將有以下樹:
buildroot/
|
├── arch
├── board
├── boot
├── configs
├── docs
├── linux
├── package
├── support
├── system
├── toolchain
└── utils
每個目錄都包含設置一部分構建所需的一組文件。在這裡我們可以突出顯示:
- board:包含用於目標板映射和配置的文件,例如閃存地址和設備樹文件;
- configs:包含一系列預設配置,以自動將哪些軟件包和屬性添加到嵌入式映像;
- 軟件包:包含到目前為止Buildroot可用的所有官方軟件包。我們不僅限於這些軟件包,Buildroot允許我們創建新的自定義軟件包。
我們將更加關注package文件夾,因為我們的主要興趣是自定義安裝在映像中的包。
作為示例,讓我們看一下fmt軟件包,其中包含3個文件:
package/fmt/
|
├── Config.in
├── fmt.hash
└── fmt.mk
Config.in是用於Buildroot配置的軟件包描述,它在選擇要構建的軟件包時負責維護用戶界面的信息。它還包含程序包依賴性。
config BR2_PACKAGE_FMT
bool "fmt"
depends on BR2_INSTALL_LIBSTDCPP
depends on BR2_USE_WCHAR
help
fmt is an open-source formatting library for C++. It can be
used as a safe alternative to printf or as a fast alternative
to IOStreams.
https://fmt.dev/latest/index.html
該fmt.mk文件是在Makefile配方建立,建設和安裝庫。
FMT_VERSION = 5.3.0
FMT_SITE = $(call github,fmtlib,fmt,$(FMT_VERSION))
FMT_LICENSE = BSD-2-Clause
FMT_LICENSE_FILES = LICENSE.rst
FMT_INSTALL_STAGING = YES
FMT_CONF_OPTS = \
-DHAVE_OPEN=ON \
-DFMT_INSTALL=ON \
-DFMT_TEST=OFF
$(eval $(cmake-package))
該文件存儲所有其他軟件包的默認屬性,例如其版本,從中下載源代碼的站點,軟件許可證名稱以及在何處可以找到該許可證文件。
在這裡,您可以看到最後調用了一個名為cmake-package的模塊。這個模塊負責使用CMake處理項目,它將執行從配置到工件安裝的所有必要命令。這種模塊化允許更高水平的自動化,否則有必要描述每個軟件包的所有CMake命令。
最後一個文件fmt.hash包含直接從站點下載的文件的校驗和。
sha256 defa24a9af4c622a7134076602070b45721a43c51598c8456ec6f2c4dbb51c89 fmt-5.3.0.tar.gz
sha256 560d39617dfb4b4e4088597291a070ed6c3a8d67668114ed475c673430c3e49a LICENSE.rst
儘管我們使用的是SHA-256,但Buildroot能夠支持SHA-1和MD5等其他格式。軟件包下載期間,Buildroot會自動驗證校驗和。如果找到的值與描述的值不同,將引發錯誤。
配置自定義映像
由於我們的目標平台是RaspberryPi3,因此Buildroot為此板提供了一個預先配置的文件,該文件位於configs目錄中。
要詢問Buildroot,我們要從RaspberryPi3構建我們的配置,我們應該使用以下命令:
$ make raspberrypi3_defconfig
一旦執行,此命令將生成文件.config,其中包含映像所需的所有軟件包,內核,工具鍊和屬性。要添加新程序包或編輯現有程序包,我們需要處理此文件,但這不是非常自動化,會在構建過程中導致許多錯誤。這就是Buildroot具有更多用戶友好界面的原因,您可以在其中自定義最終配置並自動解決依賴性。該界面有不同的格式,您可以嘗試其中的一些格式:
$ make config
$ make menuconfig
$ make gconfig
$ make xconfig
在此示例中,我們將使用menuconfig,因為它具有最小的圖形界面,並且不需要Qt之類的其他系統依賴項。
執行配置命令後,我們將得到以下輸出:
正如我們之前已經詳細介紹了fmt庫,我們將其包含在圖像中,因此我們必須以以下方式瀏覽菜單:
Target Packages -> Libraries -> Text and terminal handling -> fmt
要獲取有關包裝的更多信息,可以輸入?。它將顯示與Config.in文件中相同的內容。選擇後,我們可以通過面板保存當前設置,然後按ESC退出。
建立形象
設置完成後,我們可以繼續執行本教程中最長的步驟,構建映像。儘管構建只是命令,但Buildroot將必須下載配置文件中存在的所有源,從源進行構建,最後生成自定義映像。要開始構建過程,只需運行:
$ make
從現在開始,Buildroot將負責整個構建過程,第一次可能需要幾個小時。對於將來的構建,可以重新使用緩存,這會將構建時間縮短到幾分鐘。
使用柯南進行Buildroot構建
儘管Buildroot可以通過其軟件包結構接受新軟件包,但是構建過程仍然有些長,但是第一次可能要花費幾個小時。但是,如果可以通過下載預構建的軟件包將這一過程減少到幾分鐘,該怎麼辦?讓我們看一下柯南的一些與場景相關的功能和方面:
- 能夠提供所有平台和配置的所有二進製文件的統一視圖,而不僅僅是buildroot;
- 開發人員可以快速開發,並在其Linux盒中使用本機二進製文件在本地進行測試;
- 由於重複使用了二進製文件,因此構建速度更快,不僅用於開發,而且還用於生產和發布;
- 最佳DevOps最佳實踐,避免多次從源代碼重建二進製文件。
在將柯南引入Buildroot之前,我們需要了解如何與buildroot協作以進行軟件包構建的腳本結構:
$ ls package/*.mk
package/doc-asciidoc.mk package/pkg-cmake.mk package/pkg-download.mk package/pkg-golang.mk
...
Makefile的此列表負責為每個給定的軟件包執行構建過程。回到ZLib庫的配方示例,我們有以下部分:
$(eval $(cmake-package))
此行告訴我們,該pkg-cmake.mk
腳本將用於構建ZLib項目。在集成Conan的情況下,我們將必鬚根據Buildroot給出的配置,使用負責下載所需軟件包的命令構建一個新腳本,並將工件複製到它們的正確位置。
將Conan與Buildroot集成
讓我們在目錄中創建一個名為pkg-conan.mk的新文件package/
。同時,我們需要將其添加到package/Makefile.in
文件中,以便Buildroot能夠列出它。
$ echo 'include package/pkg-conan.mk' >> package/Makefile.in
對於腳本開發,我們將其分為幾個步驟。因為它是一個大文件,所以在本文中我們將僅描述它的一部分,但是完整版本可以在此處找到。
Buildroot通過變量定義其設置,包括處理器,編譯器版本和構建類型。但是,這些變量沒有針對柯南的直接有效值,因此我們需要解析它們中的大多數。讓我們從編譯器版本開始,默認情況下Buildroot使用基於GCC的工具鏈,因此我們僅過濾其可能的版本:
CONAN_SETTING_COMPILER_VERSION ?=
ifeq ($(BR2_GCC_VERSION_8_X),y)
CONAN_SETTING_COMPILER_VERSION = 8
else ifeq ($(BR2_GCC_VERSION_7_X),y)
CONAN_SETTING_COMPILER_VERSION = 7
else ifeq ($(BR2_GCC_VERSION_6_X),y)
CONAN_SETTING_COMPILER_VERSION = 6
else ifeq ($(BR2_GCC_VERSION_5_X),y)
CONAN_SETTING_COMPILER_VERSION = 5
else ifeq ($(BR2_GCC_VERSION_4_9_X),y)
CONAN_SETTING_COMPILER_VERSION = 4.9
endif
對於build_type,arch等,應重複相同的過程。對於柯南軟件包安裝步驟,我們將執行以下例程:
define $(2)_BUILD_CMDS
$$(TARGET_MAKE_ENV) $$(CONAN_ENV) $$($$(PKG)_CONAN_ENV) \
CC=$$(TARGET_CC) CXX=$$(TARGET_CXX) \
$$(CONAN) install $$(CONAN_OPTS) $$($$(PKG)_CONAN_OPTS) \
$$($$(PKG)_REFERENCE) \
-s build_type=$$(CONAN_SETTING_BUILD_TYPE) \
-s arch=$$(CONAN_SETTING_ARCH) \
-s compiler=$$(CONAN_SETTING_COMPILER) \
-s compiler.version=$$(CONAN_SETTING_COMPILER_VERSION) \
-g deploy \
--build $$(CONAN_BUILD_POLICY)
endef
Conan安裝命令將照常執行,但是設置和選項是通過以前從Buildroot收集的內容進行配置的,並通過Buildroot軟件包配方接受新的設置和選項。因為在這種情況下,以前所有資源都是在第一時間進行編譯的,所以我們將Conan的構建策略設置為missing
,因此將構建任何不可用的軟件包。
另外,請注意,我們正在使用generator deploy
,因為我們需要將所有工件複製到Buildroot內部結構中。構建完成後,我們將通過以下例程複製庫,可執行文件和頭文件:
define $(2)_INSTALL_CMDS
cp -f -a $$($$(PKG)_BUILDDIR)/bin/. /usr/bin 2>/dev/null || :
cp -f -a $$($$(PKG)_BUILDDIR)/lib/. /usr/lib 2>/dev/null || :
cp -f -a $$($$(PKG)_BUILDDIR)/include/. /usr/include 2>/dev/null || :
endef
通過此腳本,我們將能夠使用每個Buildroot配方的更簡單信息來安裝絕大多數Conan軟件包。
安裝柯南Zlib
一旦有了用於安裝Conan軟件包的腳本,現在讓我們安裝一個相當簡單且眾所周知的項目:zlib。為此,我們將在包目錄中創建一個新配方。讓我們從包配置文件開始:
mkdir package/conan-zlib
touch package/conan-zlib/Config.in
touch package/conan-zlib/conan-zlib.mk
Config.in文件的內容應如下所示:
config BR2_PACKAGE_CONAN_ZLIB
bool "conan-zlib"
help
Standard (de)compression library. Used by things like
gzip and libpng.
http://www.zlib.net
現在讓我們轉到包含Zlib數據的conan-zlib.mk:
# conan-zlib.mk
CONAN_ZLIB_VERSION = 1.2.11
CONAN_ZLIB_LICENSE = Zlib
CONAN_ZLIB_LICENSE_FILES = licenses/LICENSE
CONAN_ZLIB_SITE = $(call github,conan-community,conan-zlib,92d34d0024d64a8f307237f211e43ab9952ef0a1)
CONAN_ZLIB_REFERENCE = zlib/$(CONAN_ZLIB_VERSION)@conan/stable
$(eval $(conan-package))
這裡重要的一點CONAN_ZLIB_SITE
是即使不用於我們的目的也是必需的。如果不存在,則Buildroot將在執行過程中引發錯誤。其他變量很簡單,僅表示軟件包參考,名稱,版本和許可證。請注意,最後我們調用了應該執行柯南的腳本。
創建後,我們仍然需要將其添加到Buildroot配置列表中。為此,我們使用名為的新菜單更新列表Conan
。在package / Config.in文件中,讓我們添加以下部分:
menu "Conan"
source "package/conan-zlib/Config.in"
endmenu
現在,只需通過menuconfig選擇軟件包:
Target Packages -> Conan -> conan-zlib
配置並保存後,只需make
再次運行即可安裝該軟件包。在安裝過程中,我們將顯示以下輸出:

如您所見,Conan遵循的是Buildroot所使用的配置文件,這為我們提供了無需手動創建配置文件的優勢。
在安裝結束時,它將被複製到輸出目錄。
自定義柯南遙控器
假設我們有一個Artifactory實例,其中所有軟件包都可以下載。我們如何定制Buildroot使用的遙控器?我們需要引入一個新選項,我們可以在其中寫入遠程名稱,而柯南將可以使用該變量。首先,我們需要創建一個新的配置文件,以便在柯南菜單中插入新選項:
$ mkdir package/conan
$ touch package/conan/Config.in
Config.in文件應包含:
config CONAN_REMOTE_NAME
string "Conan remote name"
help
Look in the specified remote server.
另外,我們需要CONAN_REMOTE_NAME
在pkg-conan.mk中解析該選項並將其添加到Conan命令行中:
ifneq ($(CONAN_REMOTE_NAME),"")
CONAN_REMOTE = -r $$(CONAN_REMOTE_NAME)
endif
...
define $(2)_BUILD_CMDS
$$(TARGET_MAKE_ENV) $$(CONAN_ENV) $$($$(PKG)_CONAN_ENV) \
CC=$$(TARGET_CC) CXX=$$(TARGET_CXX) \
$$(CONAN) install $$(CONAN_OPTS) $$($$(PKG)_CONAN_OPTS) \
$$($$(PKG)_REFERENCE) \
-s build_type=$$(CONAN_SETTING_BUILD_TYPE) \
-s arch=$$(CONAN_SETTING_ARCH) \
-s compiler=$$(CONAN_SETTING_COMPILER) \
-s compiler.version=$$(CONAN_SETTING_COMPILER_VERSION) \
-g deploy \
--build $$(CONAN_BUILD_POLICY) \
$$(CONAN_REMOTE)
endef
現在,我們準備設置我們的特定遠程名稱。我們只需要運行make menuconfig
並遵循以下路徑:
Target Packages -> Libraries -> Conan -> Conan remote name
我們將看到:

現在,Conan已配置為在遠程命名工件中搜索軟件包。但是我們需要make
再次運行。請注意,由於現在有了Buildroot提供的緩存,因此構建時間將減少。現在我們準備好進行最後一步了。
安裝映像
經過兩個小時和幾杯咖啡後,如果在此過程中沒有發生錯誤,我們將得到以下輸出:
$ ls output/images/
bcm2710-rpi-3-b.dtb bcm2710-rpi-3-b-plus.dtb bcm2710-rpi-cm3.dtb boot.vfat rootfs.ext2 rootfs.ext4 rpi-firmware sdcard.img zImage
$ ls -lh output/images/sdcard.img
-rw-r--r-- 1 conan conan 153M ago 6 11:43 output/images/sdcard.img
這些工件是在構建過程中生成的所有內容的最終編譯,這裡我們將對sdcard.img文件感興趣。這是我們將在RaspberryPi3上使用的最終圖像,它只有153MB。與Raspbian等其他嵌入式發行版相比,它要小得多。
現在,將圖像複製到目標SD卡:
$ sudo dd if=output/images/sdcard.img of=/dev/mmcblk0 bs=4M conv=sync status=progress
請記住,SD卡的安裝點可能會因您的分佈而異。
完成後,將SD卡插入RaspberryPi3,並為已連接到視頻輸出的卡供電。您將看到引導加載程序正常運行,最後將顯示登錄屏幕,默認用戶為root,無需密碼。
結論
在本文中,我們討論瞭如何使用Buildroot輕鬆創建Linux發行版,從而獲得非常精簡的映像。
Buildroot僅使用感興趣的開發人員軟件包來幫助自動創建自定義嵌入式Linux發行版。
儘管構建過程可能需要幾個小時,但隨著柯南集成並替換了一些軟件包,該時間可以減少到只有幾分鐘。
資料來源: https://blog.conan.io/2019/08/27/Creating-small-Linux-images-with-Buildroot.html
沒有留言:
張貼留言