SPRESENSEのNuttX上でuClibc++を使用したC++アプリケーションを動かす

SPRESENSEのNuttX上でuClibc++を使用したC++アプリケーションを動かす

概要

nuttx/libxx の中に基本的なC++の機能を提供するためのライブラリは付属していますが,STLがカバーしている iostreamvector 等の機能を利用したプログラムは,そのままではコンパイルできません. この記事では,軽量なSTL互換ライブラリであるuClibc++をSPRESENSEのNuttXに組み込み,C++の標準ライブラリを利用できるようにする方法を紹介します.

バージョン等

  • SPRESENSE SDK v1.0.1
  • NuttX: git(33597a8)

uClibc++のクローンとインストール

NuttXのuClibc++をsdkと同じディレクトリにクローンします.

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

SPRESENSEのNuttXは本家NuttXの最新版とはディレクトリ構造が異なるため,install.sh を編集して対応させます.

- libs_path=${nuttx_path}/libs
+ libs_path=${nuttx_path}

実行してファイルをインストールします.

$ cd uclibc
$ ./install.sh ../nuttx

これによって,nuttx/include/uClibc++ の中にヘッダが,nuttx/libxx/uClibc++ の中にソースがコピーされます. nuttx/Make.defs を編集して,uClibc++のヘッダのあるディレクトリをインクルードパスに追加します.

- ARCHXXINCLUDES = -I. -isystem $(TOPDIR)/include -isystem $(TOPDIR)/include/cxx
+ ARCHXXINCLUDES = -I. -isystem $(TOPDIR)/include -isystem $(TOPDIR)/include/cxx -isystem $(TOPDIR)/include/uClibc++

パッチを当てる

最近のコンパイラではそのままビルドできないため,パッチを当てます.

参考: [PATCH 2/2 uClibc++] Fix ARM EABI build failure in include/unwind-cxx.h

--- unwind-cxx.h.orig   2018-08-09 01:13:19.611199326 +0900
+++ unwind-cxx.h    2018-08-09 01:13:51.634592945 +0900
@@ -184,8 +184,9 @@

 // This is the exception class we report -- "GNUCC++\0".

-const _Unwind_Exception_Class __gxx_exception_class =
-  ((((((((_Unwind_Exception_Class) 'G'
+const _Unwind_Exception_Class __gxx_exception_class
+#ifndef __ARM_EABI_UNWINDER__
+  = ((((((((_Unwind_Exception_Class) 'G'
          << 8 | (_Unwind_Exception_Class) 'N')
         << 8 | (_Unwind_Exception_Class) 'U')
        << 8 | (_Unwind_Exception_Class) 'C')
@@ -193,6 +194,9 @@
      << 8 | (_Unwind_Exception_Class) '+')
     << 8 | (_Unwind_Exception_Class) '+')
    << 8 | (_Unwind_Exception_Class) '\0');
+#else
+  = "GNUCC++";
+#endif

 // GNU C++ personality routine, Version 0.

NuttXカーネルの設定と再ビルド

$ cd sdk
$ make menuconfigkernel

矢印キーで選択,Enterで下の階層に入り,Escを2回押して上の階層に戻れます.スペースでチェックを付け外します.

  • Library Routines
    • sizeof(_Bool) is 8-bits のチェックを入れる
    • Build uClibc++ のチェックを入れる
    • Enable Exception Support のチェックを外す
    • Have libsupc++ のチェックを外す

ビルドします.

$ make cleankernel
$ make buildkernel

うまく行かないときは config.py でデフォルトの設定を読ませてから再度 make menuconfig するとうまく行くかもしれません.

STLを使用したプログラムを書く

tools/mkappsdir.pytools/mkcmd.py を使ってプロジェクトを作成します.

参考→ SPRESENSE SDKでArduinoを使わずにとりあえずLチカする

$ tools/mkappsdir.py cxxapps 'C++ Applications'
$ tools/mkcmd.py -d cxxapps test_stl 'STL test'

テンプレートとしてコピーされるソースの拡張子を変更します.

$ cd ../cxxapps/test_stl
$ mv test_stl_main.c test_stl_main.cxx

Makefileを編集します.コンパイラのフラグも書いておきます.

- MAINSRC = test_stl_main.c
+ MAINSRC = test_stl_main.cxx
+ CXXFLAGS += -std=gnu++17

外から見えている必要のある関数(ここではtest_stl_main)を extern "C" で囲みます.

#include <sdk/config.h>
#include <stdio.h>

extern "C"{

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int test_stl_main(int argc, char *argv[])
#endif
{
  return 0;
}

}

基本的にはこれだけしていればおkです. あとはプログラムを書いていきます. 以下の例は,vectorに入れて出すだけの無意味なプログラムです.

#include <sdk/config.h>
#include <iostream>
#include <vector>

using namespace std;

extern "C"{

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int test_stl_main(int argc, char *argv[])
#endif
{
    vector<int> v;
    for(int i=0; i<10; i++){
        v.push_back(i);
    }

    for(auto x : v){
        cout<<x<<",";
    }
    cout<<endl;
    return 0;
}

}

ビルド

$ make menuconfig

“C++ Applications” → “STL Test” にチェックを入れて終了します.

$ make
$ ./tools/flash.sh -b 2000000 -c /dev/ttyUSB0 nuttx.spk

できた

Share Comments