8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NDKは嫌だと思う人へ:NDKを便利に利用するツールandroid-gcc-toolchain

Last updated at Posted at 2016-09-30

直感で、一個コマンドだけで、テスト用のC/C++ファイルをAndroid版にコンパイルしたい:
android-gcc-toolchain gcc a.c

NDKは独自のmkファイルは便利ですが、世の中、いろんなオープンソースは伝統的なMakefileやautoconfやCMakeやGYPなどで構成されています。
これらのプロジェクトをAndroid版にコンパイルするには、Standalone Toolchain(むしろ標準toolchainといった方が良い)の登場です。

NDKは、確かに$NDK/build/tools/make_standalone_toolchain.py(古いバージョンは$NDK/build/tools/make-standalone-toolchain.sh)を提供していた。
これで標準toolchainを作成できますが、いくつか不便なところがあります:

  • toolchainを作成した後、自分でPATHや、CCなど環境変数をいちいち設定しないといけない
  • toolchain作成は遅い
  • arm,arm64などarchの間での切り替えは不便
  • ccache取り込んでいない
  • ... つまり、もっと自動化できるのに... 

私は我慢できませんので、ツールandroid-gcc-toolchainを作成しました。

何ができるの? 以下、android arm64版を例として簡単に説明します。arm64を省略すれば普通のarm(32bit)になります。

1. Androidのgccなどコマンドを簡単に実行できる.

  • コマンドの前にandroid-gcc-toolchainを入れば良い。arch(arm,arm64,x86,x64,mips,mip64)を指定できます。デフォルトはarm(32bit)。

    android-gcc-toolchain arm64 gcc a.c
    android-gcc-toolchain arm64 g++ -v a.cc
    android-gcc-toolchain arm64 g++ --help
    android-gcc-toolchain arm64 clang++ -c a.c
    android-gcc-toolchain arm64 which gcc
    android-gcc-toolchain arm64 objdump -h a.out
    android-gcc-toolchain arm64 sh -c 'git checkout v1.0 && make clean && make'
    

    gccなどコマンドのパラメータは元のコマンドのと変わらない。

    実際は、どんなコマンドでも良いが、以下のgcc関連コマンドは全部Android版にリライレクトされます:

    • gcc g++ cc c++ clang clang++ ar as ranlib ld strip nm ...
    • readelf objdump c++filt elfedit objcopy strings size ...

2. クロスコンパイル用bashに簡単に入れます

  • 対話式のbashなどshellに入る、gccなど関連コマンドをご利用いただけます。

    $ android-gcc-toolchain arm64
     -------------------------------------------------------
     android-9-arm toolchain is ready! The bin dir($BIN) is:
      $NDK/std-toolchains/android-9-arm/bin
    
     PATH=$BIN:$PATH. Toolchain commands can be used directly:
      gcc g++ cc c++ clang clang++ ar as ranlib ld strip nm ...
      readelf objdump c++filt elfedit objcopy strings size ...
    
    [android-9-arm] このプロムプトの後ろにコマンドを入力してください。
    

    上記でガイド表示完了。gccの場所を確認してみたり、コンパイルしたり試してみます:

    [android-9-arm] which gcc
    /Users/q/Library/Android/sdk/ndk-bundle/std-toolchains/android-9-arm/bin/gcc
    [android-9-arm] gcc a.c
    

    もちろん、後ろにzshなどを追加すれば、bashの代わりにzshにも入れます。

    android-gcc-toolchain arm64 zsh
    

    また、PATHでgccなどオーバライドするの代わりに、次のように、$CC系環境変数、$CC_target系環境変数設定済みの環境にも入れます。

  • $CCなどを設定済みの環境にも入れます;

    android-gcc-toolchain arm64 -c
    

    これで自動的に以下の変数が設定されます:

    export BIN=$NDK/std-toolchains/android-21-arm64/bin
    export CC=$BIN/gcc
    export CXX=$BIN/g++
    export LINK=$BIN/g++
    export AR=$BIN/ar
    export AS=$BIN/as
    export RANLIB=$BIN/ranlib
    export LD=$BIN/ld
    export STRIP=$BIN/strip
    export NM=$BIN/nm
    

    $BINは当時のtoolchainのbinフォルダです。

  • $CC...の代わりに、$CC_target...などを自動的に設定する環境にも入れます。

    android-gcc-toolchain arm64 -C
    

    CC_target CXX_target LINK_target AR_target AS_target RANLIB_target LD_target STRIP_target NM_targetは設定されます。

3. 普通のMakefileや、AUTOCONF project(e.g. ffmpeg)は簡単にビルドできます.

  • gccリダイレクトされた環境でビルド。例

    Makefileあり:

    android-gcc-toolchain arm64 make
    

    autoconf系:

    OTHER_FFMPEG_OPTIONS="--disable-everything --disable-doc --enable-protocol=pipe --enable-filter=scale --enable-filter=crop --enable-filter=transpose --enable-demuxer=rawvideo --enable-decoder=rawvideo --enable-muxer=image2 --enable-muxer=image2pipe --enable-muxer=mjpeg --enable-encoder=mjpeg --enable-encoder=png"
    android-gcc-toolchain arm64 <<< "./configure --enable-cross-compile --target-os=linux --arch=arm64 $OTHER_FFMPEG_OPTIONS && make"
    
  • $CC...設定済の環境でビルドしてもいいです。

    android-gcc-toolchain arm64 -c make
    

4. GYPで構成されたプロジェクト(NodeJSやV8)を簡単にビルドできます

