2012年8月11日土曜日

Android NDK で COLLADA dom ライブラリをビルド - ビルド用プロジェクトを作成


ビルド用プロジェクトを作成

Tegra Android Development Pack に含まれる eclipse を用いて、以後の説明を行う。

eclipse を起動

eclipse を起動し、任意の場所のワークスペースを開く。

プロジェクトを作成

「File」メニュー ⇒ 「New」 ⇒ 「Other」を選択
wizard 選択画面で、「C/C++」 ⇒ 「C++ Project」を選択し、「Next」ボタンを押下

Project Name:「ColladaDom」
Use default location:「チェックする」
Project type:「Makefile project ⇒ Empty Project」
Toolchains:「-- Other Toolchain --」


「Finish」ボタンを押下

 C/C++ パースペクティブを開くかどうかを聞かれるので、「Remember my decision」をチェックして、「Yes」ボタンを押下


「ColladaDom」プロジェクトに「jni」ディレクトリを作成

ビルド設定

「ColladaDom」プロジェクトを右クリックして、「Properties」を選択
「C/C++ Build」を選択

「Builder Settings」タブ
Use default build command:「チェックを外す」
Build command:「${CYGWIN_HOME}/bin/bash ${NDKROOT}/ndk-build NDK_DEBUG=1 V=1」
Build directory:「${workspace_loc:/ColladaDom/jni}」

「Behaviour」タブ
Build(Incremental build):「”all”文字列を削除」

CPUコアが沢山ある場合は、Use parallel build:Use parallel jobs を設定すると、並列にビルド処理を行うようになる。(Build command の -j オプションが、自動的に追加される)

「OK」ボタンを押下

COLLADA DOM のソースを配置


「ColladaDom」プロジェクトの「jni」ディレクトリ中に、「external-libs」ディレクトリを作成する。

適当なディレクトリに、「collada-dom-2.4.0.tgz」ファイルを解凍する。

「collada-dom-2.4.0\dom\external-libs」ディレクトリの「minizip-1.1」ディレクトリを「ColladaDom」プロジェクトの「external-libs」ディレクトリにコピーする。

「collada-dom-2.4.0\dom」ディレクトリ中の「include」および「src」ディレクトリを、「ColladaDom」プロジェクトの「jni」ディレクトリ以下にコピーする。

ソースのパッチ

「jni/include/dae/daeZAEUncompressHandler.h」ファイル

以下のように修正する。
13行目をコメントアウト
#include 
//#include 
#include 

111行目をコメントアウト
    /**
     * Finds  element in manifest.xml. Used by retrieveRootURIFromManifest().
     */
//    bool findManifestRootElement(xmlTextReaderPtr xmlReader);

「jni/src/dae/daeZAEUncompressHandler.cpp」ファイル

以下のように修正する。
74行目から122行目をコメントアウト
125行目から127行目をコメントアウト
131行目から146行目をコメントアウト
//-----------------------------------------------------------------
bool daeZAEUncompressHandler::retrieveRootURIFromManifest(const std::string& tmpDir)
{
    // extract via libxml.
//    bool error = false;
//    xmlTextReaderPtr xmlReader = xmlReaderForFile(
//        (tmpDir + MANIFEST_FILE_NAME).c_str(),
//        NULL,
//        0
//        );
//
//    if (xmlReader)
//    {
//        if (findManifestRootElement(xmlReader))
//        {
//            if (xmlTextReaderRead(xmlReader))
//            {
//                if (xmlTextReaderNodeType(xmlReader) == XML_READER_TYPE_TEXT) {
//                    const xmlChar* xmlText = xmlTextReaderConstValue(xmlReader);
//
//                    // copy xmlText.
//                    std::string rootFilePath((daeString)xmlText);
//
//                    // destroy xmlText.
//                    xmlTextReaderRead(xmlReader);
//
//                    cdom::trimWhitespaces(rootFilePath);
//                    mRootFilePath = cdom::nativePathToUri(tmpDir + rootFilePath);
//                }
//                else
//                {
//                    error = true;
//                }
//            }
//            else
//            {
//                error = true;
//            }
//        }
//        else
//        {
//            error = true;
//        }
//    }
//    else
//    {
//        error = true;
//    }
//
//    if (xmlReader)
//        xmlFreeTextReader(xmlReader);
//    if (error)
//    {
        daeErrorHandler::get()->handleError("Error parsing manifest.xml in daeZAEUncompressHandler::retrieveRootURIFromManifest\n");
        return false;
//    }
//
//    return true;
}

//-----------------------------------------------------------------
//bool daeZAEUncompressHandler::findManifestRootElement( xmlTextReaderPtr xmlReader )
//{
//    while(xmlTextReaderNodeType(xmlReader) != XML_READER_TYPE_ELEMENT)
//    {
//        if (xmlTextReaderRead(xmlReader) != 1) {
//            return false;
//        }
//    }
//
//    daeString elementName = (daeString)xmlTextReaderConstName(xmlReader);
//    if (strcmp(elementName, MANIFEST_FILE_ROOT_ELEMENT_NAME.c_str()) == 0)
//    {
//        return true;
//    }
//    return findManifestRootElement(xmlReader);
//}

