BitBake 實用指南

本文首發於本人博客 sunyongfeng.com

  1. 譯者序

本文譯自 A practical guide to BitBake

如果你發現 bug、不清楚的章節、打印錯誤或其他建議,請郵件告知我,我的郵箱是 [email protected]

注意:由於 task 和 recipe 是 BitBake 的基礎概念。個人覺得翻譯成任務和配方不免有誤解之處,因此文中基本不對這兩個詞做翻譯。類似的還有 configure。

  1. 序言

1.1 關於本教程

如果你閱讀本教程,說明你已經知道 BitBake 是一種類似 make 的構建工具,主要用於 OpenEmbedded 和 Yocto 工程構建 Linux 發行版本。你可能也已經意識到 BitBake 的學習曲線有點陡,本文可讓這個曲線變平緩一些。

本文不會告訴你 BitBake 的一切,但是會嘗試解釋使用 BitBake 時用到的一些基本功能。理解這些基礎可幫助你開始寫自己的 BitBake recipe。

1.2 本教程的目標

本教程展示如何創建一個最小工程,並一步步擴展,說明 BitBake 如何運作。

1.3 致謝

感謝 Tritech 給我時間準備本文檔。同時感謝大家在問題跟蹤站點報告的問題與打印錯誤。

1.4 反饋

如果你發現 bug、不清楚的章節、打印錯誤或其他建議, 請使用 issue tracker https://bitbucket.org/a4z/bitbakeguide/issues,不需要註冊。
同時也可以使用本文底部的 Disqus 評論功能。

  1. BitBake

2.1 什麼是 BitBake

以下內容有助於理解 BitBake:

基本上,BitBake是一個Python程序,它由用戶創建的配置驅動,可以爲用戶指定的目標執行用戶創建的任務,即所謂的配方(recipes)。

2.1.1 Config、tasks 與 recipes

通過一種 BitBake 領域特定語言寫 Config、tasks 與 recipes,這種語言包含變量與可執行的 shell、python 代碼。所以理論上,BitBake 可以執行代碼,你也可以用 BitBake 做除構建軟件之外的事情,但是並不推薦這麼做。

BitBake 是一種構建軟件的工具,因此有一些特殊的功能,比如可以定義依賴關係。BitBake 可以解決依賴關係,並將其任務以正確順序運行。此外,構建軟件包通常包含相同或相似的任務。比如常見的任務:下載源代碼包,解壓源代碼,跑 configure,跑 make,或簡單的輸出 log。Bitbake 提供一種機制,可通過一種可配置的方式,抽象、封裝和重用這個功能。

  1. 配置 BitBake

BitBake 可以從這裏下載:https://github.com/openembedded/bitbake。選擇一個版本的分支,並下載 zip。解壓 zip 包,可找到一個 bitbake-$version 目錄。

注意:本文使用的 Bitbake 版本是 bitbake-1.22,因此適合本教程的 bitbake 版本應該大於或等於1.22。
注意:譯者使用 bitbake-1.27.0,因此文中樣例爲 1.27.0 版本 bitbake 樣例。
提示:如果使用 Yocto,則不需要安裝 BitBake,Yocto 源代碼本身捆綁了 BitBake。Yocto 要求你 source 一個腳本,這個腳本和我們這裏做的一樣,安裝 BitBake 到我們的環境中。

3.1 安裝 BitBake

安裝過程很簡單:

  • 添加 bitbake-$version/bin 目錄到 PATH
  • 添加 bitbake-$version/lib 目錄到 PYTHONPATH

即執行:

export PATH=/path/to/bbtutor/bitbake/bin:$PATH
export PYTHONPATH=/path/to/bbtutor/bitbake/lib:$PYTHONPATH

這基本和 yocto init 腳本一致。yocto init 腳本同時也創建 build 目錄,我們將在一會兒創建。

首先檢測是不是一切正常、bitbake 是否安裝成功。通過執行以下 bitbake 命令:

bitbake --version

運行結果應該類似:

BitBake Build Tool Core version 1.27.0

3.2 BitBake 文檔

最實際的版本帶有源代碼。

在終端中,cd 到 bitbake-$version/doc 目錄並執行以下命令,生成 doc/bitbake-user-manual/bitbake-user-manual.html。

make html DOC=bitbake-user-manual

這個文檔可與本教程並行閱讀,在讀完本教程後也需要閱讀該文檔。

yocto 工程文檔 也有一個 bitbake 章節。

  1. 創建工程

4.1 Bitbake 工程佈局

通過 BitBake 工程通過 layers 目錄與一個 build 目錄組織,layer 目錄包含配置文件和 meta data。

