寫在前面
博主目前從事BMC工作,由於公司要開發openbmc項目,所以要學習Yocto項目。截至目前,我已經學習了一段時間了,大致可以熟練使用Yocto項目進行嵌入式系統的開發,由於網上這方面的相關知識不太多,所以想盡綿薄之力為這方面的知識做一些補充。文中可能有所疏漏,歡迎留言指正,另外有興趣的同學也歡迎交流。
1. Yocto項目是什么
Yocto項目本質是一個構建工具,其幫助開發者能夠快速地、簡單地設計一個基於Linux的系統。該項目由Linux基金會贊助,於2010年啟動。同時,在談到Yocto項目的時候,就不得不提到OpenEmbedded項目,該項目源於夏普的一個開源項目OpenZaurus(服務於SL-5000D),后來結合了其他幾個類似的嵌入式項目(Familiar Linux, OpenSIMpad),其目的是為嵌入式系統構建Linux發行版。OpenEmbedded項目維護了一個構建工具BitBake和一個元數據層(詳細描述了構建一個Linux發行版所需要的包及構建過程)。Poky Linux是OpenEmbedded項目的一個擴展應用,同時也是Yocto項目的前身。在2011年的時候,OpenEmbedded項目宣布於Yocto項目進行合作,共同維護BitBake以及一個核心數據層。
你可能想問它倆究竟區別在哪,其實它兩最終目標都是構建Linux發行版,但側重點不同,OpenEmbedded聚焦在尖端技術、菜譜和一大套針對不同硬件平台的板支持包,而Yocto項目聚焦在構建系統本身和針對交叉開發的工具化上。如果還不明白,那你直接就可以理解為一個偏硬件,一個偏軟件,相輔相成。
另外,我希望你可以通過下面這幅圖加深對我之前說的話的理解,圖片來自Yocto官網:

在上面圖中,poky是Yocto項目為開發者提供的一個開發樣例,用戶可以直接使用poky來生成一個Linux發行版鏡像,或者也可以通過擴展它來自定義鏡像。與此同時,poky中包含了一個核心元數據,其詳細描述了構建一個Linux發行版所需要的包及構建過程,而它正是OpenEmbedded項目的一部分。
2. Yocto項目有什么用
要說Yocto項目有什么用處,實際上前一節已經說了個大概。如果現在你需要基於Linux系統設計一個定制版的發行版,那么借助於Yocto項目你可以通過修改一些菜譜和配置文件(這些概念不懂沒事,之后會提到,你在這只需知道這些文件控制了構建Linux發行版系統的過程)非常簡單的構建出一個可用的發行版鏡像。又或者你現在有個小型嵌入式工控設備,需要為其提供一個特別小的可運行Linux系統,那么你也可以利用Yocto項目完成你的目的。
總之,借用Yocto官網的描述,Yocto項目就是一個工具,用於構建基於Linux的系統:
The project provides a flexible set of tools and a space where embedded developers worldwide can share technologies, software stacks, configurations, and best practices that can be used to create tailored Linux images for embedded and IOT devices, or anywhere a customized Linux OS is needed.
3. 如何快速上手Yocto項目
如果你之前曾今接觸過Yocto項目,那你肯定會抱怨過關於這方面網絡信息資源的匱乏。如果你真的對這個內容感興趣,你可以通過兩種學習路徑來理解和熟悉使用Yocto項目。
第一個學習路徑是我極為推薦的,那就是使用官網的學習手冊。這個手冊每次Yocto項目更新后,它也會隨之更新,因此內容是比較新的,不容易出現問題。但是問題就是內容是英文的,可能學起來稍微比較費時。
另外一個比較推薦的是通過Rudolf J. Streif寫的一本書《Embedded Linux Systems with the Yocto Project》,現在這本書已經被國內的一位大佬胥峰翻譯過來了,書名叫《嵌入式Linux系統開發:基於Yocto Project》。有點遺憾的是,該書是2018年出版的,所以文中有些內容已經有點過時了,所以需要讀者多注意一下。另外,如果有同學想要該書的電子版,可以留下郵箱。
最后,還要注意的是,不論哪種方法,文中都有大量的測試實驗,這些內容還請務必嘗試,最好可以舉一反三,我可以保證在學習完成之后你會有巨大的收獲。
4. 帶你通過Yocto項目編譯一個自定義鏡像文件
在做這個實驗之前,你必須先確認一下你的系統是否達到這些要求:
類型 | 需求 |
---|---|
構建主機CPU | X86架構 |
內存容量 | 大於或者等於4GB,不低於1GB |
網絡 | 最好設置連接到外網的代理,沒有也沒關系,只不過構建時間會很長 |
系統 | 任意Linux發行版 |
如果確定達到了這些要求,那么我們現在開始構建一個帶打印Hello World應用的桌面Linux系統發行版鏡像。
首先你需要預安裝一些Yocto工程會使用到的軟件包(以Ubuntu為例):
$ sudo apt install gawk wget git-core diffstat unzip texinfo gcc-multilib
$ sudo apt install build-essential chrpath socat cpio python3 python3-pip python3-pexpect
$ sudo apt install xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev
$ sudo apt install pylint3 xterm
其次,我們還需要克隆一個Yocto項目到本地:
$ git clone git://git.yoctoproject.org/poky
到此為止,你已經得到了一個完整的Yocto項目demo,直接構建該工程,你可以得到一個Linux系統發行版:
-
首先你需要初始化構建環境,以此來得到一些重要的環境變量,進入poky目錄,運行命令:
source oe-init-build-env build
,此時系統會創建一個構建目錄build(該目錄存放整個構建輸出內容,或者可以將其稱作構建環境),並跳轉到該目錄下。 -
使用vim打開build/conf/local.conf文件(該文件提供一些全局配置),增加兩行內容:
BB_NUMBER_THREADS = "4"
PARALLEL_MAKE = "-j 4"
這兩行內容分別是構建器使用的線程數,和編譯器(Make)使用的線程數,建議設置為小與系統實際能提供的最大線程數,否則默認使用最大線程數。這樣做的目的是避免線程數太多導致內存空間不足,以至於構建失敗,或者你也可以打開交換內存來增加內存空間避免這一問題,方法見這篇博客。
-
現在,你可以開始構建一個鏡像了,運行命令
bitbake core-image-sato
,這時你便開始構建一個帶用戶操作界面的Linux系統鏡像。當然了,大多數情況下,你一定會遇到一些構建錯誤,這時,你可以參考下這篇博客,或者留言,之后我會盡可能做出回復。 -
如果你成功構建完成,那么恭喜你,你已經成功了一大半了。現在開始,你可以驗證你構建的鏡像是否能夠使用,運行命令
runqemu tmp/deploy/images/qemux86-64/bzImage-qemux86-64.bin tmp/deploy/images/qemux86-64/core-image-sato-qemux86-64.ext4
。此時,系統將會使用默認參數啟動你剛剛構建的位於build/tmp/deploy/images/qemux86-64/目錄下的操作系統鏡像,例如你可以看到下面的界面:

