みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

ZephyrをSTM32F4Discoveryで試す

はじめに

Zephyrの勉強のためにとりあえず動かしてみる。

準備

いろいろ事前にインストールが必要なのでやっておく。

west

直接gitでソースを取得するのではなくwestというツールを使用することが推奨されているようだ。

pip3が必要なのでインストールする。 OSの環境を汚したくないのでuserインストールする。

$ sudo apt install python3-pip
$ pip3 install --upgrade pip
$ sudo apt purge python3-pip

westのインストール。

$ pip3 install --user west

ninja

westは内部からninjaを叩くようなのでninjaをインストールする。

$ sudo apt install ninja-build

CMakeの更新

Ubuntu 18.04のcmakeでは古いため新しいcmakeをインストール

$ wget https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4.tar.gz
$ tar xvf ./cmake-3.14.4.tar.gz 
$ cd cmake-3.14.4
$ ./configure
$ make -j $(nproc)
$ sudo make install

Zephyr SDK

SDKインストーラをダウンロードする。

$ cd /tmp
$ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.10.0/zephyr-sdk-0.10.0-setup.run

インストーラを実行する。

$ sh zephyr-sdk-0.10.0-setup.run
Verifying archive integrity... All good.
Uncompressing SDK for Zephyr  100%  
Enter target directory for SDK (default: /opt/zephyr-sdk/): ~/bin/zephyr-sdk

デフォルトでは/opt/zephyr-sdk/にインストールされる。 インストール先はどこでも良いが、ここでは~/bin/zephyr-sdkにインストールした。

環境変数を設定する必要がある。

次の内容を~/.bashrcに追加する。

export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=${HOME}/bin/zephyr-sdk

.bashrcを読み込む。

$ source ~/.bashrc

Zephyrのソースを取得

westでソースを取得する。

$ west init zephyrproject
$ cd zephyrproject
$ west update

依存パッケージのインストール

依存するpythonパッケージをインストールする。

$ pip3 install --user -r zephyr/scripts/requirements.txt

westでビルドする

先程のzephyrprojectディレクトリに戻り次のコマンドを実行する。

$ cd zephyr
$ source zephyr-env.sh

対応ボードを調べる

次のコマンドでSTM32F4Discoveryを探す。

$ west boards | grep stm32f4
stm32f411e_disco
stm32f412g_disco
stm32f429i_disc1
stm32f469i_disco
stm32f4_disco

stm32f4_discoが見つかった。

Hello worldをビルドする

手始めに世界に挨拶してみる。

$ west build -b stm32f4_disco samples/hello_world

westで書き込む

次のコマンドで書き込みからボードのリセットまでやってくれる。

$ west flash

次のように接続し、minicomなどのターミナルを起動しておく

USB Cable STM32
TXD PA3
RXD PA2
GND GND

次のように表示されればOK

***** Booting Zephyr OS zephyr-v1.14.0-1091-ge58df2c34eab *****
Hello World! stm32f4_disco

まとめ

だいたい全部westで片付く。

platformioみたい。最近はこういうのが流行りなのか。

(おまけ)qemuで実行

実機なしで手軽に試すにはqemuを使用できる。

$ west build -b qemu_x86 samples/hello_world
$ west build -t run
...(snip)...
SeaBIOS (version rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org)
Booting from ROM..***** Booting Zephyr OS zephyr-v1.14.0-1091-ge58df2c34eab *****
Hello World! qemu_x86

Ctrl+a, xで終了。

yoctoでもRust

はじめに

最近流行りのRust。meta-rustを使えばyocto環境でもRustアプリケーションを使えるようにできる。

meta-rustネタとしてはこちらに先を越されたが、試したブランチがsumo、rockoと古めなのと観点がRust開発者よりなので、本記事ではすこしyocto的に見てみる。

ちなみに筆者はRust初心者未満なのでRustの解説はリンク先の方を参照してください。

ターゲット環境はラズベリーパイ3。

環境構築

いつもの。

ソース取得

ラズベリーパイ環境のビルドのためのレイヤをダウンロードする。

$ mkdir -p rpi-thud/layers
$ cd rpi-thud/layers
$ git clone git://git.yoctoproject.org/poky.git -b thud
$ git clone git://git.yoctoproject.org/meta-raspberrypi -b thud
$ git clone git://git.openembedded.org/meta-openembedded -b thud

rustのパッケージを含んでいるmeta-rustはsumo(2.5)以降ブランチを切っていない。