4.1.1 Layer 目錄

Layer 目錄包含配置、任務和目標描述。常用 meta-'something' 命名 Layer 目錄。

4.1.2 Build 目錄

Build 目錄是 bitbake 命令被執行的地方。在這裏,BitBake 期望能找到其初始配置文件,並將其生成的所有文件放在這個目錄。

爲了讓 BitBake 運行時出現有任何錯誤,我們需要創建一個 build 目錄和一個 layer 目錄,並在此存放一些需要的配置文件。

4.2 最小工程

最小的配置看起來像這樣:

bbTutorial/
├── build
│   ├── bitbake.lock
│   └── conf
│       └── bblayers.conf
└── meta-tutorial
    ├── classes
    │   └── base.bbclass
    └── conf
        ├── bitbake.conf
        └── layer.conf

需要創建這 4 個文件:

  • bblayers.conf
  • base.bbclass
  • bitbake.conf
  • layer.conf

4.2.1 需要的配置文件

首先描述需要的文件,然後簡要說明其內容。

build/conf/bblayers.conf,BitBake 在其工作目錄(即 build 目錄)期望找到的第一個文件。現在我們以以下內容創建一個 bblayers.conf:

BBPATH := "${TOPDIR}"
BBFILES ?= ""
BBLAYERS = "/path/to/meta-tutorial"

meta-tutorial/conf/layer.conf,每個 layer 需要一個 conf/layer.conf 文件。現在我們以以下內容創建它:

BBPATH .= ":${LAYERDIR}"
BBFILES += ""

meta-tutorial/classes/base.bbclass
meta-tutorial/conf/bitbake.conf
現在,這些文件可以從 BitBake 安裝目錄中獲取。這些文件位於文件夾 bitbake-$version/conf 和 bitbake-$version/classes中。只需將它們複製到 tutorial 項目中。

4.2.2 創建文件的一些注意事項

build/conf/bblayers.conf

  • 添加當前目錄到 BBPATH,TOPDIR 被 BitBake 設置爲當前工作目錄。
  • 初始設置 BBFILES 變量爲空,Recipes 在後面會添加。
  • 添加我們 meta-tutorial 的路徑到 BBLAYERS 變量。當 BitBake 開始執行時,它會搜索所有給定的 layer 目錄,以便獲得其他配置。

meta-tutorial/conf/layer.conf

  • LAYERDIR 是 BitBake 傳給其所加載 Layer 的變量。我們添加該路徑到 BBPATH 變量。
  • BBFILES 告訴 BitBake recipes 在哪,現在我們沒有添加任何東西,但是一會兒我們會改變它。

注意事項。“.=” 和“+=” 以不添加空格、添加空格的方式,將追加值附給一個變量。

conf/bitbake.conf
conf/bibake.conf 包含 一系列我們討論的變量。

classes/base.bbclass
一個 *.bbclass 文件包含共享功能。我們的 base.bbclass 包含一些我們一會兒使用的 log 函數,以及一個 buld 任務。
並不是很有用,但是 BitBake 有需求,因爲如果沒有任何具體業務時,BitBake 默認需求的。我們隨後將改變此功能。

4.2.3 BitBake 搜索路徑

對於 BitBake 來講,有許多 BBPATH 非法和文件路徑。這說明如果我們告訴 BitBake 探索一些路徑時,它會搜索 BBPATH。
我們添加 TOPDIR 和 LAYERDIR 到 BBPATH,放在 classes/base.bbclass 或 conf/bitbake.conf 中的任意一個。
當然,我們會添加 meta-tutorial 目錄。
編譯目錄不應含有通用文件。只有像 local.conf 對實際編譯是有效的,後面我們會用到 local.conf。

第一次運行

創建上述四個配置文件後,在終端 cd 到 build 目錄,這是我們的工作目錄。我們一直在 build 目錄運行 bitbake 命令,以便 bitbake 可以找到相應的 conf/bblayers.conf 文件。

現在,在 build 目錄,不帶任何參數運行 bitbake 命令:

bitbake

如果先前的步驟正確,則控制檯會輸出:

Nothing to do.  Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.

這沒什麼用,但是一個好的開始。

這裏介紹一個很有用的命令標誌:輸出一些 debug 信息。
執行 bitbake -vDD,然後查看其輸出,它告訴我們大量關於 BitBake 如何動作的信息。

