みつきんのメモ

組み込みエンジニアです。Interface誌で「My オリジナルLinuxの作り方」連載中

yoctoでjetson nanoを動かす

はじめに

meta-tegrajetson nanoに対応したので、yoctoで動かしてみる。

いくつか注意点

readmeに重要な注意点がいくつか書いてある。

  • jetpackは必要
  • cuda10を使用する関係でgccは7系固定

Jetson-TX1についても書いてあるけど関係ないので無視。

そして最後に重要なやつ。

Toolchain version selection is usually a distro configuration setting,
but you can also set this in your build/conf/local.conf file. To use
gcc 7 instead of gcc 8, set:

GCCVERSION = "7.%"

but you will also need the gcc 7 toolchain recipes in one of your layers,
since it was retired from OE-Core in favor of gcc 8.

local.confでGCCVERSION = "7.%"と設定すればgcc7系を選択しようとするけど、 warriorブランチではgcc7系のレシピは削除されているので、自分でレイヤ作ってgcc7系のレシピを用意してね!

とのこと。

JetPackのインストール

CUDAを使用するためにはNVIDIAプロプライエタリな成果物を必要とするため yocto環境だけでは完結しない。

予めNVIDIA Developer Network(Devnet)にログインしJetPackのパッケージをインストールしておく必要がある。 このためにはDevnetのアカウントを作成する必要がある。

NVIDIAのサイトJOINをクリックし、指示に従ってアカウントを作成する。

アカウントの作成ができたら、ここからNVIDIA SDK Managerをダウンロードする。

debパッケージなのでgdebiコマンドでインストールと便利。

$ sudo gdebi sdkmanager_0.9.11-3405_amd64.deb

SDK Managerを起動する。

$ sdkmanager

ログイン画面が表示されるのでDevnetのアカウントでログインする。

f:id:mickey_happygolucky:20190421002434p:plain

Target HardwareをJetson Nanoに変更する。

f:id:mickey_happygolucky:20190421002442p:plain

I accept the terms and conditions of the license agreementsにチェックを入れる。

f:id:mickey_happygolucky:20190421002458p:plain

Linuxの管理者権限のパスワード(sudo)を入力する。 ログインパスワードではないので注意。

f:id:mickey_happygolucky:20190421002517p:plain

セットアップの項目が出てくるので、全部スキップする。

f:id:mickey_happygolucky:20190421002522p:plain f:id:mickey_happygolucky:20190421002532p:plain

本当にスキップするか確認されるのでYesをクリック

f:id:mickey_happygolucky:20190421002538p:plain

完了。

f:id:mickey_happygolucky:20190421002551p:plain

環境構築

ソース取得

Jetson Nanoはmeta-tegraのmasterかwarriorブランチでのみ対応している。 masterブランチのLAYERSERIES_COMPATwarriorに設定されているので、 thud以前のバージョンでは使用できない。

warriorは開発中のステータスだが、今回はこれを使う。

$ mkdir -p jetson-warrior/layers
$ cd jetson-warrior/layers
$ git clone git://git.yoctoproject.org/poky.git -b warrior
$ git clone git://git.openembedded.org/meta-openembedded
$ git clone https://github.com/madisongh/meta-tegra.git -b warrior
$ cd ../

meta-openembeddedwarriorブランチがまだ無いので、masterブランチを使用する。

環境変数設定

$ source layers/poky/oe-init-build-env build

自動的にビルドディレクトリに移動される。 これで、bitbake関連のツールが使用可能になる。

レイヤ追加

$ bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
$ bitbake-layers add-layer ../layers/meta-tegra/

meta-localの作成

先述の通りgcc7系のレシピを用意する必要があるので、そのためのレイヤを作成する。

$ bitbake-layers create-layer meta-local
$ rm -rf ./meta-local/recipes-example
$ mkdir -p ./meta-local/recipes-devtools/gcc
$ mv meta-local ../layers
$ bitbake-layers add-layer ../layers/meta-local

pokyリポジトリから古いレシピを取り出す。

