* 範圍
本文忽略了任務的依賴及其他處理,僅討論單個任務是如何被執行的。
* 簡介:
任務是定義在bb檔案中的python/shell函數,代表了軟體包build過程中的一個步驟。Bitbake約定,任務名必須以’do_‘開
始,bitbake提供任務的分析和處理機制,具體的任務由bbclass/bbfile提供。
* 前情提要:
Bitbake以Server/UI的方式運行,Server端負責等待並執行命令,UI端負責提交命令並回顯結果,二者通過一個雙向命令管道
和一個狀態隊列進行互動。Server決定何時執行什麼命令,而命令的具體執行由Cooker負責,這種機制通過回呼函數實現。
以bzip2為例,執行以下命令時:
$ bitbake bzip2
1)Bitbake分析命令列得到:cmdline={'action': ['buildTargets', ['bzip2'], 'build'], 'msg': None};
2)UI調用server.runCommand(cmdline['action']),把命令傳遞給Server;
3)Server交給cooker處理,cooker.buildTargets()被執行,它把自己定義的方法buildTargetsIdle()註冊到Server的_idlefunctions列表;
4)Server輪詢並執行非同步命令,控制權交還給buildTargetsIdle(),故事從這裡開始了...
* 任務執行:
Bitbake中任務是一個對象,任務的表現形式是TaskData執行個體。TaskData可以添加,刪除任務,處理任務的各種依賴,但是不能執行任務。
任務的執行依靠RunQueue實現, RunQueue是一個狀態機器,根據當前所處狀態執行相應的操作,RunQueue初始化時狀態為”runQueueSceneInit“。
從buildTargetsIdle()開始分析, '->'表示函數/方法的調用關係:
-> rq.execute_runqueue():
該方法執行runqueue隊列中的任務,在初始狀態下,它調用的是RunQueueExecuteScenequeue執行個體的execute()方法:
945 self.rqexe = RunQueueExecuteScenequeue(self)
948 retval = self.rqexe.execute()
-> RunQueueExecuteScenequeue.execute()
運行隊列中的任務,每一個任務都不是單獨存在的,若干任務構成了一條任務鏈,每個可執行任務最終要通過以下方式被執行:
1602 pid, pipein, pipeout = self.fork_off_task(fn, realtask, taskname)
-> RunQueueExecuteScenequeue.fork_off_task(): 這是一個Wrapper,下面才是真正的fork_off_task()
-> RunQueueExecute.fork_off_task():
先檢查和設定任務執行的環境和相關變數,任務的Flag:[umask/fakeroot]就是在這裡處理的; 執行任務調用如下方法:
1160 bb.build.exec_task
-> bb.build._exec_task(): 執行任務要比單獨執行一個函數複雜一些,仍然需要處理任務相關的環境變數和資料;然後剝去任務的外衣,把它當做函數處理:
321 exec_func(task, localdata)
-> bb.build.exec_func(): 處理任務的其他Flags,根據任務類型(python/shell)分而治之;
170 if ispython:
171 exec_func_python(func, d, runfile, cwd=adir)
172 else:
173 exec_func_shell(func, d, runfile, cwd=adir)
a. -> bb.build.exec_func_python(): 如果任務是python函數:
200 utils.better_exec(comp, {"d": d}, code, bbfile)
-> bb.utils.better_exec(): python類型的任務最終由python內建函數exec執行:
343 exec(code, _context, context)
b. -> bb.build.exec_func_shell():如果任務是shell函數:
243 bb.process.run(cmd, shell=False, stdin=NULL, log=logfile)
-> bb.process.run():把函數轉換成命令並返回命令的輸出:
95 pipe = Popen(cmd, **options) # subprocess.Popen(), 有關Popen()詳細使用請參考subprocess模組的help資訊。
至此一個任務執行完畢。
* 總結:
Bitbake中用TakeDate,RunQueueData組織任務資料,而且任務處理過程中還涉及到了資料緩衝,日誌和事件資訊的處理,它們
在BB中被抽象成了不同的類型和對象,希望以後能逐步分析,最終形成一個完整的BB物件類型系統說明。
* 參考:
$ bitbake bzip2 # 部分輸出
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing runqueue
NOTE: Executing SetScene Tasks
NOTE: Running setscene task 97 of 277 (/home/wenzong/sdb2/poky/meta/recipes-extended/bzip2/bzip2_1.0.6.bb:do_populate_sysroot_setscene)
NOTE: package bzip2-1.0.6-r3: task do_populate_sysroot_setscene: Started
NOTE: package bzip2-1.0.6-r3: task do_populate_sysroot_setscene: Succeeded
....
* Task Flags:
[dirs]: 任務運行前建立的目錄;
[cleandirs]: 任務運行前建立,並且是空目錄;
[noexec]: 不需要執行的任務;
[nostamp]: 不產生stamp檔案,任務總是被重新執行;
[fakeroot]: 任務需要在fakeroot環境下執行;
[umask]: 任務運行時的umask
[depends/deptask/rdeptask/recdeptask/recrdeptask]: 依賴的任務必須完成才能執行此任務