DEBUG: Found bblayers.conf (~/bbTutorial/build/conf/bblayers.conf)
DEBUG: LOAD ~/bbTutorial/build/conf/bblayers.conf
DEBUG: Adding layer ~/bbTutorial/meta-tutorial
DEBUG: LOAD ~/bbTutorial/meta-tutorial/conf/layer.conf
DEBUG: LOAD ~/bbTutorial/meta-tutorial/conf/bitbake.conf
DEBUG: BB configuration INHERITs:0: inheriting ~/bbTutorial/meta-tutorial/classes/base.bbclass
DEBUG: BB ~/bbTutorial/meta-tutorial/classes/base.bbclass: handle(data, include)
DEBUG: LOAD ~/bbTutorial/meta-tutorial/classes/base.bbclass
DEBUG: Clearing SRCREV cache due to cache policy of: clear
DEBUG: Using cache in '~/bbTutorial/build/tmp/cache/local_file_checksum_cache.dat'
DEBUG: Using cache in '~/bbTutorial/build/tmp/cache/bb_codeparser.dat'

你在注意到 BitBake 創建了一個 bitbake.log 文件和一個 tmp 目錄?

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ ls
bitbake.lock  conf  tmp

提示,所有的樣例代碼都可從 https://bitbucket.org/a4z/bitbakeguide 獲取。本樣例在 ch04。

  1. 第一個 recipe

BitBake 需要 recipes 定義要做些什麼,現在這裏什麼都沒有。
我們可以通過 bitbake -s 確認運行時什麼也沒做:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -s
ERROR: no recipe files to build, check your BBPATH and BBFILES?

Summary: There was 1 ERROR message shown, returning a non-zero exit code.
NOTE: Not using a cache. Set CACHE = <directory> to enable.
Recipe Name                                    Latest Version         Preferred Version
===========                                    ==============         =================

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ 

這告訴我們兩個信息:

  1. 沒有定義任何 cache;
  2. BitBake 真的沒事可做,只顯示了一個空的 recipe 列表

5.1 cache 位置

BitBake 緩存 meta data 在一個目錄,即 cache 目錄。這會幫助加速後面執行的命令。

我們可通過簡單添加一個變量到 bitbake.conf 文件,解決 cache 找不到的問題。因此,我們編輯 meta-tutorial/conf/bitbake.conf 文件,並在底部添加:

CACHE = "${TMPDIR}/cache/default"

添加後運行 bitbake -s 的結果:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -s
ERROR: no recipe files to build, check your BBPATH and BBFILES?

Summary: There was 1 ERROR message shown, returning a non-zero exit code.

注意:在實現項目中,比如 Yocto,這些變量已經設置好,我們不用關心。通常 cache 路徑由不同的變量組成,在名稱中包含實際的構建配置,如 debug 或 release。

下一步是添加一個 recipe,需要兩個步驟:

  1. 使 bitbake 可以找到 recipes
  2. 寫第一個 recipe

5.2 添加一個 recipe 到 tutorial layer

BitBake 需要知道一個 layer 提供哪些 recipes,可通過編輯 meta-tutorial/conf/layer.conf 文件,使用通配符告訴 BitBake 加載所有的 recipe:

BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb"

現在可以使用先前在 build/conf/bblayers.conf 定義的變量。recipe 文件的擴展名是 .bb,如果我們通過通配符的方式,只用一行就可以告訴 BitBake 加載所有 recipes。

通常 recipes 有自己的目錄,並以 groups 的形式收集在一起,也就是說把有關聯的 recipes 放在同一個目錄。

注意:通常使用 recipes-'group' 命令這些目錄,這裏 group 名錶示一個 category 或一些程序。

現在 BitBake 已經知道從哪找 recipe,我們可以開始添加第一個 recipe 了。

按通常的做法,我們創建目錄 meta-tutorial/recipes-tutorial/first,並在此創建第一個 recipe。 Recipe 文件也有通用的命名方法:{recipe}_{version}.bb

5.3 創建第一個 recipe 和 task

我們的第一個 recipe 只打印一些 log 信息。將它放在 tutorial group,版本爲 0.1。所以我們的第一個 recipe 是:
meta-tutorial/recipes-tutorial/first/first_0.1.bb

DESCRIPTION = "I am the first recipe"
PR = "r1"
do_build () {
  echo "first: some shell script running as build"
}
  • task do_build 覆蓋 base.bbclass 中的全局 build task。
  • PR 是內部修訂數據,在每次修訂後應被更新。
  • 設置 description 可解釋該 recipe 的用途。

如果上面都做對了,可以通過 bitbake -s 列出可用的 recipes。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -s
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors.
Recipe Name                                    Latest Version         Preferred Version
===========                                    ==============         =================

first                                                 :0.1-r1                          

然後就可以執行 bitbake first 編譯 first 組件。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake first
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.