masterブランチのLAYERSERIES_COMPATを確認すると次のようになっているので、thudwarriorを使用したい場合はmasterブランチを使用することになる。

LAYERSERIES_COMPAT_rust-layer = "rocko sumo thud warrior"

次のコマンドでソースを取得する。

$ git clone https://github.com/meta-rust/meta-rust.git
$ cd ../

環境変数の設定

環境変数の読み込みとビルドディレクトリを作成する。

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

コマンド実行後はビルドディレクトリに自動的に移動される。 ここではbuild_rustとしている。

レイヤの追加

ビルド対象にレイヤを追加する。 依存関係があるので追加する順番は変更しないこと。

$ bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-python
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-networking
$ bitbake-layers add-layer ../layers/meta-raspberrypi
$ bitbake-layers add-layer ../layers/meta-rust

local.confの修正

MACHINEをラズベリーパイ3にする。

INITはsystemdで。あとは細かい設定。

MACHINE = "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES_append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

IMAGE_INSTALL_append = " rust-hello-world"

ビルド

Linuxイメージを生成する。

$ bitbake core-image-base

Rustバージョンの確認

Rustのバージョンを確認。

$ find ./tmp/work -maxdepth 2 -and -type d -and -name 'rust*' | xargs ls
./tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/rust-hello-world:
git-r0

./tmp/work/x86_64-linux/rust-cross-arm:
1.33.0-r0

./tmp/work/x86_64-linux/rust-llvm-native:
1.33.0-r0

./tmp/work/x86_64-linux/rust-native:
1.33.0-r0

最新のstableが1.34.1みたいなので若干古い?。ここらへんは疎いので。

SDの作成

ddコマンドでマイクロSDにイメージを書き込む

$ sudo dd if=tmp/deploy/images/raspberrypi3/core-image-base-raspberrypi3.rpi-sdimg of=/dev/sdX bs=100M

/dev/sdXはマイクロSDのデバイスなので適宜sdbsdcなどに書き換えること。

ddの代わりにEtcherを使用することもできる。

実行確認

作成したマイクロSDをラズベリーパイ3に挿入し電源をいれ、rust-hello-worldを実行してみる。

# rust-hello-world
Hello, world!

問題なく動作した。

開発環境の確認

yoctoではbitbakeで作成したLinuxイメージ上で動くプログラムを開発するためのクロスコンパイル環境を作成することができる。 これは、作成したLinux上にインストールされているライブラリを使用するために必要な情報が全て含まれている。

基本的にはGCCC/C++向け環境となっているので、Rustの開発環境はどのようになっているか確認する。

まず、次のコマンドでSDKを作成する。

$ bitbake core-image-base -c populate_sdk

tmp/deploy/sdkインストーラスクリプトが作成されるので、次のコマンドを実行しSDKをインストールする。

$ tmp/deploy/sdk/poky-glibc-x86_64-core-image-base-cortexa7t2hf-neon-vfpv4-toolchain-2.6.2.sh

インストール先は自由に設定できるが、デフォルトでは/opt/poky/2.6.2にインストールされる。

SDKを使用できるようにするために環境変数を読み込む。

$ source /opt/poky/2.6.2/environment-setup-cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi

環境変数CCの値が次のようになっていればSDKが使用できる。

$ echo $CC
arm-poky-linux-gnueabi-gcc -march=armv7ve -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/rust/2.6.2/sysroots/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi

最低でもrustcが入っていなければRust向けの開発環境とは言えないので探してみる。 SDKでインストールされたファイルは/opt/poky/2.6.2/sysroot以下にあるためそこの下をfindする。

$ cd /opt/poky/2.6.2/sysroot
$ sudo find -iname 'rustc'

見つからない。

*rust**cargo*などで検索してもRustの開発に必要なコマンドやファイルが見つからないことがわかる。

まとめ

低レイヤ強くなりたい組込み屋さんのブログで次のように言っている。

どうしてもYoctoでビルドしてdistributionとして配布したい、という状況でなければ、わざわざYoctoでビルドするうまみはなさそうです。

こちらは開発環境の古さなどの観点からの言葉なので若干言いたいポイントは異なるのだろうとも思うが、 Rustでの開発の観点で言えば全面的に同意できる。

ただ、SDKにRustの開発環境が含まれないことからmeta-rustではyoctoで作成したLinuxの上で開発・デバッグを行うことは目的に含まれていない。そのため「Yoctoでの配布目的以外ではうまみがない」のではなく「使えない」で良いと思う。

