Androidの ライブラリモジュールに C++ ネイティブを追加する

## やりたいこと

Javaで実装したAndroidのライブラリモジュールがあります。これを C++ で再実装したいので、C++のコードを書く前に、Androidのプロジェクトの設定を行います。

## 環境

* OS Windows 10
* Android Studio 3.4.1
* Gradle 5.1.1

## Android Studio にコンポーネントを追加

[公式ドキュメントの「NDK とビルドツールのダウンロード 」](https://developer.android.com/studio/projects/add-native-code?hl=ja#download-ndk) に従って 必要なツールを *SDK Manager* の *SDK Tools* からインストールします。

1. LLDB
2. CMake
3. NDK 

## 手順

### cpp のソースファイルを追加

1. [Project] ペインを開き、ペイン内上部のプルダウンから *Project*に変更します。
2. *プロジェクト名* -> *モジュール名* -> src ディレクトリ -> main ディレクトリ の配下に *cpp* ディレクトリを作成します。
3. 作成した *cpp* ディレクトリで 右クリックして、[New] > [C/C++ Source File] を選択します。
4. ソースファイルの名前（native-lib など）を入力し、[Create an associated header]にチェックをつけて、[OK]をクリックします。

![ディレクトリ作成とソースファイル追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145742/61e40be8-649e-2e27-6afa-422ffea1e6d8.png)

### CMakelists.txt を追加

1. *プロジェクト名* -> *モジュール名* で右クリックして、[New] > [File]を選択します。
2. ファイル名に *CMakeLists.txt* を入力して、[OK]をクリックします。

![CMakelists.txtを追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145742/a76a5659-f6b2-ce54-92b4-838fa6aa6d1a.png)


### CMakeLists.txt にビルド対象を追加

```:ProjectName/ModuleName/CMakeLists.txt
# ビルドに必要なCMakeの最小バージョン
cmake_minimum_required(VERSION 3.4.1)

# ビルドするライブラリの定義
add_library( # ライブラリ名. 作成されるライブラリのファイル名は「lib[下の名前].so」になる
             native-lib
             # 静的リンクと動的リンクの指定
             SHARED
             # ライブラリを構成するソースファイル
             # C もしくは C++ のファイルを増やした時にはここに追加する 
             src/main/cpp/native-lib.cpp )

# ヘッダーファイルがあるディレクトリのパス
include_directories(src/main/cpp/include/)
```

cmake_minimum_required は CMakeの最小バージョンを指定します。Cmakeは SDK Mangerの「Android SDK Location」配下の *cmake* ディレクトリにインストールされています。

### CMakeLists.txt にNDK APIを追加

NDK APIを利用するために、利用するライブラリの場所と、リンクするライブラリを明示します。

```:ProjectName/ModuleName/CMakeLists.txt
# 使用するライブラリの場所
find_library( # NDKライブラリのパスが代入される変数名
        log-lib

        # NDKライブラリのパス
        log)

# リンクするライブラリを明示する
target_link_libraries( # 出力するライブラリ.
        native-lib

        # リンクするライブラリ ld -llog-lib に相当する.
        ${log-lib})
```

### Gradle に追加

1. *プロジェクト名* -> *モジュール名* で右クリックして、[Link C++ Project with Gradle]を選択します。
![Gradleに追加開始.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145742/b85e269e-69b2-919f-cdce-0c0f13031d6e.png)

2. ファイル選択のダイアログが表示されたら、Build Systemが *CMake* であることを確認し、 *CMakeLists.txt* のパスを指定します。

![GMakeList.txtを指定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145742/a8f5d9db-fc29-e282-6071-46f3175c766f.png)

### Gradleに追加された結果を確認

* [Project]ペインのプルダウンを　*Android* に変更すると、C++のファイルが追加されていることを確認できます。

![cppを認識した結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145742/8a5a5ce3-38e6-a358-289b-f76b78b65cd9.png)

* `<project-root>/<module-root>/build.gradle` に *externalNativeBuild* が追加されています。

```module-root/build.gradle
android {

    ～ 色々省略 ～

    externalNativeBuild {
        cmake {
            path file('CMakeLists.txt')
        }
    }
}
```
## ビルドを実行

Android StudioでC++を含むプロジェクトを新規に作成した時に生成されたサンプル使ってビルドを試します。

ここまでの手順で作成した `<project-root>/<module-root>/src/main/cpp/native-lib.cpp` を下のコードにします。

```c:module-root/src/main/cpp/native-lib.cpp
#include <jni.h>
#include <string>

#include "native-lib.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_mynativeapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

```

Android Studioの [build] -> [Make Project]を選択して、プロジェクトをビルドします。

ビルドして作成されたライブラリは  `<project-root>/<module-root>/build/intermediates/cmake/<build-type>/obj/<ABI>/lib[ライブラリ名].so` です。ABIは https://developer.android.com/ndk/guides/abis.html#sa を参照してください。

## 参考
* [プロジェクトへの C / C++ コードの追加](https://developer.android.com/studio/projects/add-native-code?hl=JA)
* [CMake @niusounds](https://qiita.com/niusounds/items/1c799475caf981eb2335)