現在檢查 tmp/work/first-0.1-r1/temp 目錄,裏面有一些有趣的文件:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ ls -al tmp/work/first-0.1-r1/temp/
total 20
drwxrwxr-x 2 sunyongfeng sunyongfeng 4096 10月 20 11:19 .
drwxrwxr-x 3 sunyongfeng sunyongfeng 4096 10月 20 11:19 ..
lrwxrwxrwx 1 sunyongfeng sunyongfeng   18 10月 20 11:19 log.do_build -> log.do_build.17314
-rw-rw-r-- 1 sunyongfeng sunyongfeng  123 10月 20 11:19 log.do_build.17314
-rw-rw-r-- 1 sunyongfeng sunyongfeng   37 10月 20 11:19 log.task_order
lrwxrwxrwx 1 sunyongfeng sunyongfeng   18 10月 20 11:19 run.do_build -> run.do_build.17314
-rwxrwxr-x 1 sunyongfeng sunyongfeng  909 10月 20 11:19 run.do_build.17314

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/first-0.1-r1/temp/log.do_build.17314 
DEBUG: Executing shell function do_build
first: some shell script running as build
DEBUG: Shell function do_build finished
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/first-0.1-r1/temp/log.task_order 
do_build (17314): log.do_build.17314
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/first-0.1-r1/temp/run.do_build
#!/bin/sh

# Emit a useful diagnostic if something fails:
bb_exit_handler() {
    ret=$?
    case $ret in
    0)  ;;
    *)  case $BASH_VERSION in
        "")   echo "WARNING: exit code $ret from a shell command.";;
        *)    echo "WARNING: ${BASH_SOURCE[0]}:${BASH_LINENO[0]} exit $ret from
  "$BASH_COMMAND"";;
        esac
        exit $ret
    esac
}
trap 'bb_exit_handler' 0
set -e
export HOME="/home/sunyongfeng"
export SHELL="/bin/bash"
export LOGNAME="sunyongfeng"
export USER="sunyongfeng"
export PATH="/home/sunyongfeng/ops-build.test/yocto/poky/scripts:/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
export TERM="linux"
do_build() {
  echo "first: some shell script running as build"

}

cd '/home/sunyongfeng/workshop/test/tutorial/build'
do_build

# cleanup
ret=$?
trap '' 0
exit $?
  1. Classes 和 functions

下一步將:

  • 添加一個 class
  • 添加一個使用 class 的 recipe
  • 探索 functions

6.1 創建 mybuild class

創建一個不同的 build 函數,並共享。先在 tutorial layer 創建 class,如 meta-tutorial/classes/mybuild.bbclass

addtask build
mybuild_do_build () {
 
  echo "running mybuild_do_build."
 
}
 
EXPORT_FUNCTIONS do_build

在 base.class 中,我們添加了一個 build task,它也是一個簡單的 shell 函數。mybuild_do 前綴的依據是 class 中 task 定義的規範 classname_do_functionname。

EXPORT_FUNCTIONS 使該 build 函數可被這個 class 的使用者使用,如果不添加這行,則它不會覆蓋 base class 中的 build 函數。

現在,已可在第二個 recipe 中使用這個 class。

6.2 在第二個 recipe 中使用 myclass

這裏添加一個小目標,在 build 任務前先運行一個 patch 函數,這裏需要一些 python 的用法。

依據 bitbake 的命名規範,我們添加一個新的 recipe 目錄,並在該目錄內添加一個 recipe 文件 meta-tutorial/recipes-tutorial/second/second_1.0.bb

DESCRIPTION = "I am he second recipe"
PR = "r1"                       (1)
inherit mybuild                 (2)
 
def pyfunc(o):                  (3)
    print dir (o)
 
python do_mypatch () {          (4)
  bb.note ("runnin mypatch")
  pyfunc(d)                     (5)
}
 
addtask mypatch before do_build (6)
  1. 像 first recipe 那樣定義 DESCRIPTION 和 PR;
  2. 繼承 mybuild class,讓 myclass_do_build 成爲默認 build task;
  3. 純 python 函數 pyfunc 獲取一些參數,並根據該入參運行 python dir 函數;
  4. bitbake python 函數 my_patch 添加並註冊成一個 task,該 task 要在 build 函數前執行。
  5. mypatch 函數調用 pyfunc 函數,並傳入全局 bitbake 變量 d。d (datastore) 由 bitbake 定義,並一直可用。
  6. mypatch 函數被註冊成一個 task,並要求在 build 函數前執行。

這就是一個使用 python 函數的樣例。

注意:函數部分的內容在 bitbake 手冊 3.4 節。

6.3 探索 recipes 和 tasks

