Playground(Android)のJenkins環境を整える

ハッカソンに行ってきた。
そのときにjenkinsである程度動いたかと思ったら動いておらず
いろんな罠にハマっていたらえらく日数がかかってしまいました。

セットアップ方法とハマりそうなエラーとその原因を軽くまとめようと思います

monoまわりをセットアップしていないので
運用としてはAppAssets.zipは作ってレポジトリに置くような感じになります。

環境のセットアップ

OS:ubuntu 12.04 64bit(12.10や13.04は苦労する可能性が大きいです)

githubに解説がありますがいくつか不足があるのと英語です。
https://github.com/KLab/PlaygroundOSS/blob/master/Doc/Android_Build.md

大きくは

必要なライブラリとツールのインストール

aaptがなぜか32bitバイナリーなのでia32libsとzipなどのコマンド類をいれます。

androidの開発環境のインストール

androidのビルドのためにjavaandroid-sdkandroid-ndkが必要です。

PlaygroundOSSのビルド

最終目的地です

では順番に

必要なライブラリとツールのインストール

aptで一発ワンライナーです。

sudo apt-get install libgd2-xpm ia32-libs ia32-libs-multiarch zip git

androidの開発環境のインストール

javaは以下からダウンロードできます。
http://www.oracle.com/technetwork/jp/java/javase/downloads/index.html
展開してパスを通しましょう。

sdkは以下からダウンロードできます。
http://developer.android.com/sdk/index.html
sdkはちょくちょくかわるのでとんでダウンロードしてください。

ndkは以下からダウンロードできます。
64 bit : http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2

例として$HOME以下に展開します。
パスを通します。
その際にANDROID_NDK_ROOTは必ず定義してください。
無いとビルド時にエラーになります。

export ANDROID_NDK_ROOT=$HOME/android-ndk-r9/
export PATH=$PATH:$ANDROID_NDK_ROOT:$HOME/android-sdk-linux/tools:$HOME/android-sdk-linux/platform-tools

sdkandroidコマンドを使ってビルドツールとかをインストールしましょう。
GUIでもできますがコマンドでやると以下のようになります。

echo 'y' | android update sdk --filter platform-tools,android-17,extra-android-support,android-17,sysimg-17 --no-ui --force
echo 'y' | android update sdk -a --filter `android list sdk --extended -a | grep \"build-tools-18.1.0\" |cut -d ' ' -f 2` --no-ui --force
echo 'y' | android update sdk -a --filter `android list sdk --extended -a | grep \"build-tools-19.0.0\" |cut -d ' ' -f 2` --no-ui --force

PlaygroundOSSのビルド

以下のページからダウンロードするかgitでクローンしてチュートリアルのプログラムをビルドします。
https://github.com/KLab/PlaygroundOSS

