cocos2d-x v3＆Android NDK r10e＆clang＆libc++なAndroidプロジェクトでprebuiltライブラリを使う


いろいろ調べたんですが「これだ！」という情報が見つからなかったので、様々なネット情報を元に試行錯誤を繰り返して得られた知見をまとめておきます。

## やりたいこと

以下の環境・条件でAndroidバイナリをビルドする必要があるcocos2d-xアプリプロジェクトでprebuitなcocos2d-xのライブラリを使いたい。

- cocos2d-x: 3.15.1
- Android NDK: r10e
- コンパイラ: clang
- STL: c++_static

ファイルツリーは以下の状態とします。

```
cocos/
 |
 +- cocos2d-x-3.15.1/ .. cocos2d-x-3.15.1.zipを展開したディレクトリ
 +- targetapp/ .. `cocos new` コマンドで生成したアプリ
```

## 手順

### cocos2d-x側の変更とprebuiltライブラリのビルド

```
$ cd cocos/cocos2d-x-3.15.1
```

リンク時に`multiple definition of 'main'`というエラーが起きてしまうため、`external/flatbuffers/Android.mk`を変更します。

```external/flatbuffers/Android.mkの差分
@@ -9,7 +9,6 @@ LOCAL_MODULE_FILENAME := flatbuffers
 LOCAL_ARM_MODE := arm
 
 LOCAL_SRC_FILES := \
-flatc.cpp \
 flathash.cpp \
 idl_gen_cpp.cpp \
 idl_gen_fbs.cpp \
```

cocosコマンドは内部で`tools/simulator/frameworks/runtime-src`というプロジェクトをビルドすることでprebuiltライブラリをビルドしていますが、LuaバインディングとJavaScriptバインディングはNDK r10eではうまくビルドできないようなので外します。

```tools/simulator/frameworks/runtime-src/Classes/AppDelegate.cppの差分
@@ -1,5 +1,4 @@
 #include "AppDelegate.h"
-#include "CCLuaEngine.h"
 #include "SimpleAudioEngine.h"
 #include "cocos2d.h"
 

```

```tools/simulator/frameworks/runtime-src/proj.android/jni/Android.mkの差分
@@ -21,14 +21,12 @@ $(LOCAL_PATH)/../../../../../../external \
 $(LOCAL_PATH)/../../../../../../tools/simulator/libsimulator/lib \
 $(LOCAL_PATH)/../../../../../../tools/simulator/libsimulator/lib/protobuf-lite
 
-LOCAL_STATIC_LIBRARIES := cocos2d_lua_static 
+LOCAL_STATIC_LIBRARIES := cocos2dx_static
 LOCAL_STATIC_LIBRARIES += cocos2d_simulator_static
-LOCAL_STATIC_LIBRARIES += cocos2d_js_static
 
-LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT
+LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2
 
 include $(BUILD_SHARED_LIBRARY)
 
-$(call import-module,scripting/lua-bindings/proj.android)
-$(call import-module,scripting/js-bindings/proj.android)
+$(call import-module,.)
 $(call import-module,tools/simulator/libsimulator/proj.android)
```

STLとしてc++_staticを使うようにします。（こうしておかないと同じくc++_staticを使うアプリとリンクできません。）

```tools/simulator/frameworks/runtime-src/proj.android/jni/Application.mkの差分
@@ -1,4 +1,4 @@
-APP_STL := gnustl_static
+APP_STL := c++_static
 
 APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char
 APP_LDFLAGS := -latomic
```

これで準備が完了したので、prebuiltライブラリをビルドします。ビルド時clangが使われるように`NDK_TOOLCHAIN_VERSION=clang`を指定している点に注意。

```
$ NDK_TOOLCHAIN_VERSION=clang cocos gen-libs -p android --app-abi armeabi:armeabi-v7a:x86
```

## アプリ側の変更とアプリのビルド

```
$ cd cocos/targetapp
```

Androidビルド時にprebuiltライブラリが使用されるように各ファイルを変更します。（`build.gradle`についてはclangでビルドされるような変更も含んでいます）

```proj.android-studio/settings.gradleの差分
@@ -1,4 +1,4 @@
 include ':libcocos2dx'
-project(':libcocos2dx').projectDir = new File(settingsDir, '../cocos2d/cocos/platform/android/libcocos2dx')
+project(':libcocos2dx').projectDir = new File(settingsDir, '../../cocos2d-x-3.15.1/cocos/platform/android/libcocos2dx')
 include ':test'
 project(':test').projectDir = new File(settingsDir, 'app')
```

```proj.android-studio/app/build.gradleの差分
@@ -13,17 +13,21 @@
         versionCode 1
         versionName "1.0"
 
         externalNativeBuild {
             ndkBuild {
                 if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
                     // skip the NDK Build step if PROP_NDK_MODE is none
                     targets 'MyGame'
-                    arguments 'NDK_TOOLCHAIN_VERSION=4.9'
+                    arguments 'NDK_TOOLCHAIN_VERSION=clang'
                     arguments 'APP_PLATFORM=android-'+PROP_TARGET_SDK_VERSION
    
-                    def module_paths = [project.file("../../cocos2d").absolutePath,
-                                        project.file("../../cocos2d/cocos").absolutePath,
-                                        project.file("../../cocos2d/external").absolutePath]
+                    def module_paths = [project.file("../../../cocos2d-x-3.15.1").absolutePath,
+                                        project.file("../../../cocos2d-x-3.15.1/cocos").absolutePath,
+                                        project.file("../../../cocos2d-x-3.15.1/external").absolutePath]
                     if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                         // should use '/' 
                         module_paths = module_paths.collect {it.replaceAll('\\\\', '/')}
```

```proj.android-studio/app/jni/Android.mkの差分
@@ -2,10 +2,7 @@
 
 include $(CLEAR_VARS)
 
-$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d)
-$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/external)
-$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/cocos)
-$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/cocos/audio/include)
+$(call import-add-path,$(LOCAL_PATH)/../../../../cocos2d-x-3.15.1/cocos/prebuilt-mk)
 
 LOCAL_MODULE := MyGame_shared
 
@@ -28,7 +25,7 @@

 include $(BUILD_SHARED_LIBRARY)

-$(call import-module,.)
+$(call import-module,./prebuilt-mk)

 # _COCOS_LIB_IMPORT_ANDROID_BEGIN
 # _COCOS_LIB_IMPORT_ANDROID_END
```

アプリのビルド時にSTLとしてc++_staticを使うように変更します。

```proj.android-studio/app/jni/Application.mkの差分
@@ -1,4 +1,7 @@
-APP_STL := gnustl_static
+APP_STL := c++_static

 APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char
 APP_LDFLAGS := -latomic
```

あとは普通にビルドすればOKです。

```
$ cocos compild -p android --android-studio -s .
```

ビルドが高速化されて快適になりました！