現在我們有兩個 recipes 可用,可探索一些新的 bitbake 命令選項。我們可以獲取BitBake 運行時 recipes 及其 tasks、控制過程的信息。

6.3.1 顯示 recipes 和 tasks 列表

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -s
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 2 .bb files complete (0 cached, 2 parsed). 2 targets, 0 skipped, 0 masked, 0 errors.
Recipe Name                                    Latest Version         Preferred Version
===========                                    ==============         =================

first                                                 :0.1-r1                          
second                                                :1.0-r1 

如果想看某個 recipe 提供哪些 tasks,可以通過 bitbake -c listtasks recipe_name 查看:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -c listtasks second
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 2 .bb files complete (0 cached, 2 parsed). 2 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
do_showdata
do_build
do_mypatch
do_listtasks
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.

6.4 執行 tasks 或完整構建

有些選項可在 recipes 執行 builds 或特定任務時使用。

  • 構建一個 recipe。使用 bitbade recipe-name 執行該 recipe 的所有 tasks。
  • 執行一個 task。使用 bitbake -c your-task recipe-name 只運行 recipe 中的某個 task。
  • 構建所有 recipe。使用 bitbake world 運行所有 recipes 的所有 tasks。

可以玩玩這些命令,看會出現什麼。

6.4.1 確認構建過程中的 log

Bitbake 創建一個 tmp/work 目錄存放所有的 log 文件。這些 log 文件包含一些有趣的信息,值得一學。第一次執行完 bitbake world ,其輸出爲:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake world
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 2 .bb files complete (0 cached, 2 parsed). 2 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 3 tasks of which 0 didn't need to be rerun and all succeeded.
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ tree tmp/work/           
tmp/work/
├── first-0.1-r1
│   └── temp
│       ├── log.do_build -> log.do_build.17657
│       ├── log.do_build.17657
│       ├── log.task_order
│       ├── run.do_build -> run.do_build.17657
│       └── run.do_build.17657
└── second-1.0-r1
    ├── second-1.0
    └── temp
        ├── log.do_build -> log.do_build.17659
        ├── log.do_build.17659
        ├── log.do_mypatch -> log.do_mypatch.17656
        ├── log.do_mypatch.17656
        ├── log.task_order
        ├── run.do_build -> run.do_build.17659
        ├── run.do_build.17659
        ├── run.do_mypatch -> run.do_mypatch.17656
        └── run.do_mypatch.17656

這些 log 文件包含很多有用的信息,比如 BitBake 如何運行,執行 tasks 輸出了什麼。

  1. BitBake layers

典型 BitBake 工程包含多個 layer。通常 layer 包含一個特定主題,比如基礎系統、圖像系統等。一些工程可以包括不止一個構建目標,每個目標由不同的 layers 組成。例如,構建一個帶 GUI 組件或不帶 GUI 組件的 Linux 發行版本。

Layers 可以被使用、擴展、配置,也可能部分覆蓋已有的 layers。這很重要,因爲它允許根據實際要求重用或自定義。

多個 layers 共同動作是通用的例子,因此我們會添加一個額外的層次到工程。

7.1 添加一個 layer

通過以下步驟添加一個新的 layer:

  1. 創建一個新的 layer 目錄
  2. 創建 layer 配置
  3. 告訴 BitBake 有新的 layer
  4. 添加 recipes 到 layer

7.1.1 添加新的 layer 目錄

創建一個新的目錄叫 meta-two:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial$ ls
build  meta-tutorial  meta-two

7.1.2 配置新 layer

添加 meta-two/conf/layer.conf 文件,該文件和 tutorial layer 的一樣:

BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb"

7.1.3 告訴 BitBake 有新的 layer

編輯 build/conf/bblayers.conf,擴展 BBLAYERS 變量:

BBLAYERS = " \
  ${TOPDIR}/../meta-tutorial \
  ${TOPDIR}/../meta-two \
"

bitbake-layer 命令

通過 bitbake-layer 命令檢查新 layer 配置。
首先使用 show-layers 選項,顯示該工程的 layers、layers 路徑和優先級。這裏優先級都是 0,後面會嘗試改一下。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake-layers show-layers
layer                 path                                      priority
==========================================================================
meta-tutorial         /home/sunyongfeng/workshop/test/tutorial/build/../meta-tutorial  0
meta-two              /home/sunyongfeng/workshop/test/tutorial/build/../meta-two  0

bitbake-layers 命令還有其他有用的選項,可通過 -h 選項顯示。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake-layers -h
usage: bitbake-layers [-h] [-d] [-q] <subcommand> ...

BitBake layers utility

optional arguments:
  -h, --help            show this help message and exit
  -d, --debug           Enable debug output
  -q, --quiet           Print only errors