個人的にyoctoのうまみは一度作った設定済みのLinuxイメージを量産できるところにあると思っている。meta-rustもRustで書かれたアプリケーションをyoctoのイメージに取り込むのがこれを使用する目的であって、この観点ではmeta-rustのスタンスも間違ってはいないし存在意義もあると思っている。

yocto環境でのRustの開発環境を期待しているとハズレ感はあると思う。

異論は認める!

参考

tinygoでnRF52840-DK(PCA10056)を動かす

はじめに

nRF52840 Development Kitを入手したのでtinygoで動かしてみる。

tinygoのインストール

Ubuntu 18.04にtinygo-0.5.0をインストールするの手順でインストール済みであることを想定。

ツールのダウンロード

nrfjprogコマンドが必要なので、下記からコマンドラインツールをダウンロードする。

https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF5-Command-Line-Tools/Download#infotabs

tarのアーカイブなので展開する。

$ tar xvf nRF-Command-Line-Tools_9_8_1_Linux-x86_64.tar
$ mv ./nrfjprog ~/bin/
$ mv ./mergehex ~/bin/
$ cat << 'EOF' >> ~/.bashrc
export PATH=$PATH:${HOME}/bin/nrfjprog:${HOME}/bin/mergehex
EOF
$ source ~/.bashrc

J-Link Softwareのインストール

当然のことながらnrfjprogはj-Linkのライブラリを必要とするので、インストールしていない場合はこれをインストールする。

SEGGERのダウンロードページからダウンロードする。

ダウンロードが完了したら次のコマンドでインストールする。

$ sudo gdebi JLink_Linux_V644g_x86_64.deb 

サンプルプログラムの書き込み

サンプルプログラムをビルドして書き込む。

バイスターゲットの生成

これは最初にやっておく必要がある。

$ cd $GOPATH/src/github.com/tinygo-org/tinygo
$ make gen-device

プログラムの書き込み

次のコマンドでビルドして書き込む。ここではexamples/Blinky1を書き込む。

ターゲット指定はpca10056

$ tinygo flash -target=pca10056 examples/blinky1

LED1がチカチカしたら成功。

まとめ

SEGGER J-LinkやnRF Command Line Toolは必要となるが、それを入れてしまえば問題なく動作する。

tinygoの手軽さは素敵。

Ubuntu 18.04にtinygo-0.5.0をインストールする

はじめに

つい先日、Ubuntu 18.04でtinygoをインストールする手順を書いたが、 この短期間でLLVMが8になったようで、前回の記事の内容はほぼ使えなくなったので書き直す。

ここの手順が更新されており、 Ubuntuではビルド済みのdebパッケージが提供されているので 簡単に導入したい場合はこれを使用すると良い。

ここでは前回と同様にソースからインストールする。

Requirement

あとは、ターゲットのツールチェイン。

  • ARM Cortex-M
  • AVR(Arduino)
  • WebAssembly

詳細は先述のリンク元を参照。

筆者環境はarm-none-eabiがインストール済み。

goのインストール

いろいろ手段があるが、インストーラによるインストールが一番便利だった。

$ sudo apt install wget git
$ wget -q https://storage.googleapis.com/golang/getgo/installer_linux
$ chmod +x installer_linux
$ ./installer_linux -version 1.11.7

今回もgoのバージョンは1.11.7とした。

GOPATHの設定

.bashrcに以下の内容を追加。

export PATH=$PATH:/home/mickey/.go/bin
export GOPATH=/home/mickey/go
export PATH=$PATH:/home/mickey/go/bin

llvm-8のインストール

ここを参考にした。

sources.listの追加

前回はllvm 7.0.1をインストールするために、/etc/apt/sources.list.d/llvm.listを次の内容で作成したため、 llvm8を入れたい今回は不要かもしれないが一応やっておく。

# i386 not available
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# 7
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main
# 8
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main

鍵を追加。

$ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
$ sudo apt update

パッケージのインストール

Install (stable branch)に書いてあったものをだいたい入れる。

$ sudo apt install clang-8 lldb-8 lld-8
$ sudo apt install libllvm-8-ocaml-dev libllvm8 llvm-8 llvm-8-dev llvm-8-doc llvm-8-examples llvm-8-runtime
$ sudo apt install  clang-8 clang-tools-8 clang-8-doc libclang-common-8-dev libclang-8-dev libclang1-8 clang-format-8 python-clang-8
$ sudo apt install libfuzzer-8-dev
$ sudo apt install lldb-8 lld-8 libc++-8-dev libc++abi-8-dev

