AndroidではRPATH、RUNPATHともに無効

下記URLにもある通り、AndroidではRPATH、RUNPATHともに無効なようです。


実行バイナリからshared objectを利用したい場合、LD_LIBRARY_PATHでパスを指定するしかない。libc.soさえも同じ扱いのようですね。


bionic libcの手抜きってことなんでしょうか。面白いけどつらい。

Android Studioのアップデート時の作業メモ

Android StudioAndroid SDKをアップデートしたら既存プロジェクトをあれこれ直す必要があって、どれが必要だったのか自分でも整理できてないけどメモ

  • Android SDKを入れ直したので、「Project Structure」「Platform Aettings」「Android SDK」の「Android SDK location」を修正
  • 「Tools」「Android」「SDK Manager」から「Android Suport Library」をインストール
  • build.gradleを修正
  • gradle-wrapper.propertiesのdistributionUrlをgradle-1.9-bin.zipに
  • 「Sync Project with Gradle Files」

Expat 2.1.0をAndroid NDKでクロスコンパイルする

ExpatはXMLパーサーライブラリです。

http://sourceforge.net/projects/expat/files/ から expat-2.1.0.tar.gz をダウンロードします。

$ tar xvzf expat-2.1.0.tar.gz
$ cd expat-2.1.0
$ CFLAGS=-O2 LDFLAGS=-s ./configure --host=arm-linux-androideabi --prefix=$ANDROID_APP_ROOT/expat-2.1.0
$ make
$ make install

特に罠もなくビルドできます。

installed files

