はじめに
recipetoolでバイナリパッケージを作ってみる。
ちなみに今回は作ることが目的のため、作ったものの動作確認はしていない。
reciptool
オプションの確認
$ recipetool create --help
NOTE: Starting bitbake server...
usage: recipetool create [-h] [-o OUTFILE] [-p PROVIDES] [-m] [-x EXTRACTPATH]
[-N NAME] [-V VERSION] [-b] [--also-native]
[--src-subdir SUBDIR] [-a | -S SRCREV] [-B SRCBRANCH]
[--keep-temp] [--npm-dev] [--mirrors]
source
Creates a new recipe from a source tree
arguments:
source Path or URL to source
options:
-h, --help show this help message and exit
-o OUTFILE, --outfile OUTFILE
Specify filename for recipe to create
-p PROVIDES, --provides PROVIDES
Specify an alias for the item provided by the recipe
-m, --machine Make recipe machine-specific as opposed to
architecture-specific
-x EXTRACTPATH, --extract-to EXTRACTPATH
Assuming source is a URL, fetch it and extract it to
the directory specified as EXTRACTPATH
-N NAME, --name NAME Name to use within recipe (PN)
-V VERSION, --version VERSION
Version to use within recipe (PV)
-b, --binary Treat the source tree as something that should be
installed verbatim (no compilation, same directory
structure)
--also-native Also add native variant (i.e. support building recipe
for the build host as well as the target machine)
--src-subdir SUBDIR Specify subdirectory within source tree to use
-a, --autorev When fetching from a git repository, set SRCREV in the
recipe to a floating revision instead of fixed
-S SRCREV, --srcrev SRCREV
Source revision to fetch if fetching from an SCM such
as git (default latest)
-B SRCBRANCH, --srcbranch SRCBRANCH
Branch in source repository if fetching from an SCM
such as git (default master)
--keep-temp Keep temporary directory (for debugging)
--npm-dev For npm, also fetch devDependencies
--mirrors Enable PREMIRRORS and MIRRORS for source tree fetching
(disabled by default).
バイナリオプション-bがある。
これを指定してレシピを作成すると、自動的にbin_packageクラスを継承してくれる。
レシピの作成
今回は例としてラズベリーパイ4向けのtensorflowを作成する。
$ recipetool create -b https://github.com/Qengineering/Tensorflow-Raspberry-Pi/raw/master/libtensorflow_2_1_0.tar.gz
レイヤの作成
ビルドするために適当なレイヤを作成し、レシピを移動する。
$ bitbake-layers create-layer meta-local $ bitbake-layers add-layer meta-local $ mkdir ./meta-local/recipes-example/libtensorflow $ mv ./libtensorflow-2-1_0.bb ./meta-local/recipes-example/libtensorflow
ビルド
とりあえずビルドしてみる。
$ bitbake libtensorflow-2-1 NOTE: Tasks Summary: Attempted 551 tasks of which 158 didn't need to be rerun and all succeeded.
問題なくビルドできた。
tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/libtensorflow-2-1/0-r0/packages-split/libtensorflow-2-1でパッケージ内のツリー構成がどうなっているか確認する。
.
├── LICENSE
├── THIRD_PARTY_TF_C_LICENSES
├── include
│ └── tensorflow
│ └── c
│ ├── c_api.h
│ ├── c_api_experimental.h
│ ├── eager
│ │ └── c_api.h
│ ├── tf_attrtype.h
│ ├── tf_datatype.h
│ ├── tf_file_statistics.h
│ ├── tf_status.h
│ └── tf_tensor.h
└── lib
├── libtensorflow.so.2 -> libtensorflow.so.2.1.0
├── libtensorflow.so.2.1.0
├── libtensorflow_framework.so.2 -> libtensorflow_framework.so.2.1.0
└── libtensorflow_framework.so.2.1.0
tarの内容を/に展開しているようだ。
bin_package.bbclass
bin_package.bbclassの実装を確認してみると下記のようになっている。
do_configure[noexec] = "1"
do_compile[noexec] = "1"
# Install the files to ${D}
bin_package_do_install () {
# Do it carefully
[ -d "${S}" ] || exit 1
if [ -z "$(ls -A ${S})" ]; then
bbfatal bin_package has nothing to install. Be sure the SRC_URI unpacks into S.
fi
cd ${S}
tar --no-same-owner --exclude='./patches' --exclude='./.pc' -cpf - . \
| tar --no-same-owner -xpf - -C ${D}
}
FILES_${PN} = "/"
EXPORT_FUNCTIONS do_install
FILES_${PN} = "/"となっている。?=などではなく=で設定されているため、レシピやlocal.confでは設定を上書きできない。
bin_package.bbclassを継承しているの場合、どこにインストールされるかは元のtarの構成に依存するということになりそうだ。
インストールディレクトリを変更したい
先述の通り、bin_packageクラスを継承する場合は、パッケージのディレクトリツリーを単純には変更できない。
今回のように。/includeや/libのように、本来は使用するべきではないディレクトリにインストールされてしまうのは避けたい。
そのような場合は次のようにする。
do_install() {
install -d ${D}/opt
cp -ra "${S}/" "${D}/opt/"
chown -R root:root "${D}/opt/"
}
FILES_${PN}_remove = "/"
FILES_${PN}-dev = "/opt/libtensorflow-2-1-0/lib/*.so \
/opt/libtensorflow-2-1-0/lib/*.so.2 \
"
FILES_${PN} = "/opt/libtensorflow-2-1-0/"
do_installを上書きして、インストール先を変更する。この時ファイルの所有権をroot:rootに変更することを忘れると下記のエラーに苦しむ。
ERROR: libtensorflow-2-1-0-r0 do_package: Error executing a python function in exec_python_func() autogenerated:
The stack trace of python calls that resulted in this exception/failure was:
File: 'exec_python_func() autogenerated', lineno: 2, function: <module>
0001:
*** 0002:sstate_report_unihash(d)
0003:
File: '/home/mickey/work/yocto/rpi-dunfell/layers/poky/meta/classes/sstate.bbclass', lineno: 840, function: sstate_report_unihash
0836: report_unihash = getattr(bb.parse.siggen, 'report_unihash', None)
0837:
0838: if report_unihash:
0839: ss = sstate_state_fromvars(d)
*** 0840: report_unihash(os.getcwd(), ss['task'], d)
0841:}
0842:
0843:#
0844:# Shell function to decompress and prepare a package for installation
File: '/home/mickey/work/yocto/rpi-dunfell/layers/poky/bitbake/lib/bb/siggen.py', lineno: 555, function: report_unihash
0551:
0552: if "." in self.method:
0553: (module, method) = self.method.rsplit('.', 1)
0554: locs['method'] = getattr(importlib.import_module(module), method)
*** 0555: outhash = bb.utils.better_eval('method(path, sigfile, task, d)', locs)
0556: else:
0557: outhash = bb.utils.better_eval(self.method + '(path, sigfile, task, d)', locs)
0558:
0559: try:
File: '/home/mickey/work/yocto/rpi-dunfell/layers/poky/bitbake/lib/bb/utils.py', lineno: 420, function: better_eval
0416: if extraglobals:
0417: ctx = copy.copy(ctx)
0418: for g in extraglobals:
0419: ctx[g] = extraglobals[g]
*** 0420: return eval(source, ctx, locals)
0421:
0422:@contextmanager
0423:def fileslocked(files):
0424: """Context manager for locking and unlocking file locks."""
File: '<string>', lineno: 1, function: <module>
File "<string>", line 1, in <module>
File: '/home/mickey/work/yocto/rpi-dunfell/layers/poky/meta/lib/oe/sstatesig.py', lineno: 585, function: OEOuthashBasic
0581:
0582: update_hash("\n")
0583:
0584: # Process this directory and all its child files
*** 0585: process(root)
0586: for f in files:
0587: if f == 'fixmepath':
0588: continue
0589: process(os.path.join(root, f))
File: '/home/mickey/work/yocto/rpi-dunfell/layers/poky/meta/lib/oe/sstatesig.py', lineno: 548, function: process
0544: add_perm(stat.S_IXOTH, 'x')
0545:
0546: if include_owners:
0547: try:
*** 0548: update_hash(" %10s" % pwd.getpwuid(s.st_uid).pw_name)
0549: update_hash(" %10s" % grp.getgrgid(s.st_gid).gr_name)
0550: except KeyError:
0551: bb.warn("KeyError in %s" % path)
0552: raise
Exception: KeyError: 'getpwuid(): uid not found: 1000'
ERROR: Logfile of failure stored in: /home/mickey/work/yocto/rpi-dunfell/build/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/libtensorflow-2-1/0-r0/temp/log.do_package.8254
ERROR: Task (/home/mickey/work/yocto/rpi-dunfell/build/meta-local/recipes-example/libtensorflow/libtensorflow-2-1_0.bb:do_package) failed with exit code '1'
これはhashを生成する際にファイルの所有権をキーにするらしいのだが、この時bitbakeはfakerootで動いており、この動作環境内に一般ユーザーが存在しないためException: KeyError: 'getpwuid(): uid not found: 1000'が発生するということらしい。
まとめ
- バイナリパッケージを作成するには
bin_packageクラスを継承する。 - 作成されるパッケージのツリー構成は
/からに固定されている。 - 自分の好きなようにファイルを配置するには少し手間がかかるが不可能ではない。
- do_install時に所有権の変更を忘れずに。