用Android NDK r6编译Python 3.2
转载请注明出处为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根目录。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库