tinygoのインストール

go getを実行する。今回はこれで問題なくインストールできる。

$ go get -u github.com/tinygo-org/tinygo

まとめ

最新版(0.5.0)ではdebパッケージが用意されたので、ソースからインストールしなくても簡単にインストールができる。

ソースコードからインストールする場合でも前回あったような、過渡期特有のワークアラウンドは必要なくなっている。

NuttXでmbedTLSを動かす

はじめに

NuttXでmbed TLSを動かす。

3年ほど前にMarceloさんが一度移植したらしいので、ここを参考にする。

ただし情報が古くその間にNuttXも新しくなっているのでこのままではうまく行かない。

今回使用するターゲットはSTM32F4Discovery。

NuttX

まずはNuttXのソースを取ってくる。

ディレクトリ構成

全体のディレクトリ構成が次のようになるようにする。

.
├── apps
├── mbedtls
└── nuttx

ソースの取得

$ git clone https://bitbucket.org/nuttx/nuttx.git
$ git clone https://bitbucket.org/nuttx/apps.git

mbedtls

ソースの取得

mbed TLSgithubでソースも公開しているのでこれを使う。

$ git clone https://github.com/ARMmbed/mbedtls.git

ファイルのコピー

mbed TLSのソースをNuttXのソースツリーに組み込む。

mbed TLSのツリー

mbed TLSのソースツリーは次のようになっている。

ここでは使用する分を抜粋する。

mbedtls
├── configs      // コンフィグヘッダ
├── include
│   └── mbedtls // ヘッダファイル
└── library      // ソースファイル

NuttX側

NuttXには次のようになるようにする。

nuttx
└── mbedtls           // ソースファイル
     └── mbedtls      // ヘッダファイル
          └── configs // コンフィグヘッダ

出力ディレクトリの作成

mbed TLSのソースディレクトリに移動し、出力先ディレクトリの作成。

$ cd mbedtls
$ mkdir ../nuttx/mbedtls

ソースファイルのコピー

インクルードファイルのコピー

$ cp -ra ./include/mbedtls ../nuttx/mbedtls/

コンフィグヘッダのコピー

configs以下のファイルから参照されることがあるためcheck_config.hconfigsにコピーする。 また、mbedtls/mbedtls/config.hはKconfigでの設定を反映できるように修正するため、もとのファイルをmbedtls/mbedtls/configs/config-default.hとしてコピーしておく。

$ cp -ra ./configs ../nuttx/mbedtls/mbedtls/
$ cp ./include/mbedtls/config.h ../nuttx/mbedtls/mbedtls/configs/config-default.h
$ cp ./include/mbedtls/check_config.h ../nuttx/mbedtls/mbedtls/configs/

ソースファイルのコピー

