Spresense SDK 環境で LLVM libc++ 標準ライブラリを使う方法

最新の NuttX バージョンでは LLVM "libc++" C++ Standard Library を Configuration により選択できるようになっていますが、Spresense SDK 環境で使用している NuttX バージョンにはそれがまだ取り込まれていないのでマニュアルで組み込む必要があります。

やり方は [LLVM libc++ for NuttX](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=139629545) に書いてある方法を参考にしました。(というかそのもの)

## インストール

インストール方法は、`<Your spresense/nuttx directory>` に Spresense SDK 環境の nuttx ディレクトリを指定して `install.sh` を実行します。

```shell
$ git clone https://github.com/baggio63446333/libcxx
$ cd libcxx
$ ./install.sh <Your spresense/nuttx directory>
```

インストールといっても nuttx 以下のディレクトリにソースやヘッダファイルをコピーするだけです。

* nuttx/libs/libxx/libcxx
* nuttx/include/libcxx
* nuttx/include/machine

これらコピー先のディレクトリは、`.gitignore` ファイルにより構成管理対象外に設定されているので、`git status`コマンドを実行しても表示されません。

アンインストール(ファイル削除)するときは、`uninstall.sh` を実行します。

```shell
$ cd libcxx
$ ./uninstall.sh <Your spresense/nuttx directory>
```

## コンフィグレーション

LLVM C++ Library を有効にするには、以下のように Configuration を設定します。

`menuconfig` を開きます。

```shell
$ cd spresense/sdk
$ ./tools/config.py default -m
```

`Build Setup -> Customize Header Files ->` から `math.h` のチェックを外します。
![uncheck-math.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/7b6ea487-c063-cd3a-f615-aee9ad29c6ef.png)

`Library Routines ->` から `Standard Math library` と `Build LLVM libcxx` にチェックを入れます。
![check-llvm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/da629f80-a614-c710-ae51-4566c70d7ced.png)


`menuconfig` の設定を完了し、`configs/feature/libcxx/defconfig` ファイルとして設定を保存しておきます。

```shell
$ ./tools/mkdefconfig.py feature/libcxx
```

ファイルの中身はこのようになります。

```
$ cat configs/feature/libcxx/defconfig 
-ARCH_MATH_H=y
-CLOCK_MONOTONIC=y
+LIBCXX=y
+LIBCXX_EXCEPTION=n
+LIBM=y
```

コンパイルオプションを変更するために、Makefile を変更します。

-  -Inuttx/include/libcxx へのインクルードパスの追加
-  -stdc=c++98 から -std=c++11 への変更
-  -D__NuttX__ 定義の追加

参考：https://github.com/baggio63446333/spresense/commit/06802864c6026ce1caac66da3aca99ea93220810

```diff
$ diff --git a/sdk/tools/scripts/Make.defs b/sdk/tools/scripts/Make.defs
index 4eb5ddaab5..9f54a50af3 100644
--- a/sdk/tools/scripts/Make.defs
+++ b/sdk/tools/scripts/Make.defs
@@ -49,7 +49,10 @@ ifeq ($(WINTOOL),y)
   DIRUNLINK = $(TOPDIR)/tools/unlink.sh
   MKDEP = $(TOPDIR)/tools/mkwindeps.sh
   ARCHINCLUDES = -I. -isystem "${shell cygpath -w $(TOPDIR)/include}" -isystem "${shell cygpath -w $(SDKDIR)/include}"
-  ARCHXXINCLUDES = -I. -isystem "${shell cygpath -w $(TOPDIR)/include}" -isystem "${shell cygpath -w $(TOPDIR)/include/cxx}" -isystem "${shell cygpath -w $(SDKDIR)/include}
+  ARCHXXINCLUDES = -I. -isystem "${shell cygpath -w $(TOPDIR)/include}" -isystem "${shell cygpath -w $(TOPDIR)/include/cxx}" -isystem "${shell cygpath -w $(SDKDIR)/include}"
+ifeq ($(CONFIG_LIBCXX),y)
+  ARCHXXINCLUDES += -isystem "${shell cygpath -w $(TOPDIR)/include/libcxx}"
+endif
   ARCHSCRIPT = -T "${shell cygpath -w $(TOPDIR)/boards/$(CONFIG_ARCH)/$(CONFIG_ARCH_CHIP)/$(CONFIG_ARCH_BOARD)/scripts/$(LDSCRIPT)}"
   HOSTEXEEXT = .exe
 else
@@ -57,6 +60,9 @@ else
   MKDEP = $(TOPDIR)/tools/mkdeps$(HOSTEXEEXT)
   ARCHINCLUDES = -I. -isystem $(TOPDIR)/include -isystem $(SDKDIR)/include
   ARCHXXINCLUDES = -I. -isystem $(TOPDIR)/include -isystem $(TOPDIR)/include/cxx -isystem $(SDKDIR)/include
+ifeq ($(CONFIG_LIBCXX),y)
+  ARCHXXINCLUDES += -isystem $(TOPDIR)/include/libcxx
+endif
   ARCHSCRIPT = -T$(TOPDIR)/boards/$(CONFIG_ARCH)/$(CONFIG_ARCH_CHIP)/$(CONFIG_ARCH_BOARD)/scripts/$(LDSCRIPT)
   HOSTEXEEXT =
 endif
@@ -86,10 +92,10 @@ ifneq ($(CONFIG_DEBUG_NOOPT),y)
 endif
 
 ARCHCFLAGS = -fno-builtin -mabi=aapcs -ffunction-sections -fdata-sections
-ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fno-rtti -std=c++98
+ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fno-rtti -std=c++11
 ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
 ARCHWARNINGSXX = -Wall -Wshadow -Wundef
-ARCHDEFINES =
+ARCHDEFINES = -D__NuttX__
 ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10
 
 CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
```

## ビルド

`tools/config.py` の引数に `feature/libcxx` を入れることで LLVM C++ Library が有効になります。

```shell
$ cd spresense/sdk
$ ./tools/config.py feature/libcxx <その他のconfig...>
$ make
```