幾つか方法があります:

  • gccリダイレクトされた環境でビルド

    android-gcc-toolchain arm64 <<< "./configure --dest-cpu=arm64 --dest-os=android --without-snapshot --without-inspector --without-intl && make"
    
  • $CC`...設定済の環境でビルド.

    android-gcc-toolchain arm64 -c <<< "./configure --dest-cpu=arm64 --dest-os=android --without-snapshot --without-inspector --without-intl && make"
    
  • $CC_target...設定済の環境でビルド.

    android-gcc-toolchain arm64 -C <<< "./configure --dest-cpu=arm64 --dest-os=android && make"
    

    このモード、Host側(ローカルマシン)実行ファイルとtarget(Android)側実行ファイル両方を作成する場合に必須です。ちなみに、上記のコマンドはNodeJSの設定エラーで通らないので、詳しくはbuild-nodejs-for-android-perfectlyを参照ください。

5. 自動的にAndroid API levelのmin/maxを取得する。

  • デフォルトはminですが、--api maxを指定すれば実際のNDKフォルダ構造からそのarchのmax Android API levelを取得する。例:

    $ android-gcc-toolchain arm64 --api max
      ...
      android-24-arm64 toolchain is ready! ...
    

6. 初めてはToolchainを自動的に作成します.

  • 既存の$NDK/build/tools/make_standalone_toolchain.pyのオプションを継承しています:
    --arch,--api, --stl,--force,--verbose.

7. Toolchain作成はすごく早い!ハードリンクを利用するようにハッキングした。

  • This is done by run a modified py file on-the-fly instead of original $NDK/build/tools/make_standalone_toolchain.py.
  • The modified py file replace shutil.copy2 and shutil.copytree with customized copy2 and copytree which use hard link.
  • You can specify --copy to force use traditional copy mode.

8. コンパイルキャッシュツールCCACHEをサポート

  • 繰り返してclean&makeの場合はCCACHEをお勧めです。brew install ccacheあるいはsudo apt-get -y install ccache。そして一回export USE_CCACHE=1で済む。 (これでandroid-gcc-toolchainに「CCACHEを利用する」と伝えます)

すごく速くなります!

9. Docker image準備できました(Docker image id: osexp2000/android-gcc-toolchain)。サイズはお得です!

このDocker imageの中に、NDKは入っていますが、膨大な1.3Gのplatformsフォルダをわずか27Mのplatforms.7zに圧縮した、フォルダを空っぽにした。デフォルト以外のtoolchainを利用しようとする時に、動的にで展開&削除。

これで、Docker imageのダンロードサイズを約1Gから410Mに縮小しました。(7zありがとう!)

このDocker imageを利用する方法はご自由に、例えば:

現在フォルダ($PWD)下にあるファイルa.ccをコンパイルしたい:

  • gccリライレクトされた対話環境で:

    $ docker run -it -v $PWD:/work osexp2000/android-gcc-toolchain arm64
    [android-21-arm64] cd /work && gcc a.cc -o result_exe
    
  • one-lineで

    docker run -v $PWD:/work osexp2000/android-gcc-toolchain arm64 g++ /work/a.cc -o /work/result_exe 
    
  • 複数コンパイルをコマンンド併用

    docker run -i -v $PWD:/work osexp2000/android-gcc-toolchain arm64 <<< "cd /work && g++ a.cc -o result_exe" 
    
  • 複数コンパイルをコマンンド併用(Here Document)

    docker run -i -v $PWD:/work osexp2000/android-gcc-toolchain arm64 <<EOF
    cd /work && g++ a.cc -o result_exe
    EOF
    

    Windows上Docker-machineを利用している場合、MINGW(例えばGit Bash)を利用ください。$PWDは必ずC:¥Usersの配下にしてください(例C:¥Users¥q¥Downloads)。また、環境変数MSYS_NO_PATHCONV=1も必要です。

10. すべてのコンパイル関連のコマンドの実際のパラメータを表示する。これは極便利な機能です。

  • 環境変数AGCC_VERBOSEを1に設定する(export AGCC_VERBOSE=1)または、-v or --verboseオプションをandroid-gcc-toolchainコマンンドに渡せばいい。

    コンパイル関連コマンドとは、gcc g++ cc c++ clang clang++ ar as ranlib ld strip nmです。(当然、android-gcc-toolchainから直接か間接的に起動されたもののみ)

    出力サンプル。

    $___ ccache '....../arm-linux-androideabi-c++' \
    $___     '-D_GLIBCXX_USE_C99_MATH' \
    $___     '-I../deps/gtest' \
    $___     '-I../deps/gtest/include' \
    $___     '-Wall' \
    $___     '-Wextra' \
    $___     '-Wno-unused-parameter' \
    $___     '-Wno-missing-field-initializers' \
    $___     '-O3' \
    $___     '-fno-omit-frame-pointer' \
    $___     '-fPIE' \
    $___     '-fno-rtti' \
    $___     '-fno-exceptions' \
    $___     '-std=gnu++0x' \
    $___     '-MMD' \
    $___     '-MF' \
    $___     '....../gtest-filepath.o.d.raw' \
    $___     '-c' \
    $___     '-o' \
    $___     '....../gtest-filepath.o' \
    $___     '../deps/gtest/src/gtest-filepath.cc'
    

    $___はgrepしやすいためです。どうせ空ですから、コピーペにも問題ありません。

... 実際は、もっとあります。

詳しくはhttps://github.com/sjitech/android-gcc-toolchainへ。

ちなみに、Windows版でのご利用はMINGW(例えばGIT Bash)が必要です。

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?