git clone https://github.com/KLab/PlaygroundOSS.git
cd $HOME/PlaygroundOSS/Tutorial/01.SimpleItem/.publish/android/
zip -r -0 $HOME/PlaygroundOSS/Engine/porting/Android/GameEngine-android/assets/AppAssets.zip ./*
echo -n "1" > $HOME/PlaygroundOSS/Engine/porting/Android/GameEngine-android/assets/version ./*
$HOME/PlaygroundOSS/Engine/porting/Android/GameEngine-android/build.py --rebuild --assemble --project SampleProject

これでサンプルプログラムが動きます。

jenkinsはshellでEngine以下をコピーしてAppAssets.zipを入れてビルドする
以下のようになります。

cp -r $HOME/PlaygroundOSS/Engine/ ./
mkdir -p `pwd`/Engine/porting/Android/GameEngine-android/assets/
mv android-assets/AppAssets.zip Engine/porting/Android/GameEngine-android/assets/
sum Engine/porting/Android/GameEngine-android/assets/AppAssets.zip > Engine/porting/Android/GameEngine-android/assets/version
cd Engine/porting/Android/GameEngine-android/
./gradlew assemble

こんな感じでビルドがまわせると思うので、後はお好みのテストツールと組み合わせるといいでしょう。

トラブルシュート

エラーが出てしまった人たち用にエラーメッセージと解決法を書いておきます

32bitライブラリーが入っていない編(必要なライブラリとツールのインストールをやってない)

まず、64bitの場合、ubuntuバージョンは12.04を使いましょう。
その上でia32libを入れないと以下のようにおこられます。

+ ./gradlew assemble
:preBuild UP-TO-DATE
:preDebugBuild UP-TO-DATE
:prepareDebugDependencies
:compileDebugAidl
:compileDebugRenderscript
:generateDebugBuildConfig
:mergeDebugAssets
:mergeDebugResources
/home/jenkins/workspace/playgroundthon/Engine/porting/Android/GameEngine-android/res/drawable-mdpi/ic_launcher.png: Error: Cannot run program "/home/jenkins/tools/android-sdk/build-tools/19.0.0/aapt": error=2, そのようなファイルやディレクトリはありません
:mergeDebugResources FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':mergeDebugResources'.
> /home/jenkins/workspace/playgroundthon/Engine/porting/Android/GameEngine-android/res/drawable-mdpi/ic_launcher.png: Error: Cannot run program "/home/jenkins/tools/android-sdk/build-tools/19.0.0/aapt": error=2, そのようなファイルやディレクトリはありません

ファイルはあるのですが32bitのバイナリを実行しようとしてこんな感じに怒られます。

13.04は確実にパッケージが無いのでia32libでインストールされるパッケージ類を調べてインストールするしかないです。
12.10は分かりません。

ANDROID_NDK_ROOTが設定されていない編

以下のような感じで怒られます。

>> Compile++ x86    : Game <= FileDelete.cpp
>> Compile++ x86    : Game <= KLBOpenSLSoundAssetLoader.cpp
>> Compile++ x86    : Game <= CSampleProjectEntrance.cpp
>> Compile++ x86    : jniproxy <= jniproxy.cpp
>> Compile arm    : Game <= hash_sha1.c
>> Compile arm    : Game <= ldebug.c
>> Compile arm    : Game <= lstrlib.c
>> Compile arm    : Game <= lgc.c
>> Compile arm    : Game <= lfunc.c
>> Compile arm    : Game <= loadlib.c
>> jni/Android/CSockWriteStream.cppCompile arm    : Game <= lopcodes.c
>> Compile arm    : Game <= ldblib.c
>> :42:22: error: use of undeclared identifier 'write'
>>         int result = write(m_fd, buffer + pos, sndSize - pos);
>>                      ^
>> jni/source/Core/DebugTracker.cpp:221:2: error: use of undeclared identifier 'sleep'
>>         sleep(1000);  // waiting for client receive CMD_END.
>>         ^
>> 1Compile arm    : Game <= lctype.c
>> Compile arm    : Game <= lmathlib.c
>> 1 error generated.
>> make: *** [obj/local/x86/objs/Game/source/Core/DebugTracker.o] Error 1
>> make: *** Waiting for unfinished jobs....
>> Compile arm    : Game <= lzio.c
>>  error generated.
>> make: *** [obj/local/x86/objs/Game/Android/CSockWriteStream.o] Error 1
>> jni/Android/CAndroidWriteFileStream.cppjni/Android/CSockReadStream.cpp:42:14: error: use of undeclared identifier 'close'
>>     if(m_fd) close(m_fd);
>>              ^
>> jni/Android/CSockReadStream.cpp:41:9: error: use of undeclared identifier 'close'
>>         close(m_fd);
>>         ^
>> :81:6: error: use of undeclared identifier 'close'
>>         close(dstSocket);
>>         ^
>> jni/Android/CSockReadStream.cpp:100:11: error: use of undeclared identifier 'close'
>>                         close(m_fd);
>>                         ^
>> jni/Android/CSockReadStream.cpp1 error generated.
>> make: *** [obj/local/x86/objs/Game/Android/CAndroidWriteFileStream.o] Error 1
>> jni/Android/CAndroidReadFileStream.cpp:110:17: error: use of undeclared identifier 'close'
>>                 close(m_fd);
>>                 ^
>> jni/Android/CSockReadStream.cpp:86:6: error: use of undeclared identifier 'close'
>>         close(pStream->m_fd);
>>         ^
>> 1:127:22: error: use of undeclared identifier 'read'
>>         int result = read(m_fd, m_readBuf + m_lastPos, READ_BUFSIZ - m_lastPos);
>>                      ^
>> jni/Android/CSockReadStream.cpp:132:22: error: use of undeclared identifier 'read'
>>         int result = read(m_fd, m_readBuf, m_getPos);
>>                      ^
>> jni/Android/CSockReadStream.cpp:136:22: error: use of undeclared identifier 'read'
>>         int result = read(m_fd, m_readBuf + m_lastPos, m_getPos - m_lastPos);
>>                      ^
>>  error generated.
>> make: *** [obj/local/x86/objs/Game/Android/CAndroidReadFileStream.o] Error 1
>> jni/Android/CSockReadStream.cpp:141:22: error: use of undeclared identifier 'read'
>>         int result = read(m_fd, m_readBuf, READ_BUFSIZ);
>>                      ^
>> jni/source/Assets/CKLBTexturePacker.cpp:367:80: warning: format specifies type 'unsigned long' but the argument has type 'uintptr_t' (aka 'unsigned int') [-Wformat]
>>         fprintf(pFile, "==== Surface Alloc %8lX Size W:%i, H:%i Byte/Pix: %i ====\n", reinterpret_cast<uintptr_t>(this), m_width, m_height, m_currFormat);
>>                                            ~~~~                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>                                            %8X
>> 8 errors generated.
>> make: *** [obj/local/x86/objs/Game/Android/CSockReadStream.o] Error 1
>> 1 warning generated.
>> jni/Android/KLBOpenSLEngine.cpp:140:9: error: use of undeclared identifier 'usleep'
>>         usleep(16000);
>>         ^
>> 1 error generated.
>> make: *** [obj/local/x86/objs/Game/Android/KLBOpenSLEngine.o] Error 1
>> jni/Android/KLBOpenSLSoundAssetLoader.cpp:38:26: error: use of undeclared identifier 'F_OK'
>>         if (access(target_path, F_OK) != -1) {
>>                                 ^
>> jni/Android/KLBOpenSLSoundAssetLoader.cpp:67:3: error: use of undeclared identifier 'usleep'
>>                 usleep(30000); // sleep for 30ms
>>                 ^
>> 2 errors generated.
>> make: *** [obj/local/x86/objs/Game/Android/KLBOpenSLSoundAssetLoader.o] Error 1
>> jni/Android/CAndroidTmpFile.cpp:43:9: error: use of undeclared identifier 'close'
>>         close(m_fd);
>>         ^
>> jni/Android/CAndroidTmpFile.cpp:51:12: error: use of undeclared identifier 'write'
>>     return write(m_fd, ptr, size);
>>            ^
>> 2 errors generated.
>> make: *** [obj/local/x86/objs/Game/Android/CAndroidTmpFile.o] Error 1
>> jni/Android/CAndroidRequest.cpp:221:3: error: use of undeclared identifier 'unlink'; did you mean 'inline'?
>>                 unlink(fullpath);
>>                 ^
>> jni/Android/CAndroidRequest.cpp1 warning generated.
>> :505:15: error: use of undeclared identifier 'ioctl'
>>         int result = ioctl(fd, _IOW('a', 4 | (ANDROID_ALARM_ELAPSED_REALTIME << 4), struct timespec), ts);
>>                      ^
>> jni/Android/CAndroidRequest.cpp:507:2: error: use of undeclared identifier 'close'
>>         close(fd);
>>         ^
>> jni/Android/CAndroidRequest.cpp:646:9: warning: enumeration value 'BGMOVIEPLAYER' not handled in switch [-Wswitch]
>>         switch(type)
>>                ^
>> 1 warning and 3 errors generated.
>> make: *** [obj/local/x86/objs/Game/Android/CAndroidRequest.o] Error 1
>> 4 warnings and 18 errors generated.
>> make: *** [obj/local/x86/objs/Game/libs/SQLite/sqlite3.o] Error 1
>> 
>> FAILURE: Build failed with an exception.
>>