$ pushd .
$ cd ../layers/poky/meta/recipes-devtools/gcc
$ git checkout -b thud origin/thud
$ cp -ra *7.3* ../../../../meta-local/recipes-devtools/gcc/
$ cp *.inc ../../../../meta-local/recipes-devtools/gcc/
$ rm -f ../../../../meta-local/recipes-devtools/gcc/*8.*
$ git checkout warrior
$ git branch -D thud
$ popd

gccレシピの修正

warriorではgcc-initialが廃止されるなど、glibcとの依存関係が変更されているためレシピを修正する必要がある。

diff --git a/recipes-devtools/gcc/gcc-cross-canadian.inc b/recipes-devtools/gcc/gcc-cross-canadian.inc
index 2f32d34..e7c08d3 100644
--- a/recipes-devtools/gcc/gcc-cross-canadian.inc
+++ b/recipes-devtools/gcc/gcc-cross-canadian.inc
@@ -3,7 +3,7 @@ inherit cross-canadian
 SUMMARY = "GNU cc and gcc C compilers (cross-canadian for ${TARGET_ARCH} target)"
 PN = "gcc-cross-canadian-${TRANSLATED_TARGET_ARCH}"
 
-DEPENDS = "virtual/${TARGET_PREFIX}gcc virtual/${HOST_PREFIX}gcc-crosssdk virtual/${HOST_PREFIX}binutils-crosssdk virtual/nativesdk-${HOST_PREFIX}libc-for-gcc nativesdk-gettext flex-native"
+DEPENDS = "virtual/${TARGET_PREFIX}gcc virtual/${HOST_PREFIX}gcc-crosssdk virtual/${HOST_PREFIX}binutils-crosssdk virtual/nativesdk-libc nativesdk-gettext flex-native virtual/libc"
 
 GCCMULTILIB = "--enable-multilib"
 
diff --git a/recipes-devtools/gcc/gcc-cross.inc b/recipes-devtools/gcc/gcc-cross.inc
index 89b1968..3274d08 100644
--- a/recipes-devtools/gcc/gcc-cross.inc
+++ b/recipes-devtools/gcc/gcc-cross.inc
@@ -2,7 +2,7 @@ inherit cross
 
 INHIBIT_DEFAULT_DEPS = "1"
 EXTRADEPENDS = ""
-DEPENDS = "virtual/${TARGET_PREFIX}binutils virtual/${TARGET_PREFIX}libc-for-gcc ${EXTRADEPENDS} ${NATIVEDEPS}"
+DEPENDS = "virtual/${TARGET_PREFIX}binutils ${EXTRADEPENDS} ${NATIVEDEPS}"
 PROVIDES = "virtual/${TARGET_PREFIX}gcc virtual/${TARGET_PREFIX}g++"
 python () {
     if d.getVar("TARGET_OS").startswith("linux"):
@@ -31,7 +31,6 @@ EXTRA_OECONF += "\
     --with-system-zlib \
 "
 
-DEPENDS_remove_libc-baremetal := "virtual/${TARGET_PREFIX}libc-for-gcc"
 EXTRA_OECONF_append_libc-baremetal = " --without-headers"
 EXTRA_OECONF_remove_libc-baremetal = "--enable-threads=posix"
 EXTRA_OECONF_remove_libc-newlib = "--enable-threads=posix"
@@ -44,6 +43,11 @@ EXTRA_OECONF_PATHS = "\
 
 ARCH_FLAGS_FOR_TARGET += "-isystem${STAGING_DIR_TARGET}${target_includedir}"
 
+do_configure_prepend () {
+   install -d ${RECIPE_SYSROOT}${target_includedir}
+   touch ${RECIPE_SYSROOT}${target_includedir}/limits.h
+}
+
 do_compile () {
    export CC="${BUILD_CC}"
    export AR_FOR_TARGET="${TARGET_SYS}-ar"
diff --git a/recipes-devtools/gcc/gcc-crosssdk.inc b/recipes-devtools/gcc/gcc-crosssdk.inc
index cda2927..bd2e71d 100644
--- a/recipes-devtools/gcc/gcc-crosssdk.inc
+++ b/recipes-devtools/gcc/gcc-crosssdk.inc
@@ -8,5 +8,5 @@ SYSTEMLIBS1 = "${SDKPATHNATIVE}${libdir_nativesdk}/"
 
 GCCMULTILIB = "--disable-multilib"
 
-DEPENDS = "virtual/${TARGET_PREFIX}binutils-crosssdk virtual/nativesdk-${TARGET_PREFIX}libc-for-gcc gettext-native ${NATIVEDEPS}"
+DEPENDS = "virtual/${TARGET_PREFIX}binutils-crosssdk gettext-native ${NATIVEDEPS}"
 PROVIDES = "virtual/${TARGET_PREFIX}gcc-crosssdk virtual/${TARGET_PREFIX}g++-crosssdk"
diff --git a/recipes-devtools/gcc/libgcc-initial.inc b/recipes-devtools/gcc/libgcc-initial.inc
index 950ad86..6edbd30 100644
--- a/recipes-devtools/gcc/libgcc-initial.inc
+++ b/recipes-devtools/gcc/libgcc-initial.inc
@@ -1,20 +1,58 @@
+#
+# Notes on the way the OE cross toolchain now works
+#
+# We need a libgcc to build glibc. Tranditionally we therefore built
+# a non-threaded and non-shared compiler (gcc-cross-initial), then use
+# that to build libgcc-initial which is used to build glibc which we can
+# then build gcc-cross and libgcc against.
+#
+# We were able to drop the glibc dependency from gcc-cross, with two tweaks:
+
+# a) specify the minimum glibc version to support in a configure option
+# b) create a dummy limits.h file so that later when glibc creates one,
+#    the headers structure has support for it. We can do this with a simple
+#    empty file
+#
+# Once gcc-cross is libc independent, we can use it to build both
+# libgcc-initial and then later libgcc.
+#
+# libgcc-initial is tricky as we need to imitate the non-threaded and
+# non-shared case. We can do that by hacking the threading mode back to
+# "single" even if gcc reports "posix" and disable libc presence for the
+# libgcc-intial build. We have to create the dummy limits.h to avoid
+# compiler errors from a missing header.
+#
+# glibc will fail to link with libgcc-initial due to a missing "exception
+# handler" capable libgcc (libgcc_eh.a). Since we know glibc doesn't need
+# any exception handler, we can safely symlink to libgcc.a.
+#
+
 require libgcc-common.inc
 
-DEPENDS = "virtual/${TARGET_PREFIX}gcc-initial"
+DEPENDS = "virtual/${TARGET_PREFIX}gcc"
 
 LICENSE = "GPL-3.0-with-GCC-exception"
 
-STAGINGCC = "gcc-cross-initial-${TARGET_ARCH}"
-STAGINGCC_class-nativesdk = "gcc-crosssdk-initial-${SDK_SYS}"
-PATH_prepend = "${STAGING_BINDIR_TOOLCHAIN}.${STAGINGCC}:"
-
 PACKAGES = ""
 
 EXTRA_OECONF += "--disable-shared"
 
-COMPILERINITIAL = "-initial"
-
 inherit nopackages
 
 # We really only want this built by things that need it, not any recrdeptask
 deltask do_build
+
+do_configure_prepend () {
+   install -d ${STAGING_INCDIR}
+   touch ${STAGING_INCDIR}/limits.h
+   sed -i -e 's#INHIBIT_LIBC_CFLAGS =.*#INHIBIT_LIBC_CFLAGS = -Dinhibit_libc#' ${B}/gcc/libgcc.mvars
+   sed -i -e 's#inhibit_libc = false#inhibit_libc = true#' ${B}/gcc/Makefile
+}
+
+do_configure_append () {
+   sed -i -e 's#thread_header = .*#thread_header = gthr-single.h#' ${B}/${BPN}/Makefile
+}
+
+do_install_append () {
+   ln -s libgcc.a ${D}${libdir}/${TARGET_SYS}/${BINV}/libgcc_eh.a
+}
\ No newline at end of file
diff --git a/recipes-devtools/gcc/libgcc.inc b/recipes-devtools/gcc/libgcc.inc
index 5f1dff6..e4e0c48 100644
--- a/recipes-devtools/gcc/libgcc.inc
+++ b/recipes-devtools/gcc/libgcc.inc
@@ -1,6 +1,6 @@
 require libgcc-common.inc
 
-DEPENDS = "virtual/${TARGET_PREFIX}gcc virtual/${TARGET_PREFIX}g++"
+DEPENDS = "virtual/${TARGET_PREFIX}gcc virtual/${TARGET_PREFIX}g++ virtual/${MLPREFIX}libc"
 
 do_install_append_class-target () {
    if [ "${TCLIBC}" != "glibc" ]; then

次の2つの修正を参考にした。

https://git.yoctoproject.org/cgit/cgit.cgi/poky/commit/meta/recipes-devtools/gcc?id=0afd3ac3ada35dd986aaf3be41d7177dc6b71ade https://git.yoctoproject.org/cgit/cgit.cgi/poky/commit/meta/recipes-devtools/gcc?id=1867965acd5291725069346eda9b239e60af2694

libxcryptのエラー回避

missing-attributesのオプションが原因でエラーになるのでbbappendを追加して回避する。

$ recipetool newappend -e ../layers/meta-local libxcrypt

このコマンドでエディタが起動するので次の内容を記述する。

TARGET_CPPFLAGS_remove = "-Wno-error=missing-attributes"
CPPFLAGS_remove_class-nativesdk = " -Wno-error=missing-attributes"

local.confの修正

色々と注意する点がある。

MACHINEの設定

MACHINE = "jetson-nano"

NVIDIA_DEVNET_MIRRORの設定

sdkmanagerがダウンロードしたファイルを格納しているディレクトリをNVIDIA_DEVNET_MIRRORで指定する必要がある。 筆者の環境では~/Downloads/nvidia/sdkm_downloadsになっていた。

NVIDIA_DEVNET_MIRROR = "file://${HOME}/Downloads/nvidia/sdkm_downloads"

gcc7を選択

CUDA10ではgccのバージョンが7で固定されているらしいのでGCCVERSION = '7.%'が必要。

GCCVERSION = "7.%"

DEBUG_PREFIX_MAPの変更

gcc7を使用する場合EXTRA_OECONF変数の中にmacro-prefix-mapがあると、libgccのdo_configureでエラーがになるため回避。

DEBUG_PREFIX_MAP = " -fdebug-prefix-map=${WORKDIR}=/usr/src/debug/${PN}/${EXTENDPE}${PV}-${PR} \
                     -fdebug-prefix-map=${STAGING_DIR_HOST}= \
                     -fdebug-prefix-map=${STAGING_DIR_NATIVE}= \
"

パッケージシステムの変更

デフォルトではrpmを使用するようになっているが、NVIDIAが提供するプロプライエタリなパッケージがdeb形式なので、 PACKAGE_CLASSESを変更する。

PACKAGE_CLASSES = "package_deb"

SDカードイメージ出力の設定

SDカードに直接ddで書き込めるイメージを生成するために次の内容を追加する。

IMAGE_CLASSES += "image_types_tegra"
IMAGE_FSTYPES = "tegraflash"

SDカードイメージのサイズ変更(オプション)

これはやらなくてもいいが、デフォルトでは16Gのイメージが生成される。

容量が大きめのSDカードを用意する必要があること、書き込みに時間がかかることから、 OSを頻繁に作り直す場合は不便となる。

TEGRAFLASH_SDCARD_SIZEで変更できる。

TEGRAFLASH_SDCARD_SIZE = "3G"

数字の部分は整数のみ。3.5Gなどの表記はできないのでそのようなサイズを指定したい場合は3500Mなどとする。

cuda関連パッケージ

cuda関連のパッケージを追加する。

# cuda
IMAGE_INSTALL_append = " \
             cuda-toolkit \
             cudnn \
             tegra-tools \
             opencv \
"

サンプルパッケージ

サンプルプログラムを収録したパッケージを追加する。

# samples
IMAGE_INSTALL_append = " \
             opencv-samples \
             cudnn-samples \
             cuda-samples \
             libvisionworks-sfm-samples \
             libvisionworks-tracking \
             tensorrt-samples \
"

イメージのビルド

最小構成のビルド。

$ bitbake core-image-minimal

この他にcore-image-satocore-image-westonがビルドできることを確認した。

SDカードの作成

ddコマンドでsdcardイメージを書き込む。

$ sudo dd if=./tmp/deploy/core-image-weston-jetson-nano.sdcard of=/dev/sdX bs=100M

/dev/sdXは環境に応じてsdbやsdcなどに適宜変更する。

SDKの作成

次のコマンドでSDKを作成する。今回はcore-image-westonをベースにSDKを作成した。

$ bitbake core-image-weston -c populate_sdk

下記のようなWARNINGが出るが、SDK自体は作成された。

The following packages have unmet dependencies:
 apt-dev : Depends: apt (= 1.2.24-r0) but it is not going to be installed
           Recommends: bash-dev
           Recommends: libcurl-dev but it is not installable
           Recommends: liblzma-dev but it is not installable
           Recommends: shadow-sysroot-dev but it is not installable
 cogl-1.0-dev : Depends: cogl-1.0 (= 1.22.2-r0)
                Recommends: libcogl-dev but it is not installable
                Recommends: libcogl-gles2-dev but it is not installable
                Recommends: libcogl-pango-dev but it is not installable
                Recommends: libcogl-path-dev but it is not installable
 dpkg-dev : Depends: dpkg (= 1.19.4-r0) but it is not going to be installed
            Recommends: dpkg-start-stop-dev but it is not installable
            Recommends: libbz2-dev but it is not installable
            Recommends: liblzma-dev but it is not installable
            Recommends: perl-dev
            Recommends: perl-module-carp-dev but it is not installable
            Recommends: perl-module-constant-dev but it is not installable
            Recommends: perl-module-cwd-dev but it is not installable
            Recommends: perl-module-digest-dev but it is not installable
            Recommends: perl-module-digest-md5-dev but it is not installable
            Recommends: perl-module-errno-dev but it is not installable
            Recommends: perl-module-exporter-dev but it is not installable
            Recommends: perl-module-fcntl-dev but it is not installable
            Recommends: perl-module-feature-dev but it is not installable
            Recommends: perl-module-file-basename-dev but it is not installable
            Recommends: perl-module-file-compare-dev but it is not installable
            Recommends: perl-module-file-copy-dev but it is not installable
            Recommends: perl-module-file-find-dev but it is not installable
            Recommends: perl-module-file-path-dev but it is not installable
            Recommends: perl-module-file-spec-dev but it is not installable
            Recommends: perl-module-file-temp-dev but it is not installable
            Recommends: perl-module-filehandle-dev but it is not installable
            Recommends: perl-module-io-dev but it is not installable
            Recommends: perl-module-io-handle-dev but it is not installable
            Recommends: perl-module-io-seekable-dev but it is not installable
            Recommends: perl-module-list-util-dev but it is not installable
            Recommends: perl-module-overload-dev but it is not installable
            Recommends: perl-module-parent-dev but it is not installable
            Recommends: perl-module-posix-dev but it is not installable
            Recommends: perl-module-scalar-util-dev but it is not installable
            Recommends: perl-module-selectsaver-dev but it is not installable
            Recommends: perl-module-storable-dev but it is not installable
            Recommends: perl-module-symbol-dev but it is not installable
            Recommends: perl-module-term-ansicolor-dev but it is not installable
            Recommends: perl-module-tie-handle-dev but it is not installable
            Recommends: perl-module-tie-hash-dev but it is not installable
            Recommends: perl-module-time-hires-dev but it is not installable
            Recommends: perl-module-time-piece-dev but it is not installable
            Recommends: perl-module-xsloader-dev but it is not installable
            Recommends: update-alternatives-opkg-dev but it is not installable
 target-sdk-provides-dummy-dev : Depends: target-sdk-provides-dummy (= 1.0-r0) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.

まとめ

gccバージョンやコンパイルオプションなど意外と罠が多かった。 結局、jetbackのインストールなどが必要となるので、わざわざyoctoでやる必要は薄い気がした。

ツールチェインを含め、より自由度の高いOSを作成できるのはやはり利点か。