$ cp -ra ./library/*.c ../nuttx/mbedtls/

ライセンスとREADMEのコピー

$ cp -a ./LICENSE ../nuttx/mbedtls
$ cp -a ./apache-2.0.txt ../nuttx/mbedtls
$ cp -a ./README.md ../nuttx/mbedtls

ビルドに必要なファイルの作成

nuttx以下に次のファイルを作成する。

  • mbedtls/Kconfig
  • mbedtls/Makefile
  • mbedtls/mbedtls/config.h

Kconfig

mbedtls/Kconfigを次の内容で作成する。

config MBED_TLS_LIB
    bool "mbed TLS Support"
    default n
    ---help---
        Enable or disable mbed TLS support

if MBED_TLS_LIB

choice
    prompt "mbed Configuration Profile"
    default MBED_PROFILE_DEFAULT

config MBED_PROFILE_SUITE_B
    bool "Suite B"

config MBED_PROFILE_CCM_PSK_TLS_1_2
    bool "CCM, PSK and TLS 1.2"

config MBED_PROFILE_MINI_TLS_1_1
    bool "Mini TLS 1.1"

config MBED_PROFILE_THREAD
    bool "Thread"

config MBED_PROFILE_NOENTROPY
    bool "No entropy"

config MBED_PROFILE_DEFAULT
    bool "Default configuration"

endchoice

endif # MBED_TLS_LIB

Makefile

mbedtls/Makefileを次の内容で作成する。

-include $(TOPDIR)/Make.defs

ASRCS =
CSRCS =

ifeq ($(CONFIG_MBED_TLS_LIB),y)

CSRCS += aes.c          asn1parse.c asn1write.c             base64.c        \
        bignum.c        blowfish.c              camellia.c      \
        ccm.c           cipher.c                cipher_wrap.c   \
        ctr_drbg.c      des.c                   dhm.c           \
        ecdh.c          ecdsa.c                 ecjpake.c       \
        ecp.c           ecp_curves.c            entropy.c       \
        entropy_poll.c  error.c                 gcm.c           \
        havege.c        hmac_drbg.c             md.c            \
        md2.c           md4.c                   md5.c           \
        md_wrap.c       memory_buffer_alloc.c   oid.c           \
        padlock.c       pem.c                   pk.c            \
        pk_wrap.c       pkcs12.c                pkcs5.c         \
        pkparse.c       pkwrite.c               platform.c      \
        ripemd160.c     rsa.c                   sha1.c          \
        sha256.c        sha512.c                threading.c     \
        timing.c        version_features.c      version.c       \
        xtea.c          x509_create.c           x509_crl.c      \
        x509_crt.c      x509_csr.c              x509write_crt.c \
        x509write_csr.c ssl_ciphersuites.c      ssl_cli.c       \
        ssl_cookie.c    ssl_srv.c               ssl_ticket.c    \
        ssl_tls.c       platform_util.c


endif # CONFIG_MBED_TLS_LIB

AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))

SRCS = $(ASRCS) $(CSRCS)
OBJS = $(AOBJS) $(COBJS)

BIN = libmbedtls$(LIBEXT)

all: $(BIN)
.PHONY: depend clean distclean

$(AOBJS): %$(OBJEXT): %.S
    $(call ASSEMBLE, $<, $@)

$(COBJS): %$(OBJEXT): %.c
    $(call COMPILE, $<, $@)

$(BIN): $(OBJS)
    $(call ARCHIVE, $@, $(OBJS))

.depend: Makefile $(SRCS)
ifeq ($(CONFIG_MBED_TLS_LIB),y)
    $(Q) $(MKDEP) --dep-path . "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
endif
    $(Q) touch $@

depend: .depend

clean:
    $(call DELFILE, $(BIN))
    $(call CLEAN)

distclean: clean
    $(call DELFILE, Make.dep)
    $(call DELFILE, .depend)

-include Make.dep

config.h

Kconfigの内容を反映できるようにするために、既存のmbedtls/mbedtls/config.hを破棄し、次の内容で作成する。

#include <nuttx/config.h>

#if defined(CONFIG_MBED_PROFILE_SUITE_B)
#include "mbedtls/configs/config-suite-b.h"
#elif defined(CONFIG_MBED_PROFILE_CCM_PSK_TLS_1_2)
#include "mbedtls/configs/config-ccm-psk-tls1_2.h"
#elif defined(CONFIG_MBED_PROFILE_MINI_TLS_1_1)
#include "mbedtls/configs/config-mini-tls1_1.h"
#elif defined(CONFIG_MBED_PROFILE_THREAD)
#include "mbedtls/configs/config-thread.h"
#elif defined(CONFIG_MBED_PROFILE_NOENTROPY)
#include "mbedtls/configs/config-no-entropy.h"
#elif defined(CONFIG_MBED_PROFILE_DEFAULT)
#include "mbedtls/configs/config-default.h"
#else
#error "mbed TLS configuration file was not set"
#endif

config-default.h

先程コピーしたmbedtls/mbedtls/configs/config-default.hは、このままではビルドに失敗するため、次の2つのコンフィグを変更しておく。

diff --git a/mbedtls/mbedtls/configs/config-default.h b/mbedtls/mbedtls/configs/config-default.h
index fd91d7074c..878f4e67cf 100644
--- a/mbedtls/mbedtls/configs/config-default.h
+++ b/mbedtls/mbedtls/configs/config-default.h
@@ -1149,7 +1149,7 @@
  *
  * Uncomment this macro to disable the built-in platform entropy functions.
  */
-//#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_NO_PLATFORM_ENTROPY
 
 /**
  * \def MBEDTLS_ENTROPY_FORCE_SHA256
@@ -3018,7 +3018,7 @@
  *
  * This module is used by the HAVEGE random number generator.
  */