通過上面的步驟,你已經得到了一個利用poky制作的樣例鏡像,接下來,我們要為這個鏡像嵌入一個我們要用的軟件包。
首先,先建立一個自己的層(一般在頂級目錄下,以meta開頭的目錄都叫層,每個層都是獨立的,因此為了避免污染其他層,我們建立自己的層),進入poky頂層目錄,執行命令mkdir meta-mylayer
。
對於每個層,都需要有自己層的配置文件,用於告訴構建器層中菜譜文件的位置及其他內容,因此我們提供這樣一個文件,進入meta-mylayer目錄中,新建一個文件夾conf,並在該目錄下新建一個layer.conf文件,其內容如下:
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend \
"
BBFILE_COLLECTIONS += "mylayer"
BBFILE_PATTERN_mylayer := "^${LAYERDIR}/"
BBFILE_PRIORITY_mylayer = "5"
除此之外,我們需要提供helloworld的源碼包,在meta-mylayer目錄中新建文件夾recipes-apps,並進入該目錄,新建文件夾hello-1.0,在這個文件夾新建三個文件,內容如下:

之后,我們將這三個文件打包為hello-1.0.tar.gz,並存放到hello-1.0目錄下。
隨后,我們需要設計軟件包菜譜,這個菜譜告訴了構建器從哪里找包,並如何編譯安裝到鏡像中,在recipes-apps目錄下新建hello_1.0.bb菜譜文件,其內容如下:
SUMMARY = "Simple Hello World Application"
DESCRIPTION = "A test application to demonstrate how to create a recipe \
by directly compiling C files with BitBake."
# a category this package belong to
SECTION = "examples"
# this package is optional, lacking of it doesn't cause error
PRIORITY = "optional"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "\
file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://hello-1.0.tar.gz"
# S = "${WORKDIR}"
# fix WARN_QA error
TARGET_CC_ARCH += "${LDFLAGS}"
do_compile() {
${CC} -c helloprint.c
${CC} -c hello.c
${CC} -o hello hello.o helloprint.o
}
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}
}
最后,我們將這個包添加到鏡像中,在文件meta/recipes-sato/images/core-image-sato.bb或者build/conf/local.conf中添加一行內容IMAGE_INSTALL += " hello "
。重新構建鏡像bitbake core-image-sato
,測試時,你可以發現多出了一個新的命令hello。
我希望能通過這個簡單的實例讓大家對Yocto有個初步的認識,如果想繼續深入了解Yocto項目,可以參照第三節內容學習,另外,你也可以關注我,后續我會不定期的更新這方面的相關知識。