Makefile を作成

「jni」ディレクトリに「Application.mk」および「Android.mk」ファイルを作成する。LF改行にしておくこと。

「Application.mk」ファイル

APP_MODULES := collada_dom collada_LIBXMLPlugin collada_stdErrPlugin collada_STLDatabase
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
APP_STL := gnustl_static

「Android.mk」ファイル

LOCAL_PATH := $(call my-dir)

DOM_VERSION := 1.4
#DOM_VERSION := 1.5
DOM_VERSION_NO_DOSTS := $(subst .,,$(DOM_VERSION))

COLLADA_DOM_SUPPORT := COLLADA_DOM_SUPPORT141
#COLLADA_DOM_SUPPORT := COLLADA_DOM_SUPPORT150

#
# collada_dom
#
include $(CLEAR_VARS)
LOCAL_MODULE := collada_dom
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := $(wildcard src/$(DOM_VERSION)/dom/*.cpp)
LOCAL_SRC_FILES += $(wildcard src/dae/*.cpp)
LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include \
    $(LOCAL_PATH)/external-libs/boost \
    $(LOCAL_PATH)/external-libs/minizip-1.1 \
    $(LOCAL_PATH)/external-libs/pcre \
    $(LOCAL_PATH)/external-libs/tinyxml

LOCAL_CPPFLAGS := -DCOLLADA$(DOM_VERSION_NO_DOSTS)
LOCAL_CPPFLAGS += -D$(COLLADA_DOM_SUPPORT)
LOCAL_CPPFLAGS += -DDOM_INCLUDE_TINYXML
LOCAL_CPPFLAGS += -fexceptions
LOCAL_STATIC_LIBRARIES := \
    boost_filesystem \
    boost_system \
    minizip \
    pcre \
    pcrecpp \
    tinyxml

include $(BUILD_STATIC_LIBRARY)


#
# LIBXMLPlugin
#
include $(CLEAR_VARS)
LOCAL_MODULE := collada_LIBXMLPlugin
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := src/modules/LIBXMLPlugin/daeLIBXMLPlugin.cpp
LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include \
    $(LOCAL_PATH)/external-libs/minizip-1.1 \
    $(LOCAL_PATH)/external-libs/tinyxml

LOCAL_CPPFLAGS := -DCOLLADA$(DOM_VERSION_NO_DOSTS)
LOCAL_CPPFLAGS += -D$(COLLADA_DOM_SUPPORT)
LOCAL_CPPFLAGS += -DDOM_INCLUDE_TINYXML
LOCAL_CPPFLAGS += -fexceptions

include $(BUILD_STATIC_LIBRARY)


#
# stdErrPlugin
#
include $(CLEAR_VARS)
LOCAL_MODULE := collada_stdErrPlugin
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := src/modules/stdErrPlugin/stdErrPlugin.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := -DCOLLADA$(DOM_VERSION_NO_DOSTS)
LOCAL_CPPFLAGS += -D$(COLLADA_DOM_SUPPORT)
LOCAL_CPPFLAGS += -DDOM_INCLUDE_TINYXML
LOCAL_CPPFLAGS += -fexceptions

include $(BUILD_STATIC_LIBRARY)


#
# STLDatabase
#
include $(CLEAR_VARS)
LOCAL_MODULE := collada_STLDatabase
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := src/modules/STLDatabase/daeSTLDatabase.cpp
LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include \
    $(LOCAL_PATH)/external-libs/boost
LOCAL_CPPFLAGS := -DCOLLADA$(DOM_VERSION_NO_DOSTS)
LOCAL_CPPFLAGS += -D$(COLLADA_DOM_SUPPORT)
LOCAL_CPPFLAGS += -DDOM_INCLUDE_TINYXML
LOCAL_CPPFLAGS += -fexceptions

include $(BUILD_STATIC_LIBRARY)

#
# common libs
#
$(call import-add-path,external-libs)

$(call import-module,boost)
$(call import-module,minizip-1.1)
$(call import-module,pcre)
$(call import-module,tinyxml)


備考

試行錯誤中などに、インポートモジュールだけをビルドしたい場合がある。
かといって、「external-libs」のそれぞれの「Android.mk」だけを、実行しようとしても、ndk-build が、親ディレクトリを検索して、おかしな挙動をするので、うまくいかなかった。
仕方が無いので、次の方法でお茶を濁すことにした。

「jni/Application.mk」
APP_MODULES をコメントアウトして
その下の行に以下の行を追加
APP_MODULES := dummy

「jni/Android.mk」
# common libs ブロックの上に、下の設定を追加
include $(CLEAR_VARS)
LOCAL_MODULE := dummy
LOCAL_STATIC_LIBRARIES := \
    boost_filesystem \
    boost_system
include $(BUILD_STATIC_LIBRARY)

LOCAL_STATIC_LIBRARIES にビルドしたいライブラリ名(boost のモジュール名など)を指定する。