subcommands:
  <subcommand>
    show-layers         show current configured layers
    add-layer           Add a layer to bblayers.conf
    remove-layer        Remove a layer from bblayers.conf
    show-overlayed      list overlayed recipes (where the same recipe exists
                        in another layer)
    show-recipes        list available recipes, showing the layer they are
                        provided by
    show-appends        list bbappend files and recipe files they apply to
    flatten             flatten layer configuration into a separate output
                        directory.
    show-cross-depends  Show dependencies between recipes that cross layer
                        boundaries.
    layerindex-fetch    Fetches a layer from a layer index along with its
                        dependent layers, and adds them to conf/bblayers.conf.
    layerindex-show-depends
                        Find layer dependencies from layer index.

Use bitbake-layers <subcommand> --help to get help on a specific command

7.3 擴展 layer 配置

在 layer 的 layer.conf 文件中,定義優化級和其他配置值。爲配置 layer 的優先級,需要添加新的定義到已有的 layer.conf。以 meta-tutorial/conf/layer.conf 開始,添加:

# append layer name to list of configured layers                                                       
BBFILE_COLLECTIONS += "tutorial"                                                                       
# and use name as suffix for other properties                                                          
BBFILE_PATTERN_tutorial = "^${LAYERDIR}/"                                                              
BBFILE_PRIORITY_tutorial = "5" 

使用的變量在 BitBake 使用手冊有很好的說明,這裏不重複。

模式應是清楚的,這裏定義 layer 名,並使用這個名字做爲其他變量的後綴。這種在 BitBake 變量名中使用用戶定義的域後綴機制,在 BitBake 的很多地方可以看到。

同樣的,修改 meta-two/conf/layer.conf:

# append layer name to list of configured layers                                                       
BBFILE_COLLECTIONS += "tutorial"                                                                       
# and use name as suffix for other properties                                                          
BBFILE_PATTERN_tutorial = "^${LAYERDIR}/"                                                              
BBFILE_PRIORITY_tutorial = "5" 

如果此時運行 bitbake-layers show-layers,結果是:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake-layers show-layers     
layer                 path                                      priority
==========================================================================
meta-tutorial         /home/sunyongfeng/workshop/test/tutorial/build/../meta-tutorial  5
meta-two              /home/sunyongfeng/workshop/test/tutorial/build/../meta-two  5
  1. 共享和重用配置

截止目前,我們使用 classes 和 config 文件封裝配置和 tasks。但是還有更多的方法重用和擴展 tasks 和配置:

  • class 繼承
  • bbappend 文件
  • include 文件

爲說明如何使用這些方法,我們將添加 class 到 layer-two,新的 class 將介紹一個 configure-build 鏈並使用 class 繼承重用現存的 mybuild class。然後在新的 recipe 中使用這個新 class,最後通過 append 方法擴展現有的 recipe。

8.1 class 繼承

爲實現 configure-build 鏈,這裏創建一個 class,該 class 繼承 mybuild,並簡單添加一個 configure task,讓 build task 依賴 configure task。

meta-two/classes/confbuild.bbclass

inherit mybuild                            (1)
 
confbuild_do_configure () {                (2)
 
  echo "running configbuild_do_configure."
 
}
 
addtask do_configure before do_build       (3)
 
EXPORT_FUNCTIONS do_configure              (4)
  1. 以 mybuild class 爲基礎;
  2. 創建新的函數;
  3. 定義函數的順序,configre 在 build 之前;
  4. export 剛創建的函數使之可用。

然後創建 third recipe 使用 confbuild class。
meta-two/recipes-base/third_01.bb

DESCRIPTION = "I am the third recipe"
PR = "r1"
inherit confbuild

這時運行 bitabke third 會執行 configure 和 build task。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake third
Parsing recipes: 100% |######################################################################################################################################| Time: 00:00:00
Parsing of 3 .bb files complete (0 cached, 3 parsed). 3 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/third-01-r1/temp/
log.do_build            log.do_configure        log.task_order          run.do_build.19728      run.do_configure.19726  
log.do_build.19728      log.do_configure.19726  run.do_build            run.do_configure        
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/third-01-r1/temp/log.task_order 
do_configure (19726): log.do_configure.19726
do_build (19728): log.do_build.19728
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/third-01-r1/temp/log.do_configure
DEBUG: Executing shell function do_configure
running configbuild_do_configure.
DEBUG: Shell function do_configure finished
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/third-01-r1/temp/log.do_build
DEBUG: Executing shell function do_build
running mybuild_do_build.
DEBUG: Shell function do_build finished

8.2 bbappend 文件