bin/xmlwf
include/*.h
lib/libexpat.a
lib/libexpat.la
lib/libexpat.so
lib/libexpat.so.1
lib/libexpat.so.1.6.0
lib/pkgconfig/expat.pc
share/man/man1/xmlwf.1

zsh 5.0.2をAndroid NDKでクロスコンパイルする

まずhttp://zsh.sourceforge.net/Arc/source.html から zsh-5.0.2.tar.bz2 をダウンロードします。

ビルドには ncurses, PCRE, libiconv の各ライブラリが必要です。以前の記事「ncurses 5.9をAndroid NDKでクロスコンパイルする」「PCRE 8.33をAndroid NDKでクロスコンパイルする」および「libiconv 1.14をAndroid NDKでクロスコンパイルする」を参照してください。

zshに含まれるconfig.subはAndroidのクロスコンパイル環境に対応していない古いものなので、libtoolのファイルをコピーしてからconfigureします。

また、_mktemp(3)を使わないようにするためconfigureに対して環境変数をセットします(理由は後述)。

さらに、Android 4.3時点ではttyname(3)は未実装であり、下記のようなエラーメッセージを出してNULLを返します。

char* ttyname(int)(3) is not implemented on Android

zshは内部的にttyname(3) を利用しているので、これを利用しないよう、パッチを当てた上でttyname(3)を使わないよう環境変数をセットします。

configure中で利用しているpcre-config(シェルスクリプト)にパスを通す必要もあります。

以上を反映したものが下記の実行例です。

$ tar xvjf zsh-5.0.2.tar.bz2
$ cd zsh-5.0.2
$ for i in `find . -name config.guess` ; do cp /usr/local/share/libtool/config/config.guess $i ; done
$ for i in `find . -name config.sub` ; do cp /usr/local/share/libtool/config/config.sub $i ; done
$ curl https://gist.github.com/hnw/6751590/raw/0297fdc1987130f67d3cde11dc76fa18276da3c8/zsh-5.0.2-android-patch.txt | patch -p1
$ autoreconf
$ PATH=$ANDROID_APP_ROOT/pcre-8.33/bin:$PATH CFLAGS="-O2 -I$ANDROID_APP_ROOT/ncurses-5.9/include -I$ANDROID_APP_ROOT/pcre-8.33/include -I$ANDROID_APP_ROOT/libiconv-1.14/include" LDFLAGS="-s -L$ANDROID_APP_ROOT/ncurses-5.9/lib -L$ANDROID_APP_ROOT/pcre-8.33/lib -L$ANDROID_APP_ROOT/libiconv-1.14/lib" ac_cv_func__mktemp=no ac_cv_func_ttyname=no ./configure --host=arm-linux-androideabi --prefix=$ANDROID_APP_ROOT/zsh-5.0.2 --with-term-lib=ncurses --disable-locale --disable-multibyte --enable-pcre
$ make
$ make install

Androidの_mktemp(3)について

Android NDK r9時点では、toolkitに含まれるlibcは_mktempという関数を含んでいるようで、configure中のチェックビルドでは_mktempシンボルを解決できてしまいます。

しかし、実際に_mktempを利用しているバイナリを実機で実行しようとすると下記のようなエラーが出てしまいます。

CANNOT LINK EXECUTABLE: cannot locate symbol "_mktemp" referenced by "/data/local/tmp/a.out"...

このように、AndroidのlibcとAndroid NDKのlibcとが異なっていることがあるようです。この手のトラブルは実機やエミュレータで動かしてみるまでわからないので、なかなか厄介です。

installed files

bin/zsh
bin/zsh-5.0.2
share/man/man1/*.1
share/zsh/5.0.2/functions/*

ncurses 5.9をAndroid NDKでクロスコンパイルする

http://ftp.gnu.org/pub/gnu/ncurses/ から ncurses-5.9.tar.gz をダウンロードします。

Androidでビルドするため、locale.hが存在しないかのようにconfigureに対して環境変数をセットする必要があります(理由は後述)。

それ以外は特に気をつける点はありません。下記の実行例の場合、C++バインディングを外す指示と*.soを作る指示を追加しています。

$ tar xvzf ncurses-5.9.tar.gz
$ cd ncurses-5.9
$ CFLAGS=-O2 LDFLAGS=-s ac_cv_header_locale_h=no ./configure --host=arm-linux-androideabi --prefix=$ANDROID_APP_ROOT/ncurses-5.9 --with-shared --without-cxx-binding
$ make
$ make install

Android NDKのロケールについて

Android NDK r9時点ではロケールの実装はスタブ実装になっています。ロケールが必要ならSDK使ってねという発想でしょうから、今後もNDKレベルで実装されることは無いでしょう。

それはそれでいいのですが、ロケール周りが下記のように中途半端なスタブ実装になっているため各種OSSのconfigureが混乱しがちです。

  • locale.h:ある
  • setloacle(3):ある、特に仕事はしない
  • LC_CTYPEなどのenum定数:ある
  • localeconv(3):ヘッダファイルでは定義されてるけど実体がないのでリンクに失敗する
  • lconv構造体:定義されてるけどメンバ数がゼロ

実際、ncursesはlocale.hが存在したらロケール周りがフル実装されていると判断するものの、localeconvが無いのでビルドが通りません。

Androidでのビルドということを考えると、一般論としては「configure --disable-locale」するのが正解だと言えます。ただし、ncursesのconfigureでは--disable-localeが提供されていないため、今回はlocale.hが存在しないかのようにautoconfのcache variableを環境変数として渡したというわけです。

installed files

bin/captoinfo
bin/clear
bin/infocmp
bin/infotocap
bin/ncurses5-config
bin/reset
bin/tabs
bin/tic
bin/toe
bin/tput
bin/tset
include/ncurses/*.h
lib/libform.a
lib/libform.so
lib/libform.so.5
lib/libform.so.5.9
lib/libform_g.a
lib/libmenu.a
lib/libmenu.so
lib/libmenu.so.5
lib/libmenu.so.5.9
lib/libmenu_g.a
lib/libncurses.a
lib/libncurses.so
lib/libncurses.so.5
lib/libncurses.so.5.9
lib/libncurses_g.a
lib/libpanel.a
lib/libpanel.so
lib/libpanel.so.5
lib/libpanel.so.5.9
lib/libpanel_g.a
lib/terminfo/
man/man?/*.?
share/tabset/*
share/terminfo/??/*

インストール時の注意

ロスコンパイル環境でもterminfoディレクトリは作られるんですが、なぜかMacOSX上でmake install.dataするとterminfoディレクトリの下に「31」のように2文字のディレクトリができてしまい、これをAndroidに持っていっても期待通りには動きません。

正しく動かすには、Android上でticコマンドを動かす必要があります。

libiconv 1.14をAndroid NDKでクロスコンパイルする

http://ftp.gnu.org/gnu/libiconv/ から libiconv-1.14.tar.gz をダウンロードします。

config.subが古いので、libtoolのファイルをコピーしてからconfigureします。

$ tar xvzf libiconv-1.14.tar.gz
$ cd libiconv-1.14
$ for i in `find . -name config.guess` ; do cp /usr/local/share/libtool/config/config.guess $i ; done
$ for i in `find . -name config.sub` ; do cp /usr/local/share/libtool/config/config.sub $i ; done
$ CFLAGS=-O2 LDFLAGS=-s ./configure --host=arm-linux-androideabi --prefix=$ANDROID_APP_ROOT/libiconv-1.14
$ make
$ make install

installed files

bin/iconv
include/*.h
lib/charset.alias
lib/libcharset.a
lib/libcharset.la
lib/libcharset.so
lib/libcharset.so.1
lib/libcharset.so.1.0.0
lib/libiconv.la
lib/libiconv.so
lib/libiconv.so.2
lib/libiconv.so.2.5.1
lib/preloadable_libiconv.so
share/doc/libiconv/*.html
share/man/man?/*.?

PCRE 8.33をAndroid NDKでクロスコンパイルする

http://sourceforge.net/projects/pcre/files/pcre/ から pcre-8.33.tar.bz2 をダウンロードします。

$ tar xvjf pcre-8.33.tar.bz2
$ cd pcre-8.33
$ CFLAGS=-O2 LDFLAGS=-s ./configure --host=arm-linux-androideabi --prefix=$ANDROID_APP_ROOT/pcre-8.33 --enable-jit --enable-utf
$ make
$ make install

installed files

bin/pcre-config
bin/pcregrep
bin/pcretest
include/*.h
lib/libpcre.a
lib/libpcre.la
lib/libpcre.so
lib/libpcre.so.1
lib/libpcre.so.1.2.1
lib/libpcrecpp.a
lib/libpcrecpp.la
lib/libpcrecpp.so
lib/libpcrecpp.so.0
lib/libpcrecpp.so.0.0.0
lib/libpcreposix.a
lib/libpcreposix.la
lib/libpcreposix.so
lib/libpcreposix.so.0
lib/libpcreposix.so.0.0.2
lib/pkgconfig/libpcre.pc
lib/pkgconfig/libpcrecpp.pc
lib/pkgconfig/libpcreposix.pc
share/doc/pcre/*
share/doc/pcre/html/*
share/man/man1/pcre-config.1
share/man/man1/pcregrep.1
share/man/man1/pcretest.1
share/man/man3/*.3