轉載請註明出處為KlayGE遊戲引擎
本文的目的不是為了完整地把Python 3.2移植到Android,只是希望編譯出能用在自己程式裡的連結庫。
完成boost 1.47的移植之後,下一個目標就是Python 3.2。目前Python只有2.6.2非官方地移植到了Android(見P4A),他們遲遲不開始移植3.x,主要原因是他們認為3.x沒用-_-。看來這件事情只能自己做了。由於Python 3.x和之前的版本有著巨大的區別,其難度完全不可預測。
準備工作
需要下載
configure
按照linux平臺的老習慣,很多配置是寫在.in檔案中,需要用configure來生成出對應的.c或者.h。這裡需要特別注意的是,需要讓configure用NDK的工具鏈:
./configure –host=arm-linux-androideabi CC=arm-linux-androideabi-gcc CPPFLAGS=”-I$ANDROID_NDK/platforms/android-9/arch-arm/usr/include -I$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/include -I$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include -I$ANDROID_NDK/sources/crystax/include” CFLAGS=”-nostdlib” LDFLAGS=”-Wl,-rpath-link=$ANDROID_NDK/platforms/android-9/arch-arm/usr/lib -L$ANDROID_NDK/platforms/android-9/arch-arm/usr/lib” LIBS=”-lc”
其中$ANDROID_NDK是環境變數,指向NDK的根目錄。
經過configure,pyconfig.h、config.c等檔案被生成出來了。需要手工把pyconfig.h拷貝到Include目錄下。
工程檔案
和boost不一樣的是,python沒有自帶bjam這樣的編譯工具,所以得自己建立一個Android.mk。我拿了P4A的Android.mk進行一番修改,加入3.2新增的一些.c檔案。
打補丁
P4A提供了一個Python-2.6.2-android.patch,但僅僅適用於2.6.2,畢竟3.x和2.x差異太大了。這裡需要修改Python 3.2的原始碼,手工把一個個補丁打上。注意pyconfig.h和config.c就不用改了。
編譯
ndk-build進行編譯,剛開始一切順利,接著問題出現。首先出現編譯錯誤的是Objects/unicodeobject.c。在有 wchar的情況下,它需要有PY_FORMAT_LONG_LONG的定義。但不知為何,configure並沒有生成正確的 PY_FORMAT_LONG_LONG。於是我加上了一行
#define PY_FORMAT_LONG_LONG "ll"
接著Modules/posixmodule.c編譯錯誤。經過細緻的檢查,我發現是因為在configure生成pyconfig.h中,包含了
#define HAVE_DEV_PTMX 1
但在P4A的pyconfig.h中,這裡是
#undef HAVE_DEV_PTMX
可能的原因似乎Cygwin支援/dev/ptmx,但Android不支援。所以configure根據Cygwin的情況就錯誤地定義了HAVE_DEV_PTMX。同樣多情況還有HAVE_KILLPG,也得#undef掉。
最棘手的當屬Modules/posixmodule.c說找不到fdatasync的編譯錯誤。這個函式定義在$ANDROID_NDK /platforms/android-9/arch-arm/usr/include/unistd.h中,這個目錄也已經新增到了 Android.mk中,不應該找不到才對。通過使用ndk-build NDK_LOG=1 V=1來仔細檢視每個步驟發現,NDK預設使用了android-3的API,即使你定義了LOCAL_C_INCLUDES也沒用。所以它其實包含的是 android-3下的unistd.h,而android-3是不支援fdatasync的,那個函式被放在#if 0中。於是我不得不新增了一個Application.mk,內容只有一行:
APP_PLATFORM := android-9
至此,Python 3.2已經可以用NDK編譯,生成libpython3.2.so了。
還能用VC編譯嗎?
我仍然希望同一份原始碼也能用VC編譯生成Windows版的Python。這基本上只有一個問題,Android的pyconfig.h和 Windows的pyconfig.h不同。於是我把前者命名為pyconfig.android.h,後者命名為pyconfig.win.h,並分別 在編譯指令碼和Pre-Build Event裡把對應的pyconfig.xxx.h覆蓋拷貝成pyconfig.h。這樣一來,不同的編譯系統就都可以順利編譯了。
合在一起
在附件裡面你可以找到所有我修改過的檔案。在編譯之前,你必須設定一個環境變數,名字為“ANDROID_NDK”,只想你的NDK根目錄。