-#define MBEDTLS_TIMING_C
+//#define MBEDTLS_TIMING_C
 
 /**
  * \def MBEDTLS_VERSION_C

既存ファイルの修正

ビルド対象に含めるためにNuttX側のファイルを修正する。

今回は次のファイルを修正する。

  • Kconfig
  • tools/Directories.mk
  • tools/FlatLibs.mk
  • tools/KernelLibs.mk
  • tools/LibTargets.mk
  • tools/ProtectedLibs.mk

Kconfig

NuttXのソースツリーのルートにあるKconfigを次のように修正する。

diff --git a/Kconfig b/Kconfig
index dbcf9ee9ff..1ea6383698 100644
--- a/Kconfig
+++ b/Kconfig
@@ -1698,6 +1698,10 @@ source libs/libxx/Kconfig
 source libs/libdsp/Kconfig
 endmenu
 
+menu "mbed TLS Support"
+source mbedtls/Kconfig
+endmenu
+
 menu "Application Configuration"
 source "$APPSDIR/Kconfig"
 endmenu

Directories.mk

tools/Directories.mkを次のように修正する。

diff --git a/tools/Directories.mk b/tools/Directories.mk
index 7c17510789..8b66691dfa 100644
--- a/tools/Directories.mk
+++ b/tools/Directories.mk
@@ -183,3 +183,8 @@ ifeq ($(CONFIG_CRYPTO),y)
 KERNDEPDIRS += crypto
 endif
 CLEANDIRS += crypto
+
+ifeq ($(CONFIG_MBED_TLS_LIB),y)
+KERNDEPDIRS += mbedtls
+endif
+CLEANDIRS += mbedtls

FlatLibs.mk

tools/FlatLibs.mkを次のように修正する。

diff --git a/tools/FlatLibs.mk b/tools/FlatLibs.mk
index 0ad2cc335b..fde3dd8c6e 100644
--- a/tools/FlatLibs.mk
+++ b/tools/FlatLibs.mk
@@ -93,6 +93,12 @@ ifeq ($(CONFIG_NET),y)
 NUTTXLIBS += staging$(DELIM)libnet$(LIBEXT)
 endif
 
+# Add libraries for mbed TLS
+
+ifeq ($(CONFIG_MBED_TLS_LIB),y)
+NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT)
+endif
+
 # Add libraries for Crypto API support
 
 ifeq ($(CONFIG_CRYPTO),y)

KernelLibs.mk

tools/KernelLibs.mkを次のように修正する。

diff --git a/tools/KernelLibs.mk b/tools/KernelLibs.mk
index f36d8d6ce5..1f14159d87 100644
--- a/tools/KernelLibs.mk
+++ b/tools/KernelLibs.mk
@@ -91,6 +91,12 @@ ifeq ($(CONFIG_CRYPTO),y)
 NUTTXLIBS += staging$(DELIM)libcrypto$(LIBEXT)
 endif
 
+# Add libraries for mbed TLS
+
+ifeq ($(CONFIG_MBED_TLS_LIB),y)
+NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT)
+endif
+
 # Add libraries for file system support
 
 NUTTXLIBS += staging$(DELIM)libfs$(LIBEXT) staging$(DELIM)libbinfmt$(LIBEXT)

LibTargets.mk

tools/LibTargets.mkを次のように修正する。

diff --git a/tools/LibTargets.mk b/tools/LibTargets.mk
index 188e4fb403..df5421ae89 100644
--- a/tools/LibTargets.mk
+++ b/tools/LibTargets.mk
@@ -94,6 +94,12 @@ crypto$(DELIM)libcrypto$(LIBEXT): context
 staging$(DELIM)libcrypto$(LIBEXT): crypto$(DELIM)libcrypto$(LIBEXT)
        $(Q) $(call INSTALL_LIB,$<,$@)
 
+mbedtls$(DELIM)libmbedtls$(LIBEXT): context
+       $(Q) $(MAKE) -C mbedtls TOPDIR="$(TOPDIR)" libmbedtls$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE)
+
+staging$(DELIM)libmbedtls$(LIBEXT): mbedtls$(DELIM)libmbedtls$(LIBEXT)
+       $(Q) $(call INSTALL_LIB,$<,$@)
+
 fs$(DELIM)libfs$(LIBEXT): context
        $(Q) $(MAKE) -C fs TOPDIR="$(TOPDIR)" libfs$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE)
 

インデントはスペースではなくタブであることに注意すること。

ProtectedLibs.mk

tools/ProtectedLibs.mkを次のように修正する。

diff --git a/tools/ProtectedLibs.mk b/tools/ProtectedLibs.mk
index 4bb3d19424..8ed6e3e461 100644
--- a/tools/ProtectedLibs.mk
+++ b/tools/ProtectedLibs.mk
@@ -98,6 +98,12 @@ ifeq ($(CONFIG_CRYPTO),y)
 NUTTXLIBS += staging$(DELIM)libcrypto$(LIBEXT)
 endif
 
+# Add libraries for mbed TLS
+
+ifeq ($(CONFIG_MBED_TLS_LIB),y)
+NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT)
+endif
+
 # Add libraries for file system support
 
 NUTTXLIBS += staging$(DELIM)libfs$(LIBEXT) staging$(DELIM)libbinfmt$(LIBEXT)

サンプルプログラム

簡単に動作を確認するためMD5を動かしてみる。

プログラムはtlssampleとする。

新規に作成するアプリケーションのために、次のファイルをapps以下に追加する。

  • external/tlssample/Kconfig
  • external/tlssample/Make.defs
  • external/tlssample/Makefile
  • external/tlssample/tlssample_main.c

ディレクトリ作成

次のコマンドでプログラムのためのディレクトリを作成する。

$ cd apps
$ mkdir -p external/tlssample
$ ln -s external/tlssample tlssample

appsから1つ下の階層のディレクトリにあるMakefileは自動的にビルド対象に追加されるため、 external/tlssampleへのシンボリックリンクを作成する。

Kconfig

external/tlssample/Kconfigを次の内容で作成する。

config EXTERNAL_TLSSAMPLE
    tristate "\"Tlssample\" example"
    default n
    ---help---
        Enable the \"Tlssample\" example

if EXTERNAL_TLSSAMPLE

config EXTERNAL_TLSSAMPLE_PROGNAME
    string "Program name"
    default "tlssample"
    depends on BUILD_LOADABLE
    ---help---
        This is the name of the program that will be use when the NSH ELF
        program is installed.

config EXTERNAL_TLSSAMPLE_PRIORITY
    int "Tlssample task priority"
    default 100

config EXTERNAL_TLSSAMPLE_STACKSIZE
    int "Tlssample stack size"
    default 2048

endif

Make.defs

external/tlssample/Make.defsを次の内容で作成する。

ifneq ($(CONFIG_EXTERNAL_TLSSAMPLE),)
CONFIGURED_APPS += tlssample
endif

Makefile

external/tlssample/Makefileを次の内容で作成する。

-include $(TOPDIR)/Make.defs

# Tlssample, World! built-in application info

CONFIG_EXTERNAL_TLSSAMPLE_PRIORITY ?= SCHED_PRIORITY_DEFAULT
CONFIG_EXTERNAL_TLSSAMPLE_STACKSIZE ?= 2048

APPNAME = tlssample

PRIORITY  = $(CONFIG_EXTERNAL_TLSSAMPLE_PRIORITY)
STACKSIZE = $(CONFIG_EXTERNAL_TLSSAMPLE_STACKSIZE)

# Tlssample, World! Example

ASRCS =
CSRCS =
MAINSRC = tlssample_main.c

CFLAGS += -I$(TOPDIR)/mbedtls

CONFIG_EXTERNAL_TLSSAMPLE_PROGNAME ?= tlssample$(EXEEXT)
PROGNAME = $(CONFIG_EXTERNAL_TLSSAMPLE_PROGNAME)

MODULE = CONFIG_EXTERNAL_TLSSAMPLE

include $(APPDIR)/Application.mk

tlssample_main.c

external/tlssample/tlssample_main.cを次の内容で作成する。

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <stdio.h>
#include "mbedtls/md5.h"

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * tlssample_main
 ****************************************************************************/

