2020年10月21日 星期三

BitBake 實用指南

 本文譯自A practical guide to BitBake

如果你發現bug、不清楚的章節、打印錯誤或其他建議,請郵件告知我,我的郵箱是`sunnogo@gmail.com `。

注意:由於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

即執行:

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

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

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

1
bitbake --version

運行結果應該類似:

1
BitBake Build Tool Core version 1.27.0

3.2 BitBake 文檔

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

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

1
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 最小工程

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

1 
2
3
4
5
6
7
8
9
10
11
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:

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

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

1 
2
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命令:

1
bitbake

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

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

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

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

1 
2
3
4
5
6
7
8
9
10
11
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 目錄?

1 
2
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確認運行時什麼也沒做:

1 
2
3
4
5
6
7
8
9
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 文件,並在底部添加:

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

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

1 
2
3
4
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:

1 
2
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

1 
2
3
4
5
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。

1 
2
3
4
5
6
7
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組件。

1 
2
3
4
5
6
7
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 1tasks of which 0 didn 't need to be rerun and all succeeded.

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

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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 1020 11 : 19 .
drwxrwxr-x 3 sunyongfeng sunyongfeng 4096 1020 11 : 19 ..
lrwxrwxrwx 1 sunyongfeng sunyongfeng 18 1020 11 : 19log.do_build -> log.do_build. 17314
-rw-rw-r-- 1 sunyongfeng sunyongfeng 123 1020 11 : 19 log.do_build. 17314
-rw-rw-r-- 1 sunyongfeng sunyongfeng 37 1020 11 : 19 log.task_order
lrwxrwxrwx 1 sunyongfeng sunyongfeng 18 1020 11 : 19 run.do_build -> run.do_build. 17314
-rwxrwxr-x 1 sunyongfeng sunyongfeng 909 1020 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

1 
2
3
4
5
6
7
8
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

1 
2
3
4
5
6
7
8
9
10
11
12
13
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 列表

1 
2
3
4
5
6
7
8
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查看:

1 
2
3
4
5
6
7
8
9
10
11
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 ,其輸出為:

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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:

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

7.1.2 配置新layer

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

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

7.1.3 告訴BitBake 有新的layer

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

1 
2
3
4
BBLAYERS = " \ ${TOPDIR} /../meta-tutorial \ ${TOPDIR} /../meta-two \ "



bitbake-layer 命令

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

1 
2
3
4
5
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 選項顯示。

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sunyongfeng@openswitch-OptiPlex- 380 :~/workshop/test/tutorial/build$ bitbake-layers -h 
usage: bitbake-layers [-h] [-d] [-q] <subcommand> ...

BitBake layers utility

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

subcommand s: <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 開始,添加:

1 
2
3
4
5
# 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:

1 
2
3
4
5
# 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,結果是:

1 
2
3
4
5
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

1 
2
3
4
5
6
7
8
9
10
11
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

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

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

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

1 
2
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

1 
2
3
4
5
python do_patch () { bb.note ( "first:do_patch" ) } addtask patch before do_build




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

添加前:

1 
2
3
4
5
6
7
8
9
10
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 文件後:

1 
2
3
4
5
6
7
8
9
10
11
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 結果:

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

1 
2
require local . conf 
include conf /might_exist. conf

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

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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,現在在這個文件加一些變量。比如添加一行:

1
MYVAR = "hello from MYVAR"

9.1.2 訪問全局變量

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

1 
2
3
4
5
6
7
8
9
10
11
12
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變量。

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

1 
2
3
4
5
6
7
varbuild_do_build () { echo "build with args: ${BUILDARGS} " } addtask build EXPORT_FUNCTIONS do_build






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

1 
2
3
4
5
6
7
DESCRIPTION = "Demonstrate variable usage \ 
for setting up a class task"
PR = "r1" BUILDARGS = "my build arguments" inherit varbuild




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

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
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. 附目錄樹

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 的工程,並繼續深入理解。

資料來源: http://sunyongfeng.com/201610/programmer/yocto/Bitbake_practical_guide

沒有留言: