SPRESENSE SDKに独自の拡張機能を追加する【External Library】

SPRESENSEを使ってIoTシステムを開発していく中で、アプリケーション共通の機能をライブラリとして実装したくなることがあります。独自の拡張機能を追加できるよう、Visual Studio CodeベースのSPRESENSE開発環境である「SPRESENSE SDK」はExternal Libraryという仕組みを備えています。

![スクリーンショット 2022-09-13 18.03.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595184/ec9aef9d-91c4-9ccc-1eaa-1f9bac115888.png)

### 既存のExternal Library

2022年9月現在、External Libraryとして既に以下の機能が提供されています。これらは、SDKコンフィグにてON/OFFを切り替えることにより、アプリケーションとリンクすることができます（ https://github.com/sonydevworld/spresense/tree/master/externals ）。

- mbedtls
- awsiot
- cmsis
- libjpeg
- wakaama：LightWeight M2M protocol (LWM2M)
- mqtt
- tensorflow

など

# External Libraryを追加する

## 動画

<iframe width="560" height="315" src="https://www.youtube.com/embed/9TjoShr-uT0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## 手順

自前のExternal Libraryを作成・追加することは非常に簡単です。こちらのテンプレート（ https://bit.ly/spresense_extlib_sample ）をダウンロードし、External Libraryディレクトリ内に展開してください。その後、externalディレクトリにあるKconfigに１行追加します。

```Makefile
menu "Externals"
source "/Users/shino/spresense/externals/sample_extlib/Kconfig"
...
endmenu # Externals
```

これだけで、sample_extlibという名前のExternal Libraryが定義されます。内容物を更新することで、独自のライブラリへと進化させてください。サンプルのExternal Libraryを構成しているファイルの意味と内容は以下の通りです。

### Kconfig

SDKコンフィグのメニューを定義しています。
「config EXTERNALS_SAMPLE_EXTLIB」は、DefineとしてCONFIG_EXTERNALS_SAMPLE_EXTLIBをON/OFFする設定項目です。if文を利用可能で、項目が選択されている場合に、子項目を表示するといった設定が可能です。

```Makefile
config EXTERNALS_SAMPLE_EXTLIB
	bool "Sample External Libraries"
	default n
	---help---
		Enable Sample External Libraries.
    
if EXTERNALS_SAMPLE_EXTLIB
config EXTERNALS_SAMPLE_EXTLIB_DEBUGON
	bool "Enablke Debug Print in Sample External Libraries"
	default n
	---help---
		Set log enable of sample extlib component.

endif # EXTERNALS_SAMPLE_EXTLIB
```

### Makefile

ビルドするソースコードや、関連するディレクトリ、生成するライブラリ名を決定します。一般的なMakefileですが、ビルドする処理についてはSPRESENSE SDK全体で共通の定義がありますので省略されています。

```Makefile
-include $(APPDIR)/Make.defs
-include $(SDKDIR)/Make.defs

BIN = libsample_extlib$(LIBEXT)

SAMPLE_EXTLIB_ROOT    = sample_extlib_src

SAMPLE_EXTLIB_DIRS    := $(shell find $(SAMPLE_EXTLIB_ROOT) -type d)
SAMPLE_EXTLIB_SRCS    := $(foreach dir, $(SAMPLE_EXTLIB_DIRS), $(wildcard $(dir)/*.c))
SAMPLE_EXTLIB_OBJS    := $(SAMPLE_EXTLIB_SRCS:.c=.o)

CSRCS         := $(SAMPLE_EXTLIB_SRCS)
CFLAGS        += -std=c99 -DENABLE_SAMPLE_EXTLIB
CFLAGS        += $(addprefix "-I", $(SAMPLE_EXTLIB_DIRS))

VPATH         := $(SAMPLE_EXTLIB_DIRS)
ROOTDEPPATH   := $(foreach dir,$(SAMPLE_EXTLIB_DIRS), --dep-path $(dir))

include $(APPDIR)/Application.mk
```

### Make.defs

Makefileにincludeされます。ここで、対象のライブラリをビルド対象に設定しています。SDKコンフィグのON/OFFに合わせてビルド対象or対象外を選択できるようにしています。

```Makefile
ifeq ($(CONFIG_EXTERNALS_SAMPLE_EXTLIB),y)
CONFIGURED_APPS += sample_extlib
endif
```

### Library.mk

ビルド結果のライブラリをリンクする設定を記述するファイルです。SDKコンフィグのON/OFFに合わせてリンクを付け外しできるようにしています。Makefileのビルド製生物と名前を一致させる必要があります。例えば、Makefileでlibsample_extlib.aを生成する場合、このファイルでは、-lsample_extlibを指定します。

```Makefile
ifeq ($(CONFIG_EXTERNALS_SAMPLE_EXTLIB),y)
  EXTRA_LIBPATHS += -L "$(EXTLIBDIR)$(DELIM)sample_extlib"
  EXTRA_LIBS     += -lsample_extlib
endif
```

### LibIncludes.mk

ライブラリを含めてビルドする場合に、他のソースコードのビルドオプションに追加するものがあれば、追記するファイルです。主に-Iオプションを指定し、ライブラリ内のincludeフォルダをincludeできるようにしておきます。その他、追加Define（以下例ではENABLE_SAMPLE_EXTLIBを追加Define）などを指定します。

```Makefile
ifeq ($(CONFIG_EXTERNALS_SAMPLE_EXTLIB),y)
CFLAGS += -std=c99 -DENABLE_SAMPLE_EXTLIB
endif

ifeq ($(CONFIG_EXTERNALS_SAMPLE_EXTLIB),y)
CFLAGS   += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(SDKDIR)/../externals/sample_extlib/sample_extlib_src"}
endif
```

以上を加えて、SDKコンフィグでExternal Libraryを選択し、ビルドしてください。

![スクリーンショット 2022-09-13 17.57.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595184/ec0d6408-44a4-1966-e311-47dafb5c5505.png)

# アプリケーションからの利用方法

アプリケーションからExternal Libraryを使う場合、includeを追加し、利用したい関数を呼び出してください。LibIncludes.mkによりincludeのパスが通っていますので、<>で宣言可能です。

```c
#include <stdio.h>
#include <stdint.h>
#include <sample_extlib.h>

int
main
(int argc, char *argv[])
{
    int a = 10;
    int b = 20;
    int c;
    /* call Sample External Lib */
    c = sample_extlib_add(a, b);
    return 0;
}
```

最初に述べました通り、MQTTなどの便利機能をライブラリ化するためのものですので、複雑な実装ももちろん入れることが可能です（むしろ複雑な実装を入れることが目的ですね）。SPRESENSE SDKにこの機能を入れたい！とアイデアをお持ちの方、是非お試しください。