append 文件可以添加函數到已有 class 中,而不需要創建一個新 class。它向同名 class 添加 append 文件的文本。需要設置 layer 配置,才能加載到對應的 append 文件。因此需要改變 layer 的配置,添加加載 *.bbappend 文件的配置到 BBFILES 變量。例如:
meta-two/conf/layer.conf

BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"

現在擴展已有的 first recipe,讓它在 build task 前先運行一個 patch 函數。爲做對比,將對應的 recipe 和 append 文件放到 meta-two/recipes-base/first 目錄。
meta-two/recipes-base/first/first_0.1.bbappend

python do_patch () {
  bb.note ("first:do_patch")
}
 
addtask patch before do_build

此時若列出 first recipe 的 task 列表,可以看到 patch task。運行 bitbake first 可看到運行了 patch 和 build。

添加前:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -c listtasks first
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 3 .bb files complete (0 cached, 3 parsed). 3 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
do_showdata
do_build
do_listtasks
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.

添加 append 文件後:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake -c listtasks first
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 3 .bb files complete (0 cached, 3 parsed). 3 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
do_showdata
do_build
do_listtasks
do_patch
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.

運行 bitbake first 結果:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake first
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 3 .bb files complete (0 cached, 3 parsed). 3 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/first-0.1-r1/temp/
log.do_build            log.do_listtasks.20111  run.do_build            run.do_listtasks.20111
log.do_build.20152      log.do_patch            run.do_build.20152      run.do_patch
log.do_listtasks        log.do_patch.20151      run.do_listtasks        run.do_patch.20151
log.do_listtasks.20001  log.task_order          run.do_listtasks.20001  
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/first-0.1-r1/temp/log.task_order 
do_listtasks (20001): log.do_listtasks.20001
do_listtasks (20111): log.do_listtasks.20111
do_patch (20151): log.do_patch.20151
do_build (20152): log.do_build.20152
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ 

提示:如果你願意,現在就可以構建一個 recipe,使用 confbuild class 和一個 append 文件,運行 patch、configure 和 build 任務。

8.3 include 文件

BitBake 有兩種指令引用文件:

  • include filename,這是一種可選引用,如果 filename 找不到,不會有 error 產生;
  • require filename,如果 filename 沒找到,會產生 error。

值得一提的是,include 和 require 都是在 BBPATH 中指定的目錄查找 filename。

8.3.1 添加 local.conf 用於引用文件

BitBake 工程通常使用 bitbake.conf 引用一個位於 build 目錄內的 local.conf 文件。local.conf 文件可能包含一些當前構建目標相關的特殊設置。典型的樣例是 Yocto 的設置。

這裏模仿 local.conf 的典型應用,讓 bitbake.conf require 引用 local.conf,添加以下內容到 meta-tutorial/conf/bitbake.conf:

require local.conf
include conf/might_exist.conf

如果此時執行構建命令,BitBake 會產生類似以下的錯誤信息:

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake world
ERROR: Traceback (most recent call last):
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/cookerdata.py", line 175, in wrapped
    return func(fn, *args)
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/cookerdata.py", line 185, in parse_config_file
    return bb.parse.handle(fn, data, include)
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/parse/__init__.py", line 107, in handle
    return h['handle'](fn, data, include)
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 148, in handle
    statements.eval(data)
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/parse/ast.py", line 39, in eval
    statement.eval(data)
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/parse/ast.py", line 61, in eval
    bb.parse.ConfHandler.include(self.filename, s, self.lineno, data, "include required")
  File "/home/sunyongfeng/ops-build.test/yocto/poky/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 98, in include
    raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), parentfn, lineno)
ParseError: ParseError at /home/sunyongfeng/workshop/test/tutorial/build/../meta-tutorial/conf/bitbake.conf:53: Could not include required file local.conf

ERROR: Unable to parse conf/bitbake.conf: ParseError at /home/sunyongfeng/workshop/test/tutorial/build/../meta-tutorial/conf/bitbake.conf:53: Could not include required file local.conf

添加一個 local.conf 文件到 build 目錄可解決此問題。注意 include 語句包含的文件可有可無。

  1. 使用變量

可定義變量並在 recipes 中使用,讓 BitBake 具有很強的靈活性。可將可配置部分使用變量的方式編寫 recipe,這種 recipe 的用戶可以給出那些將由 recipe 使用的變量值。一個典型的例子是給 recipe 傳遞額外的配置或標誌。通過正確使用變量,不需要編輯和更改 recipe,因爲某些函數只需要一些特殊的參數。

9.1 全局變量

全局變量可以通過使用者設置,recipe 可以使用。

