2010年08月26日

AndroidのNDKツールを使ってrubyをビルドして動かす

前回の知識を使ってNDKのツールで先日リリースされたruby-1.9.2をビルドしてAndroid上で動かしてみました。

(2011.7.21) アップデート記事を書きました。

RubyをAndroid用にビルドする



開発環境にはUbuntu 9.04 (x86_64)を使っています。

準備

ruby 1.9.2をクロスビルドするためには、そのホストでruby 1.9.2がインストールされている必要があります。(ビルド中に実行されるrubyスクリプトが1.9.2用になっているため。)

$ tar xvf ruby-1.9.2-p0.tar.bz2
$ mkdir obj
$ cd obj
$ ../ruby-1.9.2-p0.android/configure
$ make
$ sudo make install

Android用のビルド

基本的な手順は以下の通りです。

  1. 環境変数を設定した状態でconfigureスクリプトを実行してMakefileを生成する。
  2. makeして、コンパイルエラーをなんとか修正する。
  3. 仮のディレクトリへ make install
  4. 必要なファイルだけ実機にコピーする。

環境変数の設定

まずNDKをインストールしたディレクトリをNDK_TOPにセットします。

$ export NDK_TOP=/path/to/your/android-ndk-r4b
$ export SYSROOT=$NDK_TOP/build/platforms/android-4/arch-arm
$ export CFLAGS="-march=armv5te -msoft-float " 
$ export CC="$NDK_TOP/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/arm-eabi-gcc -mandroid --sysroot=$SYSROOT"

configureの実行

$ mkdir obj.android
$ cd obj.android
$ ../ruby-1.9.2-p0.android/configure --host=arm-eabi --disable-ipv6 --prefix=/system/local --enable-shared

これでうまくいけばよかったのですが、rubyのconfigureはクロスビルドに対応していない部分がありました。修正してなんとかできるようにしました。その修正点はこのページの最後に貼っておきます。

必ず --enable-shared をつけてください。これがないと一見正常にビルドが終了していてもrubyからネイティブのダイナミックリンクライブラリをdlopenした時に失敗します。

$ make

これで無事に最後までビルドできたら、いったん/system/localのディレクトリにインストールしてみます。

$ sudo mkdir -p /system/local
$ sudo make install

ここで、/system/local/binと/system/local/lib以下のファイルだけ実機にコピーします。インクルードヘッダやドキュメントは不要です。

普通はadb push コマンドを使うところですが、私の場合は実機のファイルシステムはNFSマウントしているので以下のようにコピーしました。

$ sudo cp -a /system/local/bin /export/android/root/system/local/
$ sudo cp -a /system/local/lib /export/android/root/system/local/

/system/local/lib/libruby.so はシステムのライブラリパスが通っているディレクトリに置く必要があります。今回はシンボリックリンクを張りました。

実機のshellで

# cd /system/lib
# ln -s ../local/lib/libruby.so libruby.so

Android上でRubyを実行

ためしにirbを起動してみます。

# /system/local/bin/irb
irb(main):001:0> p RUBY_VERSION
"1.9.2"
=> "1.9.2"
irb(main):002:0> 

RubyでのHTTPサーバの実行

このページを参考にして、以下のプログラムを動かしてみました。

#!/system/local/bin/ruby
require 'webrick'
include WEBrick

s = HTTPServer.new(
  :Port => 8001,
  :DocumentRoot => File.join("/data/local/exp", "public_html")
)
trap("INT"){ s.shutdown }
s.start

このファイルを実機にコピーして

# ./httpserver1.rb
[1970-01-01 05:32:46] INFO  WEBrick 1.3.1
[1970-01-01 05:32:46] INFO  ruby 1.9.2 (2010-08-18) [arm-eabi]
[1970-01-01 05:32:46] INFO  WEBrick::HTTPServer#start: pid=287 port=8001
192.168.1.26 - - [01/Jan/1970:05:33:11 GMT] "GET / HTTP/1.1" 304 0
- -> /

PCからこの実機のURLをブラウザで開いて表示できることも確認できました。

実機を起動したときに自動的にこのHTTPサーバを起動するには/init.rcにserviceとして登録すればよいです。例えば

service httpd /system/bin/logwrapper /data/local/exp/httpserver1.rb

このようにlogwrapperを経由して起動するとstdout, stderrへの出力をlogcatで見ることができます。

ruby-1.9.2-p0のソースに加えた修正

diff -u -r ruby-1.9.2-p0/configure ruby-1.9.2-p0.android/configure
--- ruby-1.9.2-p0/configure	2010-08-18 14:56:27.000000000 +0900
+++ ruby-1.9.2-p0.android/configure	2010-08-19 11:36:01.000000000 +0900
@@ -13525,7 +13525,9 @@
   $as_echo_n "(cached) " >&6
 else
   if test "$cross_compiling" = yes; then :
