Androidを載せたbeagleboard-xmをTimeMachine用のNASにするまで(其の弐)
avahiのポーティング
avahi-daemonをbeagleboard-xm上のAnroidで動作するようにポーティングする。
toolchainはberkeley DBのビルドの時と同じようにcodesourceryからもってきたarm-none-linux-gnueabiのコンパイラを使う。ライブラリ群はandroid上のものと異なるのですべてstatic linkする。
https://sourcery.mentor.com/sgpp/lite/arm/portal/release324
依存ライブラリの準備
avahiをビルドするために必要なexpatとlibdaemonをビルドする。
expat
XML処理用のライブラリ。expat。
これはAndroidをビルドしたときに使ったrowboatソースツリーの中に入っていたのでそれを使うことにした。ただ、通常は共有ライブラリとしてビルドされているので、staticなライブラリとしてビルドしなおした。
external/expat/Android.mkの末尾を$(BUILD_SHARED_LIBRARY)から$(BUILD_STATIC_LIBRARY)に変更してmm。out/target/product/beagleboard/obj/STATIC_LIBRARIES/libexpat_intermediatesにlibexpat.aができるので、これを適当なフォルダにコピーしておく。今回は~/lib.myFroyo/libexpat.aとした。
libdaemon
デーモンプログラムを作るときにユーティリティ的に使えるライブラリ。これはAndroidのソースツリーに入っていないのでサイトからダウンロードしてきてビルドする。バージョンは0.14を使った。
クロスコンパイル用のオプション付きでconfigureをしてmakeするわけだが、そのままのconfigureでは実行時にエラーする。TARGET環境にはないコマンド(setpgrp)を使ったチェックロジックを実行しようとする部分が問題なので、その箇所をコメントアウトした。
$ diff configure configure.org 13786a13787,13860 > { $as_echo "$as_me:$LINENO: checking whether setpgrp takes no argument" >&5 > $as_echo_n "checking whether setpgrp takes no argument... " >&6; } > if test "${ac_cv_func_setpgrp_void+set}" = set; then > $as_echo_n "(cached) " >&6 > else > if test "$cross_compiling" = yes; then > { { $as_echo "$as_me:$LINENO: error: cannot check setpgrp when cross compiling" >&5 > $as_echo "$as_me: error: cannot check setpgrp when cross compiling" >&2;} > { (exit 1); exit 1; }; } > else > cat >conftest.$ac_ext <<_ACEOF > /* confdefs.h. */ > _ACEOF > cat confdefs.h >>conftest.$ac_ext > cat >>conftest.$ac_ext <<_ACEOF > /* end confdefs.h. */ > $ac_includes_default > int > main () > { > /* If this system has a BSD-style setpgrp which takes arguments, > setpgrp(1, 1) will fail with ESRCH and return -1, in that case > exit successfully. */ > return setpgrp (1,1) != -1; > ; > return 0; > } > _ACEOF > rm -f conftest$ac_exeext > if { (ac_try="$ac_link" > case "(($ac_try" in > *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; > *) ac_try_echo=$ac_try;; > esac > eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" > $as_echo "$ac_try_echo") >&5 > (eval "$ac_link") 2>&5 > ac_status=$? > $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 > (exit $ac_status); } && { ac_try='./conftest$ac_exeext' > { (case "(($ac_try" in > *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; > *) ac_try_echo=$ac_try;; > esac > eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" > $as_echo "$ac_try_echo") >&5 > (eval "$ac_try") 2>&5 > ac_status=$? > $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 > (exit $ac_status); }; }; then > ac_cv_func_setpgrp_void=no > else > $as_echo "$as_me: program exited with status $ac_status" >&5 > $as_echo "$as_me: failed program was:" >&5 > sed 's/^/| /' conftest.$ac_ext >&5 > > ( exit $ac_status ) > ac_cv_func_setpgrp_void=yes > fi > rm -rf conftest.dSYM > rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext > fi > > > fi > { $as_echo "$as_me:$LINENO: result: $ac_cv_func_setpgrp_void" >&5 > $as_echo "$ac_cv_func_setpgrp_void" >&6; } > if test $ac_cv_func_setpgrp_void = yes; then > > cat >>confdefs.h <<\_ACEOF > #define SETPGRP_VOID 1 > _ACEOF > > fi 15430,15431c15504 < ac_cr=' < ' --- ' ac_cr='
configureのオプションは下記のとおり。
./configure --host=arm-none-linux-gnueabi CC=arm-none-linux-gnueabi-gcc CFLAGS="--sysroot=/android/toolchain/arm/arm-none-linux-gnueabi/libc/" LDFLAGS="--sysroot=/android/toolchain/arm/arm-none-linux-gnueabi/libc/ -static"
makeを実行してできあがる.libs/libdaemon.aを適当なフォルダにコピーしておく。今回はlib.mybuild/libdaemon.aとした。
avahiのconfigure
クロスコンパイル用にオプション設定してconfigureを実行する。
ポイントは下記。
- static linkされるようにLDFLAGSに"-Wl,-Bstatic"と"-static"。ふつうは"-static"だけでいいはずだがなぜかリンカのオプションに反映されなかったので"-Wl"で直接"-Bstatic"をリンカに渡すようにした。
- libgccに依存しないようにLDFLAGSに"-static-libgcc"。
- ビルドの対象を必要最低限にするように--disable-XXXで不要な機能を無効化。dbusもとりえあず無効にした。(dbusはrowboatのソースツリーに入っているのでもし必要であれば有効にできるはず)
- avahiの実行ユーザ、グループをrootにするように--with-avahi-userと--with-avahi-grouで設定。これをしないとavahiという名前のユーザ、グループが必要になる。android上ではユーザ追加が簡単にできない(というかやり方をしらない。/etc/passwd方式じゃない)のでrootにしておく。
- インストール先のディレクトリをprefixで/data/avahiに指定。このディレクトリ配下で設定ファイル等を探しにいくことになるためデフォルト(/usr/local)から変更しておく。
./configure --host=arm-none-linux-gnueabi CC=arm-none-linux-gnueabi-gcc CFLAGS="-I/android/include.myFroyo/expat -I/android/include.myFroyo/dbus -I/android/libdaemon/libdaemon-0.14 --sysroot=/android/toolchain/arm/arm-none-linux-gnueabi/libc" LDFLAGS="-Wl,-Bstatic -static -static-libgcc -lpthread -L/android/lib.myFroyo -L/android/libdaemon/libdaemon-0.14/libdaemon/.libs --sysroot=/android/toolchain/arm/arm-none-linux-gnueabi/libc" --with-distro=none --disable-qt3 --disable-qt4 --disable-gtk --disable-gtk3 --disable-gdbm --disable-python --disable-pygtk --disable-python-dbus --disable-mono --disable-monodoc --disable-doxygen-doc --disable-doxygen-dot --disable-manpages --disable-dbus --prefix=/data/avahi --with-avahi-user=root --with-avahi-group=root
ソースの修正
avahi-daemon/main.cで実行ユーザ、グループの情報をgetpwnam()、getprnam()でとってきて使おうとするがandroid上ではうまくいかない(/etc/passwdを使わない独自形式のユーザ管理のためか?)ので、この処理に依存する部分をコメントアウトした。
static int make_runtime_dir(void) { int r = -1; mode_t u; int reset_umask = 0; struct passwd *pw; struct group * gr; struct stat st; #if 0 if (!(pw = getpwnam(AVAHI_USER))) { avahi_log_error( "Failed to find user '"AVAHI_USER"'."); goto fail; } if (!(gr = getgrnam(AVAHI_GROUP))) { avahi_log_error( "Failed to find group '"AVAHI_GROUP"'."); goto fail; } #endif u = umask(0000); reset_umask = 1; if (mkdir(AVAHI_DAEMON_RUNTIME_DIR, 0755) < 0 && errno != EEXIST) { avahi_log_error("mkdir(\""AVAHI_DAEMON_RUNTIME_DIR"\"): %s", strerror(errno)); goto fail; } #if 0 chown(AVAHI_DAEMON_RUNTIME_DIR, pw->pw_uid, gr->gr_gid); #endif if (stat(AVAHI_DAEMON_RUNTIME_DIR, &st) < 0) { avahi_log_error("stat(): %s\n", strerror(errno)); goto fail; } #if 0 if (!S_ISDIR(st.st_mode) || st.st_uid != pw->pw_uid || st.st_gid != gr->gr_gid) { avahi_log_error("Failed to create runtime directory "AVAHI_DAEMON_RUNTIME_DIR"."); goto fail; } #endif r = 0; fail: if (reset_umask) umask(u); return r; }
build
configureができたらbuild。
ARM用のstatic linkされたバイナリができていることを確認する。
$ file ./avahi-daemon ./avahi-daemon: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.14, not stripped $ readelf -d ./avahi-daemon There is no dynamic section in this file.
うまくstatic linkできていないと下記のように表示される。
LDFLAGSが-staticだけのとき $ readelf -d avahi-daemon Dynamic section at offset 0x64588 contains 28 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libgcc_s.so.1] 0x00000001 (NEEDED) Shared library: [libpthread.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x00000001 (NEEDED) Shared library: [ld-linux.so.3] 0x0000000c (INIT) 0x9c10 0x0000000d (FINI) 0x5efc8 ... LDFLAGSが-staticと-static-libgccのとき $ readelf -d avahi-daemon Dynamic section at offset 0x66588 contains 27 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libpthread.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x00000001 (NEEDED) Shared library: [ld-linux.so.3] 0x0000000c (INIT) 0x9c64 0x0000000d (FINI) 0x608cc ...
実行
avahi-daemon/avahi-daemon.confをとりあえずデフォルトのままandroidの/data/avahi/etc/avahi-daemon.confにコピーしておく。あと、httpdのサービスが立ち上がっていると仮定して、/data/avahi/etc/services/http.serviceファイルを作っておく。下記のような感じで。
<?xml version="1.0" standalone='no' ?> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">%h</name> <service> <type>_http._tcp</type> <port>80</port> </service> </service-group>
あとpidファイルを置くための/data/avahi/var/run/avahi-daemonフォルダを作っておく。(作っておかないと実行時にmkdirできないというエラーが出る)
avahi-daemon実行ファイルもandroidにコピーして実行する。PC(Ubuntu)からavahi-browseでandroidのhttpdサービスを見つけることができた。
$ avahi-browse -r _http._tcp -t + eth0 IPv4 linux Web Site local + eth0 IPv4 mywebserver Web Site local = eth0 IPv4 linux Web Site local hostname = [linux.local] address = [192.168.1.200] port = [80] txt = [] = eth0 IPv4 mywebserver Web Site local hostname = [lynx.local] address = [192.168.1.100] port = [80] txt = []
avahiのインストールはこれでできたっぽい。