#if defined(BUILD_MODULE)
int main(int argc, FAR char *argv[])
#else
int tlssample_main(int argc, char *argv[])
#endif
{
  unsigned char buf[32] = "hello world";
  unsigned char out[16];
  int i = 0;
  int n;


  n = strlen(buf);
  printf("source = %s, %d\n", buf, n);
  mbedtls_md5_ret(buf, n, out);
  printf("-----\n");
  for (i = 0; i < 16; ++i) {
    printf("%02x ", out[i]);
  }

  printf("\n-----\n");
  mbedtls_md5_self_test(1);

  return 0;
}

ビルド

ここまででmbedtlsを含んだNuttXのビルドは可能となった。

STM32F4Discoveryのusbnsh環境向けにビルドしてみる。

$ tools/configure.sh configs/stm32f4discovery/usbnsh -l
$ make menuconfig

mbed TLSの有効化

次のような感じで設定する。

f:id:mickey_happygolucky:20190423230242p:plain

f:id:mickey_happygolucky:20190423230302p:plain

f:id:mickey_happygolucky:20190423230314p:plain

現時点ではDefault configurationNo entropy以外では次のチェックで引っかかる。

#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)

#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
    !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
    !defined(__HAIKU__)
#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h"
#endif

Linnux、Mac OSQNXHAIKUWindows以外のOSでは機能が足りないと判断されるためエラーとなる。