-  as_fn_error "cannot check setpgrp when cross compiling" "$LINENO" 5
+  #as_fn_error "cannot check setpgrp when cross compiling" "$LINENO" 5
+  # hack for Android
+  ac_cv_func_setpgrp_void=yes
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -15046,7 +15048,10 @@
     	LDFLAGS="$LDFLAGS -Zomf"
 			 ;; #(
   *) :
-     	: ${LDSHARED='ld'} ;;
+#     	: ${LDSHARED='ld'} ;;
+# hack for Android
+     	: ${LDSHARED='$(CC) -shared'} ;;
+
 esac
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rb_cv_dlopen" >&5
 $as_echo "$rb_cv_dlopen" >&6; }
diff -u -r ruby-1.9.2-p0/dir.c ruby-1.9.2-p0.android/dir.c
--- ruby-1.9.2-p0/dir.c	2010-08-09 13:39:57.000000000 +0900
+++ ruby-1.9.2-p0.android/dir.c	2010-08-19 13:17:16.000000000 +0900
@@ -700,8 +700,14 @@
 static VALUE
 dir_set_pos(VALUE dir, VALUE pos)
 {
+/* hack for Android*/
+#ifdef HAVE_SEEKDIR
     dir_seek(dir, pos);
     return pos;
+#else
+    rb_notimplement();
+#endif
+
 }
 
 /*
diff -u -r ruby-1.9.2-p0/eval_intern.h ruby-1.9.2-p0.android/eval_intern.h
--- ruby-1.9.2-p0/eval_intern.h	2010-06-03 18:58:32.000000000 +0900
+++ ruby-1.9.2-p0.android/eval_intern.h	2010-08-19 11:45:39.000000000 +0900
@@ -214,8 +214,12 @@
 void rb_trap_restore_mask(void);
 
 #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
+#ifdef __ANDROID__
+#define CharNext(p) ((p) + 1)
+#else
 #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
 #endif
+#endif
 
 #if defined DOSISH || defined __CYGWIN__
 static inline void
diff -u -r ruby-1.9.2-p0/ext/nkf/nkf-utf8/nkf.h ruby-1.9.2-p0.android/ext/nkf/nkf-utf8/nkf.h
--- ruby-1.9.2-p0/ext/nkf/nkf-utf8/nkf.h	2010-04-22 17:04:13.000000000 +0900
+++ ruby-1.9.2-p0.android/ext/nkf/nkf-utf8/nkf.h	2010-08-19 11:41:13.000000000 +0900
@@ -164,6 +164,10 @@
 # ifndef HAVE_LOCALE_H
 #  define HAVE_LOCALE_H
 # endif
+#elif defined(__ANDROID__)
+# ifndef HAVE_LOCALE_H
+#  define HAVE_LOCALE_H
+# endif
 #else
 # ifndef HAVE_LANGINFO_H
 #  define HAVE_LANGINFO_H
diff -u -r ruby-1.9.2-p0/include/ruby/intern.h ruby-1.9.2-p0.android/include/ruby/intern.h
--- ruby-1.9.2-p0/include/ruby/intern.h	2010-05-01 02:56:23.000000000 +0900
+++ ruby-1.9.2-p0.android/include/ruby/intern.h	2010-08-19 11:02:12.000000000 +0900
@@ -28,6 +28,9 @@
 #endif
 #include "ruby/st.h"
 
+#ifdef __ANDROID__
+#include <sys/select.h>
+#endif
 /*
  * Functions and variables that are used by more than one source file of
  * the kernel.

NDKのヘッダに加えた修正

diff -u pthread.h.org pthread.h
--- pthread.h.org	2010-08-16 17:00:54.000000000 +0900
+++ pthread.h	2010-08-16 17:01:25.000000000 +0900
@@ -87,6 +87,7 @@
  */
 #define PTHREAD_COND_INITIALIZER  {0}
 
+#define PAGE_SIZE 0x400
 #define PTHREAD_STACK_MIN (2 * PAGE_SIZE)
 
 #define PTHREAD_CREATE_DETACHED  0x00000001
diff -u linux/in.h.org linux/in.h
--- linux/in.h.org	2010-08-20 10:53:29.000000000 +0900
+++ linux/in.h	2010-08-20 10:53:45.000000000 +0900
@@ -29,7 +29,7 @@
  IPPROTO_RSVP = 46,
  IPPROTO_GRE = 47,
 
- IPPROTO_IPV6 = 41,
+ /*IPPROTO_IPV6 = 41,*/
 
  IPPROTO_ESP = 50,
  IPPROTO_AH = 51,


トラックバックURL

トラックバック一覧

1. [android]ruby on android  [ 組み込みの人。 ]   2010年08月26日 12:56
http://code.google.com/p/android-ruby/ そのうちやってみたいなと思っていたことをすでにやっている人がいました。 オープンソースって素晴らしい。 2010.8.26 追記 自分でもやってみました。 KMC Staff Blog:AndroidのNDKツールを使ってrubyをビルドして動かす
2. KZM-CA9-01ボードのリンク集  [ KMC Staff Blog ]   2010年09月16日 10:44
4コアのCortex-A9のKZM-CA9-01ボードを使って実験したことを書いたページをまとめてみました。

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード