この記事の前提
- C-10「Yoctoの地図」とC-10.5前編「現場で正を決める」の続きです
- 自社ユーザーアプリをGitから取得してpackage化する構成を主な例にします
- 変数の細かな挙動はYoctoのリリースで変わるため、採用版の公式資料と実際のpkgdataを最終確認してください
はじめに
前編では、次の三点を結論にしました。この後編は結論を増やす記事ではありません。前編の運用を実装・レビューするときに、BitBake内部のどの情報を根拠として確認すればよいかを掘り下げる記事です。
- 独立したリリース単位ごとにrecipeを分ける
- 同じ版を複数箇所へ直書きしない
- 出荷した組み合わせは製品マニフェストで確定する
では、これをYoctoで実現するとき、版情報はどのように流れるのでしょうか。
recipeファイル名の1.2.3、PV、PR、PKGV、Git tag、SRCREV。どれも版に関係しますが、同じものではありません。ここを曖昧にしたまま実装すると、GUIは1.2.3、package DBは1.0+git...、ビルド担当者はcommit IDだけを見ている、という状態になります。
後編では、BitBake内部の流れを追いながら、それぞれの役割を整理します。
まず全体の流れ
自社アプリをYocto製品へ載せるとき、release tag/version fileからrecipe、package metadata、rootfs、製品マニフェストへ情報が伝わります。途中で同じ文字列が何度か登場しても、役割は異なります。
この図の上段はrecipeからpackage DBへ流れる経路、下段はアプリ自身が版を名乗る経路です。表示形式が違っても、両方が同じcommitへ戻れることが重要です。
登場する変数・機能の早見表
すべてを一度に暗記する必要はありません。読み進めて迷ったら、この表へ戻ってください。
| 名前 | 分類 | 何を表す/何をするか |
|---|---|---|
PV |
recipe変数 | recipeが扱うソフトウェアの版 |
PR |
recipe変数 | 同じPVをpackage化し直したrevision |
PE |
recipe変数 | 版の比較順序を補正するepoch |
PKGE/PKGV/PKGR
|
package metadata | 最終package側のepoch/version/revision |
SRCREV |
recipe変数 | 取得してビルドするソースrevision |
PRSERV_HOST |
設定変数 | 接続するPR Serviceを指定する |
IMAGE_MANIFEST |
image成果物 | rootfsへ採用されたpackageと版の一覧 |
buildhistory |
class | package/image/SDKの構成変化を履歴化する |
image-buildinfo |
class | ビルド設定とlayer revisionを装置へ残す |
create-spdx |
class | image/SDKのSPDX SBOMを生成する |
PV、PR、PEは何を表すか
PV:recipeが扱うソフトウェアの版
PVはrecipe versionです。通常、recipeファイル名から設定されます。
product-gui_2.3.0.bb
└── PV = "2.3.0"
自社アプリが2.3.0としてリリースされるなら、recipeのPVも原則として2.3.0へ対応させます。ここへYocto担当者だけが知る27.4のような別番号を付けると、アプリ開発者との会話に変換表が必要になります。
recipeファイル名で版を表しているなら、同じ値をrecipe内へもう一度書く必要はありません。
# product-gui_2.3.0.bb
# ファイル名からPVが決まるため、PV = "2.3.0"は重ねて書かない
SUMMARY = "Product GUI"
LICENSE = "CLOSED"
PR:同じPVをどうpackage化し直したか
PRはrecipe revisionで、既定値はr0です。
アプリのソースは同じ2.3.0でも、次のようなrecipe側の修正でpackage内容が変わることがあります。
- systemd unitを修正した
- 設定ファイルやインストール先を変えた
- runtime dependencyを直した
- package分割を変更した
このときPRは、同じPVの中でどちらのpackageが新しいかをpackage managerへ伝えるために使われます。
ここで誤解しやすいのですが、BitBakeが再ビルドを判断するためにPRを上げるわけではありません。 BitBakeはタスク入力のsignatureで再実行を判断します。PRは主に、生成されたRPM、DEB、IPKなどの更新順序に関係します。
したがって、GUIへr7だけを「アプリ版」として表示しても、機能差は説明できません。
PE:版の比較規則を越えるためのepoch
PEはpackage epochです。通常は0で、表示上省略されます。上流の版体系が変わり、文字列比較では新しい版が古いと判断されてしまう場合などに使います。
普段から連番として回すものではありません。いったん上げると、そのpackage系列では以後もepochを意識する必要があります。
PKGVとPKGRは最終package側の値
PVとPRはrecipe側の値です。生成されるpackageでは、対応する値としてPKGVとPKGRが使われます。
| recipe側 | package側 | 既定の対応 |
|---|---|---|
PE |
PKGE |
PKGE = PE |
PV |
PKGV |
PKGV = PV |
PR |
PKGR |
PKGR = PR |
最終的なpackage版は、概念的には次の形です。
[PKGE:]PKGV-PKGR
ただし、PVに+を含めてソース管理情報をpackage版へ加える構成や、PR Serviceを利用する構成では、package生成の後段で値が補われます。そのため、bitbake -eだけを見て「最終版はこれだ」と判断しない方が安全です。
ビルド後にoe-pkgdata-utilで確認します。
oe-pkgdata-util package-info product-gui
このコマンドはPKGDATA_DIRにあるビルド済みpackage metadataを問い合わせます。GUIや製品マニフェストへpackage版を載せるなら、このような最終値を元にします。
SRCREV:実際にビルドするソースを固定する
Gitからソースを取得するrecipeでは、SRCREVがビルド対象のrevisionを決めます。
# product-gui_2.3.0.bb
SRC_URI = "git://git.example.local/product/product-gui.git;protocol=https;branch=main"
SRCREV = "0123456789abcdef0123456789abcdef01234567"
S = "${WORKDIR}/git"
release tagは、人が理解しやすい名前です。しかしtagは技術的には移動や付け直しが可能です。量産・出荷用recipeでは、tag名だけでなく、そのtagが指していた完全なcommit IDへSRCREVを固定します。
アプリ版とcommit IDは競合しません。
- アプリ版/tag:正式なリリースとして何を意味するか
- commit ID:実際にどのソース内容を使ったか
両方を結び付けて残します。
${AUTOREV}が量産へ向かない理由
SRCREV = "${AUTOREV}"
PV = "1.0"
${AUTOREV}は最新revisionを自動的に取得できるため、開発中には便利です。しかし、この例では取得するコードが変わっても、見た目のPVは1.0のままです。同じ名前の出荷ビルドが複数でき、追跡の起点を失います。
開発用の利便性として使う場合も、量産・リリースではcommit IDへ固定する運用に切り替えます。
PV = "1.2.3+git"とソース管理情報
YoctoではPVへ+を含めると、package化の後段でソース管理情報がPKGVへ加えられます。
PV = "1.2.3+git"
SRCREV = "0123456789abcdef0123456789abcdef01234567"
最終的には、採用するYoctoリリースやPR Serviceの有無に応じて、次のようなpackage版になります。
1.2.3+git0+0123456789-r0
ここで重要なのは、文字列の見栄えではなく、最終package版からソースrevisionへ戻れることです。具体的な生成形式を自社ルールで決め打ちせず、採用版の公式資料とoe-pkgdata-utilの結果を確認します。
2026年時点の補足:以前使われていた
${SRCPV}は、現在のYocto文書では非推奨化が進んでいます。保守対象の古いrecipeでは意味を読み取り、新規実装へ移すときは採用リリースの書き方を確認してください。
アプリ自身へ版をどう渡すか
GUIのソースへ版文字列を手書きしてはいけません。大きく二つの方法があります。
アプリリポジトリの版を使う
アプリが単独でもリリースされるなら、version fileやrelease tagをアプリ側の意味上の正にします。CIで次を検査します。
-
VERSIONの値、release tag、recipeのPVが対応している - release tagが指すcommitと、recipeの
SRCREVが一致している
git describeをビルド時に埋め込む方法もありますが、ビルド用ソースツリーにGit metadataが存在することを暗黙の前提にしないよう注意します。開発者のローカルビルドでは便利でも、正式ビルドではCIまたはrecipeが確定した版とrevisionを明示的に渡す方が制御しやすいことがあります。
また、正式ビルドの作業ツリーがdirtyなら、版表示から隠すのではなく、ビルドを失敗させる方が安全です。未commitの内容は、同じcommitをcheckoutしても再現できないためです。
recipeから版を注入する
製品専用アプリなら、recipeが持つ値をCMakeなどへ渡せます。
EXTRA_OECMAKE += "-DAPP_VERSION=${PV} -DAPP_SOURCE_REVISION=${SRCREV}"
アプリ側は、渡された値からversion headerやJSON resourceを生成します。これなら、GUI用文字列を別に手入力せずに済みます。
ただし、PR Serviceが後段で付与する最終PKGRまでdo_compile中のバイナリへ埋め込もうとすると、処理順が不自然になります。アプリ自身には意味上の版とsource revisionを持たせ、最終package版はpackage metadataや製品マニフェストから取得する方が整理しやすくなります。
一つのrecipeから複数packageを作るとき
一つのrecipeから複数のpackageを生成することは一般的です。
PACKAGES =+ "${PN}-gui ${PN}-daemon"
FILES:${PN}-gui = "${bindir}/product-gui"
FILES:${PN}-daemon = "${sbindir}/product-daemon ${systemd_system_unitdir}/system/product-daemon.service"
この場合、実行ファイルは別packageになっても、同じrecipeが持つPV/PRを基本的に共有します。
したがって、この構成が自然なのは次のような場合です。
- 同じソースから作る
- 同じtagでリリースする
- 同じ組み合わせで試験する
- 常に一緒に出荷する
GUI2.3.0とデーモン1.8.2を独立して更新したいのに、一つのrecipeへ押し込むと、recipeのPVが何の版なのか分からなくなります。この場合は別recipeへ分け、packagegroupやimage recipeで組み合わせます。
BitBakeでは、一つのrecipeから複数のGitリポジトリを取得し、それぞれに名前付きSRCREVを設定することも可能です。しかし、できることと保守しやすいことは別です。複数リポジトリを束ねる明確なリリース上の理由がなければ、recipeを分ける方が追跡しやすくなります。
PR Serviceは何を解決するか
同じPVでpackage内容が変わるたび、人がPRを確実に増やし続けるのは簡単ではありません。特に複数のビルドマシンから同じpackage feedへ成果物を出すと、更新順序の整合が問題になります。
PR Serviceは、packageの変更に応じて増加するrevisionを管理します。生成結果では、例えばr0.1、r0.2のように.xが追加されます。
PRSERV_HOST = "localhost:0"
これは単一ビルドホストで使う最小例です。複数ホストが共通package feedへ成果物を供給する場合は、同じPR Serviceを共有する構成を検討します。sstateとの共有範囲も含め、全ビルド環境で方針を統一する必要があります。
PR Serviceを使っても、アプリの機能版が自動的に決まるわけではありません。管理するのはpackage revisionです。アプリ版、source revision、製品版は別に残します。
rootfsへ本当に入った版を確認する
recipeを更新しただけでは、そのpackageが最終imageへ入った証明にはなりません。image生成後の情報を確認します。
IMAGE_MANIFEST
Yoctoは、imageへインストールされたpackageの名前、architecture、versionをマニフェストとして出力できます。まず「rootfsへ本当に入ったpackage版」を確認する基準になります。
oe-pkgdata-util
ビルド済みpackageの最終metadataをPKGDATA_DIRから確認します。
oe-pkgdata-util package-info product-gui
oe-pkgdata-util find-path /usr/bin/product-gui
buildhistory
package、image、SDKの構成変化をGit履歴として記録できます。
INHERIT += "buildhistory"
BUILDHISTORY_COMMIT = "1"
意図せず依存packageが増えた、package sizeが急増した、versionが後退した、といった変化をCIで検出する材料になります。PR Serviceと併用することも公式資料で推奨されています。
image-buildinfo
IMAGE_CLASSES += "image-buildinfo"
既定ではターゲットの/etc/buildinfoへ、ビルド設定と使用した全layerのrevisionを書き出します。現物から「どのlayer構成で作ったimageか」を確認する入口になります。
SPDX SBOM
imageやSDKの内容に基づくSPDX SBOM(ソフトウェア部品表)を生成できます。GUI表示用の簡易版情報とは用途が異なりますが、脆弱性・ライセンス調査で「何が入っていたか」を機械的に追うための記録になります。
ここは版差が大きい部分なので、私が触れてきた旧版と2026年時点のYocto 6.0系を分けて見ます。注意したいのは、create-spdxというクラス名が同じでも、採用リリースにより生成するSPDX世代が異なることです。
# 旧リリース:create-spdxがSPDX 2.2文書を生成する構成
INHERIT += "create-spdx"
# Yocto 6.0系:create-spdxがSPDX 3.0文書を生成する
INHERIT += "create-spdx"
Yocto 6.0ではcreate-spdx-2.2が削除され、create-spdxによるSPDX 3.0生成へ一本化されました。途中のリリースで使われたクラス名もあるため、脆弱性対応の運用へ組み込む前に、採用版の移行ガイドとclassリファレンスを確認してください。
製品マニフェストはどこで作るか
まず、装置上ですでに利用できる情報源を整理します。
| 情報源 | 主な生成元 | 分かること |
|---|---|---|
/etc/os-release |
OS/distro設定 | 製品向けの版、BUILD_IDなど |
/etc/buildinfo |
image-buildinfo |
ビルド設定、全layerのrevision |
| package DB/pkgdata | package生成処理 | 最終package版、ファイルとの対応 |
| アプリの版情報 | version fileまたはrecipeからの注入 | アプリ版、source revision |
IMAGE_MANIFEST |
image生成処理 | rootfsへ採用されたpackage一覧 |
製品マニフェストは、これらを置き換える別の台帳ではありません。GUIや保守ツールが使いやすい形へ、必要な情報を結び直す索引です。
製品GUIが読むマニフェストへ、次のような情報を集めます。
- 製品版とBuild ID
- アプリの意味上の版
- 最終package版
- source revision
- layer revision
- 対象machineとハードウェアrevision
- 必要に応じて設定・データのschema version
ただし、この情報を一つのrecipeへ手書きしてはいけません。CIまたは自社のimage classで、次の確定済み情報を集めて製品マニフェストを生成します。
- 製品リリース情報
- recipeが固定した
SRCREV - pkgdataの最終package版
-
IMAGE_MANIFESTの採用package一覧 - buildinfo/buildhistoryのlayer revision
特に最終package revisionはpackage生成段階で決まることがあります。アプリのcompile時に将来のpackage版らしき値を埋め込むより、image生成側で最終metadataを収集する方が確実です。
装置内へ入れる簡易マニフェストと、ビルドサーバへ保管する完全な記録を分けても構いません。装置側には保守に必要な主要情報、サーバ側には全package、layer、SBOM、試験結果を残し、Build IDで結びます。
CIで検査したいこと
自動化の目的は、版を自動で増やすことだけではありません。人が間違った組み合わせを出荷できないようにすることです。
最低限、次を検査します。
- アプリのversion fileとrelease tagが一致する
- recipeの
PVがアプリ版へ対応している -
SRCREVがrelease tagのcommitと一致する - 量産設定で
${AUTOREV}を使っていない - 正式ビルドに未commit変更がない
- image manifestへ必要なpackageが入っている
- 製品マニフェストとpkgdataの最終package版が一致する
- Build IDに対応するCI成果物と試験結果が保存されている
現地の一画面からソースへ戻る
ここまでの情報が結び付くと、前編で示した追跡経路を、Yoctoの成果物で裏付けられます。
この連鎖が作れていれば、「画面には1.2.3と出ているけれど、中身は何だろう」で止まりません。
まず手元のビルドで確かめる
最初から独自マニフェストを実装する必要はありません。まず、BitBakeのビルド環境を初期化し、対象packageとimageを一度ビルドした状態で、すでに生成されている情報を確認します。次は、標準的なTMPDIR = "${TOPDIR}/tmp"を前提にした例です。
# 自社packageの最終metadataを確認する
oe-pkgdata-util package-info product-gui
# imageへ入ったpackage一覧を探す
find tmp/deploy/images -name '*.manifest'
実機では、次の情報が取得できるか確認します。
cat /etc/os-release
cat /etc/buildinfo # image-buildinfoを有効にしている場合
次に、開発用ビルドのlocal.confでbuildhistoryを有効にし、変更前後の差分を見ます。
INHERIT += "buildhistory"
BUILDHISTORY_COMMIT = "1"
ここまで確認すると、「足りないのはアプリ版なのか、最終package版なのか、layer revisionなのか」が分かります。その不足分を製品マニフェストへ結ぶ順番で進めると、いきなり大きな仕組みを作らずに済みます。
まとめと次回
-
PVはrecipeが扱うソフトウェア版、PRは同じPVのpackage revisionを表す - 最終package側では
PKGE、PKGV、PKGRを確認する -
SRCREVはビルド対象のcommitへ固定し、アプリ版/tagと対応させる - 複数packageへ分けても同じrecipeの版系列は基本的に共通なので、独立リリースならrecipeを分ける
- アプリへは意味上の版とsource revisionを渡し、最終package版は後段のmetadataから収集する
- 出荷構成は
IMAGE_MANIFEST、pkgdata、buildhistory、buildinfo、SBOMを利用して製品マニフェストへ結ぶ
前後編を通した結論は、各層の正を一つにし、その間を人の転記ではなく生成物で結ぶことです。
次回C-11では、この版管理の考え方を持ったまま、AMD Zynq系の「Vivado→XSA→PetaLinux/Yocto」という流れを追います。
参考資料
- Variables Glossary:PV/PR/PE/PKGV/PKGR/SRCREV(Yocto Project Reference Manual)
- Working With a PR Service(Yocto Project Development Tasks Manual)
- Viewing Package Information with oe-pkgdata-util(Yocto Project Development Tasks Manual)
- Maintaining Build Output Quality:buildhistory(Yocto Project Development Tasks Manual)
- image-buildinfo/create-spdx classes(Yocto Project Reference Manual)
- Yocto Project 6.0 Migration Notes ― SPDX 2.2 support removed
- IMAGE_MANIFEST(Yocto Project Variables Glossary)
- Reproducible Builds(Yocto Project Test Environment Manual)