今回は試していないが、NuttXはPOSIX LikeなOSなのでここのチェックを騙して、 ちょっと修正すれば他のコンフィグレーションでも動作するようになると思われる。

サンプルプログラムの有効化

次のような感じで設定する。

f:id:mickey_happygolucky:20190423230327p:plain

f:id:mickey_happygolucky:20190423230402p:plain

実行

プログラムの書き込み

st-flashでnuttx.binを書き込む。

$ st-flash write nuttx.bin 0x8000000

プログラムの実行

STM32F4DiscoveryとPCをマイクロUSBケーブルで接続しボードをリセットすると、PC側に/dev/ttyACM0が見えるようになる。

このデバイスをminicomなどで開いてnshにアクセスする。

nsh> tlssample
source = hello world, 11
-----
5e b6 3b bb e0 1e ee d0 93 cb 22 bb 8f 5a cd c3 
-----
  MD5 test #1: passed
  MD5 test #2: passed
  MD5 test #3: passed
  MD5 test #4: passed
  MD5 test #5: passed
  MD5 test #6: passed
  MD5 test #7: passed

nsh> 

hello worldMD55e b6 3b bb e0 1e ee d0 93 cb 22 bb 8f 5a cd c3となる。

確認方法

Linuxで次のコマンドを実行し同じになることを確認する。

$ echo -n "hello world" | md5sum
5eb63bbbe01eeed093cb22bb8f5acdc3

同じ結果になった。

まとめ

既存のライブラリをNuttXのソースツリーに持っていきビルドする方法を確認した。 サンプルプログラムを作成し、きちんと機能することも確認できた。

以前にmbed TLSを移植したMarceloさんは各コンフィグをそれぞれ選択できるようにカスタムメニューを作成しているが、 今回は省略した。

今のところNuttXは割と素直に動いてくれていて、 Linux経験者がMCUに世界に飛び込むにはかなりとっつきやすい印象。

ただ、移植にはライブラリが求めている機能をNuttXが持っているかどうかなど条件があり、 これを満たすようにするためには、いろいろと修正しなければならない場合がある。

NuttXでOSSのライブラリを使用するには、事前にそのライブラリの移植性やその難易度を予め調査するのが良さそう。 以前にNuttXに移植された実績があるかどうかなども、結構重要なポイントとなる。

規模の大きいものや複雑なものを使用したい場合は注意が必要。

ただ、NuttXは楽しい。

npm install -g mermaid-filterでエラー

はじめに

pandocの環境を再構築するために、mermaid-filterをインストールしようとしたら次のエラーが出てハマった。

$ sudo npm install -g mermaid-filter
/usr/local/bin/mermaid-filter -> /usr/local/lib/node_modules/mermaid-filter/index.js

> puppeteer@1.14.0 install /usr/local/lib/node_modules/mermaid-filter/node_modules/puppeteer
> node install.js

ERROR: Failed to download Chromium r641577! Set "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" env variable to skip download.
{ Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/mermaid-filter/node_modules/puppeteer/.local-chromium'
  -- ASYNC --
    at BrowserFetcher.<anonymous> (/usr/local/lib/node_modules/mermaid-filter/node_modules/puppeteer/lib/helper.js:110:27)
    at Object.<anonymous> (/usr/local/lib/node_modules/mermaid-filter/node_modules/puppeteer/install.js:64:16)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
  errno: -13,
  code: 'EACCES',
  syscall: 'mkdir',
  path:
   '/usr/local/lib/node_modules/mermaid-filter/node_modules/puppeteer/.local-chromium' }
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! puppeteer@1.14.0 install: `node install.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the puppeteer@1.14.0 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

解決方法

どうもchromiumブラウザをダンロードしてこようとしているようだが本来は特に必要ない。 ダンロードをスキップする場合は次の環境変数を設定しろというメッセージが出た。

Set "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" env variable to skip download.

いろいろ調べて次のようにしたが状況は変わらない。

$ npm config set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD TRUE -g

ここの情報をもとに次のようにしたところ、エラーが回避できた。

$ sudo npm config set puppeteer_skip_chromium_download true -g

小文字なんだってさ。

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を作成できるのはやはり利点か。