9.1.1 定義全局變量

剛纔已經創建一個空的 local.conf,現在在這個文件加一些變量。比如添加一行:

MYVAR="hello from MYVAR"

9.1.2 訪問全局變量

可以在 recipes 或 classes 中訪問 MYVAR 變量。這裏創建一個新的 recipes 組 recipes-vars,及一個 recipe myvar。
meta-two/recipes-vars/myvar/myvar_0.1.bb

DESCRIPTION = "Show access to global MYVAR"
PR = "r1"
 
do_build(){
  echo "myvar_sh: ${MYVAR}"                        (1)
}
 
python do_myvar_py () {
  print "myvar_py:" + d.getVar('MYVAR', True)      (2)
}
 
addtask myvar_py before do_build
  1. 在類 bash 語法中訪問變量;
  2. 通過全局數據存儲訪問變量。

現在運行 bitbake myvar,檢查 tmp 目錄的輸出,則可以看到我們確實訪問了全局 MYVAR 變量。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake myvar
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 4 .bb files complete (0 cached, 4 parsed). 4 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ 
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/myvar-0.1-r1/temp/log.task_order 
do_myvar_py (4595): log.do_myvar_py.4595
do_build (4596): log.do_build.4596
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/myvar-0.1-r1/temp/log.do_myvar_py
DEBUG: Executing python function do_myvar_py
myvar_py:hello from MYVAR
DEBUG: Python function do_myvar_py finished
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/myvar-0.1-r1/temp/log.do_build
DEBUG: Executing shell function do_build
myvar_sh: hello from MYVAR
DEBUG: Shell function do_build finished

9.2 本地變量

典型的 recipe 只包含一些本地變量,這些變量用於其繼承的 classes 中的函數設置。

先創建 meta-two/classes/varbuild.bbclass

varbuild_do_build () {
  echo "build with args: ${BUILDARGS}"
}
 
addtask build
 
EXPORT_FUNCTIONS do_build

然後在 meta-two/recipes-vars/varbuld/varbuild_0.1.bb 中使用:

DESCRIPTION = "Demonstrate variable usage \
  for setting up a class task"
PR = "r1"
 
BUILDARGS = "my build arguments"
 
inherit varbuild

運行 bitbake varbuild,輸出的 log 顯示 build 任務使用了 recipe 設置的變量值。

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ bitbake varbuild
Parsing recipes: 100% |################################################################################| Time: 00:00:00
Parsing of 5 .bb files complete (0 cached, 5 parsed). 5 targets, 0 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/varbuild-0.1-r1/temp/log.task_order 
do_build (4760): log.do_build.4760
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ cat tmp/work/varbuild-0.1-r1/temp/log.do_build
DEBUG: Executing shell function do_build
build with args: my build arguments
DEBUG: Shell function do_build finished
sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial/build$ 

這是使用 BitBake的典型方法。通用 task 由 class 定義,比如下載源代碼、configure、make 和其他操作,recipe 設置這些 task 所需要的變量。

  1. 附目錄樹

sunyongfeng@openswitch-OptiPlex-380:~/workshop/test/tutorial$ tree ./*
./build
├── bitbake.lock
├── conf
│   └── bblayers.conf
└── local.conf
./meta-tutorial
├── classes
│   ├── base.bbclass
│   └── mybuild.bbclass
├── conf
│   ├── bitbake.conf
│   └── layer.conf
└── recipes-tutorial
    ├── first
    │   └── first_0.1.bb
    └── second
        └── second_1.0.bb
./meta-two
├── classes
│   ├── confbuild.bbclass
│   └── varbuild.bbclass
├── conf
│   ├── bitbake.conf
│   └── layer.conf
├── recipes-base
│   ├── first
│   │   └── first_0.1.bbappend
│   └── third
│       └── third_01.bb
└── recipes-vars
    ├── myvar
    │   └── myvar_0.1.bb
    └── varbuild
        └── varbuild_0.1.bb

14 directories, 17 files
  1. 總結

以上是本教程的所有內容,感謝你一直看到這裏,希望你喜歡。
學習完教程,你應該對 BitBake 的基本概念有基本理解。本教程涉及的內容有:

  • BitBake 是一個執行 python 和 shell 腳本的引擎;
  • 常見的 BitBake 工程設計與一些默認文件的位置;
  • BitBake 使用的 5 種文件類型(.bb,.bbclass,.bbappend,.conf 和 include 文件);
  • BitBake 函數和 task,說明如何組織、分組和調用它們;
  • BitBake 變量及其基本使用方法 。

熟悉這些內容後,希望你可以開始使用類似 Yocto 的工程,並繼續深入理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章