Yoctoの依存関係を整理する

# はじめに
Yoctoを使う仕事をしていると、**依存関係**という言葉をよく聞きます
しかしながら、Yoctoにおける**依存関係**は結構複雑です。

このため、この記事では以下の順番で**依存関係**を整理します。

* パッケージとタスクの関係
* **依存関係**とは何か
* **パッケージ間の依存関係**の設定
* **タスク間の依存関係**の設定
* **依存関係**を可視化する方法
  
# 前提とする知識
yoctoの文脈で以下の言葉を知っていればたぶんOKです
* yocto
* poky
* bitbake
* パッケージ
* タスク
* フラグ
* DEPENDS/RDEPENDS

# パッケージとタスクの関係
### パッケージとは
パッケージはbitbakeのビルド単位です。例えば、gccやpythonなどのパッケージがあります。

### タスクとは
タスクはbitbakeが実行する処理の単位です。例えば、do_buildやdo_compileなどがあります。

### パッケージとタスクの関係
パッケージとタスクは1:Nの関係です。つまり、1パッケージに複数のタスクが紐づきます。
以下のようなイメージですね。

```
package_X -- package_X:do_fetch
          |- package_X:do_patch
	  |- package_X:do_compile
	  `- package_X:do_package_sysroot
package_Y -- package_Y:do_fetch
          |- package_Y:do_patch
	  |- package_Y:do_compile
	  `- package_Y:do_package_sysroot
```

御覧の通り、タスクは**パッケージ名:do_\*\*** という名前です
(**パッケージ名.do_\*\*** のように.でつなぐ場合もあります)
ただし、レシピに記載する際は**パッケージ名**の部分は記載しません

# **依存関係**とは何か
Yoctoにおける **依存関係**は以下の2種類が存在します。

* パッケージ間の依存関係
* タスク間の依存関係

bitbakeは最初にパッケージ間の**依存関係**はタスク間の**依存関係**に変換します。
つまり、以下の図のようになります。

![depends.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185272/57cd59a5-2f23-d5d3-9feb-d12ab1a58428.png)

具体的な設定方法は次のセクションで説明します。

# パッケージ間の依存関係の設定
パッケージ間の依存関係はさらに細かく以下の2種類に分類できます。

* ビルド時の依存関係
* 実行時の依存関係

それぞれ方法が異なるため、ひとつづつ設定方法を紹介します。

#### ビルド時の依存関係
###### 設定方法
端的にいうと、DEPENDSで設定します。[^1]
以下の例はpackage_Xがpackage_Yにビルド時に依存する場合の設定です。

```
# package_Xのレシピファイル
DEPENDS += " package_Y"
```

###### タスクの依存関係への変換方法
各タスクのdeptaskフラグを使って変換を実施します。
例えば、package_Xのレシピファイルが以下の場合を考えます。

```
# package_Xのレシピファイル
DEPENDS += " package_Y"
do_A[deptask] += "do_B"
```

この場合、DEPENDSの設定は
**package_X:do_Aがpackage_Y:do_Bに依存する**
というタスク間の依存関係に変換されます。

:::note info
deptaskフラグはbbclass(staging.bbclassなど)で設定されています。
ユーザーがdeptaskフラグを設定する必要は基本的にはありません。
:::

#### 実行時の依存関係
`ビルド時の依存関係` と同じですが、参照する変数やフラグが以下のように変わります。
* DEPENDS -> RDEPENDS
* deptask -> rdeptask

# タスク間の依存関係の設定
ここでは直接タスクとタスクの依存関係を設定する方法を紹介します。

#### 二つのタスクの順番を定義する
二つのタスクの依存関係を定義する場合、depends/rdependsフラグを使います。
この依存関係はタスクの実行順序を制御するだけの関係です。[^1]
```
# dependsフラグを使用する場合
do_A[depends] += "do_B"
# 別のパッケージのタスクへ依存する場合はこの書き方
do_A[depends] += "package_Y:do_B" 

# rdependsフラグを使用する場合
do_A[rdepends] += "do_B"
# 別のパッケージのタスクへ依存する場合はこの書き方
do_A[rdepends] += "package_Y:do_B" 
```

:::note info
rdependsはdependsとほぼ同じ働きをします
ただし、rdependsではpackage_Yの部分にPACKAGES変数の値が使用できます[^2]
:::

#### 再帰的に依存関係を定義する
recrdeptaskフラグを使用します。
[このメーリングリストのログ](https://lore.kernel.org/all/CAK7LNARQkLVykdxsY1RgcXNDP8zzLb+uSXkAsqdHo722iUEmyw@mail.gmail.com/T/)が詳しく説明してくれています。


# 依存関係を可視化する方法
#### パッケージ間の依存関係を可視化する方法
存在しません。頑張って自分でスクリプトを書きましょう[^3]
各パッケージのDEPENDSやRDEPENDSは以下の方法で取得できます

```$
$ bitbake -e ${PACKAGE_NAME} | grep ^DEPENDS=
```
パッケージ毎に上述のコマンドでbitbakeサーバを立てると時間がかかるとおもいます
--server-onlyオプションを活用するとよいかもしれません

#### タスク間の依存関係を可視化する方法
以下のコマンドで出力されるtask-depends.dotで可視化できます。

```
$ bitbake -g ${対象のパッケージ}
# 以下のコマンドでpng画像に変換できます。かなり時間かかる上に、巨大すぎて見づらいですが...
$ dot -Tpng -o output.png task-depends.dot
```


[^1]: DEPENDS/RDEPENDSの設定は、タスク間の依存関係へ変換されるだけではありません。各パッケージのsysrootに依存パッケージのアウトプットをコピーするという意味もあります。
[^2]: [PN](https://docs.yoctoproject.org/ref-manual/variables.html#term-PN), [PACKAGES](https://docs.yoctoproject.org/ref-manual/variables.html#term-PACKAGES)
[^3]: これはサポートされるべきと思う