みつきんのメモ

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

STM32F4Discovery NuttXでC++(libc++)をためす

はじめに

make menuconfigで見てみると、NuttXでもlibc++uClibc++などが使えるようになっているらしい。 ただ、ライブラリのソースはカーネルやアプリからは分離されているようで、別途取得する必要がある。

具体的なやり方はAlan C. Assisさんが紹介してくれているのでなぞってみる。

コミットログを見るにこの人はコアなコントリビュータっぽい。

ソースの取得

NuttX

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

Apps

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

libc++

$ git clone https://bitbucket.org/acassis/libcxx

libc++のインストール

libc++のソースをNuttXのソースツリーにインストールする。

$ cd libcxx
$ ./install.sh ../nuttx
Installing LLVM/libcxx in the NuttX source tree
Installation suceeded

./install.shの中身

基本的にはNuttXのソースツリーの構造をチェックして、ファイルをコピーしているだけっぽい。 ここではチェック部分を省略したが、実際はかなり細かくチェックしている。

#!/bin/bash

usage="USAGE: $0 <full path to the NuttX directory>"

# Get the single, required command line argument

nuttx_path=$1
if [ -z "${nuttx_path}" ]; then
  echo "ERROR: Missing path to the NuttX directory"
  echo $usage
  exit 1
fi

# Lots of sanity checking so that we do not do anything too stupid

if [ ! -d src ]; then
  echo "ERROR: Directory src/ does not exist in this directory"
  echo "       Please CD into the libcxx directory and try again"
  echo $usage
  exit 1
fi

...(snip)...

libxx_srcdir=${nuttx_path}/libs/libxx

if [ ! -d "${libxx_srcdir}" ]; then
  echo "ERROR: Directory ${libxx_srcdir} does not exist"
  echo $usage
  exit 1
fi

...(snip)...

libcxx_incdir=${nuttx_incdir}/libcxx

if [ -d "${libcxx_incdir}" ]; then
  echo "ERROR: Directory ${libcxx_incdir} already exists"
  echo "       Please remove the  ${libcxx_incdir} directory and try again"
  echo $usage
  exit 1
fi

...(snip)...

# Installation

echo "Installing LLVM/libcxx in the NuttX source tree"

filelist=`find src -type f`

for file in $filelist; do
  if [ "${file##*.}" = "cpp" ]; then
    endfile="`basename ${file} .cpp`.cxx"
  else
    endfile=${file}
  fi
  install -D ${file} ${libxx_srcdir}/libcxx/${endfile#src/}
done

mkdir -p ${libcxx_incdir}

filelist=`find include -type f`

for file in $filelist; do
  install -D ${file} ${nuttx_path}/include/libcxx/${file#include/}
done

filelist=`find machine -type f`

for file in $filelist; do
  install -D ${file} ${nuttx_path}/include/${file}
done

echo "Installation suceeded"
echo ""

拡張子cppをすべてcxxに変換し、NuttXのlibs/libxx/libcxxにコピー。

include以下のファイルはそのままNuttXのinclude/libcxxにコピー。

machine以下のファイルもそのままで、NuttXのincludeにコピーしている。

コンフィグレーションとビルド

今回はstm32f4discovery/testlibcxxを使用する。

元記事ではこの前にいくつかパッチを適用しているが、今回の手順で試す場合は必要なさそうだった。

$ ./tools/configure.sh ./configs/stm32f4discovery/testlibcxx
$ make -j4

動作確認

出来上がったnuttx.binを書き込む。

$ st-flash write nuttx.bin 0x8000000

ボードをリセットするとnshが起動する。 helpコマンドを実行するとhelloxxが見つかるので実行する。

nsh>helloxx
helloxx_main: Saying hello from the dynamically constructed instance
CHelloWorld::HelloWorld: Hello, World!!
helloxx_main: Saying hello from the instance constructed on the stack
CHelloWorld::HelloWorld: Hello, World!!
helloxx_main: Saying hello from the statically constructed instance
CHelloWorld::HelloWorld: Hello, World!!

ちゃんと動いている。

C++11

例えば、ラムダ式や一様初期化 (uniform initialization)とかは動くのか。

helloxxのソースを変更して試してみる。

diff --git a/examples/helloxx/helloxx_main.cxx b/examples/helloxx/helloxx_main.cxx
index 4be4bf6b..3bc4865b 100644
--- a/examples/helloxx/helloxx_main.cxx
+++ b/examples/helloxx/helloxx_main.cxx
@@ -43,6 +43,9 @@
 #include <debug.h>
 
 #include <nuttx/init.h>
+#include <iostream>
+#include <vector>
+#include <algorithm>
 
 #include "platform/cxxinitialize.h"
 
@@ -161,6 +164,8 @@ extern "C"
     printf("helloxx_main: Saying hello from the statically constructed instance\n");
     g_HelloWorld.HelloWorld();
 #endif
+    std::vector<char> vec{'h','e','l','l','o',' ','w','o','r','l', 'd', '\n'};
+    std::for_each(vec.begin(), vec.end(), [](char c){std::cout << c;});
 
     delete pHelloWorld;
     return 0;

再度makeコマンドでnuttx.binを作り、helloxxを実行する。

nsh>helloxx
helloxx_main: Saying hello from the dynamically constructed instance
CHelloWorld::HelloWorld: Hello, World!!
helloxx_main: Saying hello from the instance constructed on the stack
CHelloWorld::HelloWorld: Hello, World!!
helloxx_main: Saying hello from the statically constructed instance
CHelloWorld::HelloWorld: Hello, World!!
hello world
nsh>

最後にhello worldが追加されている。 ちゃんと動くようだ。