拥抱Android:编译python搭建移动的无线服务器平台
你想用废旧的Android手机作家庭服务器嘛?
其实并不难。以前,用Android SDK开发一个手机应用,安装下apk就可以host服务了,而现在就直接native化吧。
这篇文章会带你体验编译Python的过程,并用Python搭建可以带着跑的服务器。
首先,我们要开始在Arm的Android平台上编译Python。当然,你需要先准备好一台Linux的机器,然后从Android的官方网站下载并安装好Android NDK(最好SDK也装了)。
下载一些必要的代码包:
openssl-1.0.1j: http://www.openssl.org/source/
ncurses-5.9: http://ftp.gnu.org/gnu/ncurses/
readline 6.3: http://ftp.gnu.org/gnu/readline/
sqlite-autoconf-3080701: http://www.sqlite.org/download.html
python-2.7.8: https://www.python.org/downloads/release/python-278/
我们需要一个一个编译这些包:
1. common.sh:这个文件里包含一些基础设置,比如选用的GCC,CFLAGS和LDFLAGS如何配置。
export NDKDIR="/你的NDK路径比如/android-ndk-r10c" # GCC 版本选用,目前有4.6,4.8,4.9,选用时也注意Linux系统的类型,这里x86_64是六十四位 export COMPILER="$NDKDIR/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin" export CC="$COMPILER/arm-linux-androideabi-gcc" export CXX="$COMPILER/arm-linux-androideabi-g++" export CPP="$COMPILER/arm-linux-androideabi-cpp" export LD="$COMPILER/arm-linux-androideabi-ld" export AS="$COMPILER/arm-linux-androideabi-as" export AR="$COMPILER/arm-linux-androideabi-ar" export STRIP="$COMPILER/arm-linux-androideabi-strip" export OBJCOPY="$COMPILER/arm-linux-androideabi-objcopy" export OBJDUMP="$COMPILER/arm-linux-androideabi-objdump" export RANLIB="$COMPILER/arm-linux-androideabi-ranlib" export NM="$COMPILER/arm-linux-androideabi-nm" export STRINGS="$COMPILER/arm-linux-androideabi-strings" export READELF="$COMPILER/arm-linux-androideabi-readelf" # 选择要编译文件在哪个Android版本上使用,这里案例是在Android 4.2上使用,就是android 17;2.2对应Android 8,5.0对应Android 21 export ANDROID="$NDKDIR/platforms/android-17/arch-arm/usr" # 配置系统头文件和库文件位置 export CFLAGS="-I$ANDROID/include --sysroot=$ANDROID" export CXXFLAGS="-I$ANDROID/include --sysroot=$ANDROID" export CPPFLAGS="-I$ANDROID/include" export LDFLAGS="-L$ANDROID/lib"
2. 编译openssl:
tar zxf openssl-1.0.1j.tar.gz cd openssl-1.0.1j mkdir dist source common.sh MACHINE=armv7 SYSTEM=android ./config -fPIC --prefix=./dist # 在Makefile里做一些补丁,以防error sed -i "s|-m64||" Makefile sed -i "s|-Wall|-Wall --sysroot=$ANDROID|" Makefile # 编译并安装 make make install
3. 编译ncurses,readline,sqlite
仿照openssl的方法,编译另外三个库;其实还有一个zlib需要编译,当然后面不让python支持bz2就可以忽略。
注意readline编译最好选择--with-curses,然后把编译好的ncurses链接上。库类文件编译,尽量都加-fPIC,这是什么,不从汇编说还真说不清楚,还是大家自己去看官方文档吧。
对于localeconv的问题,大家最好改写下那个locale.h,在里面把localeconv的struct里fix放上你要的字符,比如decimal_point是".",这样后面都不会出这类locale的问题了。
这里给出快捷的解决方案就是把localeconv干掉,直接hardcode:
# 在ncurses编译之前,需要打的补丁 sed -i "s/#define isDecimalPoint(c) .*/#define isDecimalPoint(c) ((c) == '.')/" form/fty_num.c sed -i "s/localeconv()/NULL/" form/fty_num.c
4. 编译Python:
其实过程整体和openssl没有什么区别,细节上有一些注意事项。
- configure文件是需要手动fix的,打开文件,搜索 ac_cv_file__dev_ptmx 和 ac_cv_file__dev_ptc;删除对这两个变量的自动判断。手动去Android查看/dev文件夹里有没有ptmx和ptc设备,有就设置为yes没就no:
ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=no
- 打开Modules/Setup.dist文件,把需要的python模块前面的#去掉,比如#_socket socketmodule.c timemodule.c,要python支持网络socket接口,需要把#去掉;建议尽量多加一些包;实在编译不过的包不要,有些模块需要额外下载开源软件库编译,就不只openssl,ncurses,readline,sqlite了。
- 有一段编译会报错,仔细检查,发现python需要编译一个程序,这个程序跑在host上,但gcc是arm的,host linux是x86_64的,所以我们需要复制一份解压好的python代码,然后用本地原有的gcc编译;当然编译时直接./configure && make就可以了,直到Parser文件夹下出现了pgen这个可执行文件;把它拿出来,复制到另一个python源码的Parser文件夹中,修改Makefile:
sed -i "s|\$(PGEN):.*|\$(PGEN):|" Makefile sed -i "s|\$(CC) \$(OPT) \$(LDFLAGS) \$(PGENOBJS) \$(LIBS) -o \$(PGEN)|echo \"fake Parser/pgen\"|" Makefile
- 解决locale的问题,还有一些常量问题,笨方法hardcode:
sed -i "s|.*localeconv().*||" Objects/stringlib/localeutil.h sed -i "s|locale_data->grouping|\"\"|" Objects/stringlib/localeutil.h sed -i "s|locale_data->thousands_sep|\"\"|" Objects/stringlib/localeutil.h sed -i "s|.*localeconv().*||" Objects/stringlib/formatter.h sed -i "s|locale_data->grouping|\"\"|" Objects/stringlib/formatter.h sed -i "s|locale_data->thousands_sep|\"\"|" Objects/stringlib/formatter.h sed -i "s|locale_data->decimal_point|\".\"|" Objects/stringlib/formatter.h sed -i "s|.*localeconv().*||" Python/pystrtod.c sed -i "s|locale_data->decimal_point|\".\"|" Python/pystrtod.c sed -i "s|I_PUSH|0x5302|" Modules/posixmodule.c sed -i "s|p->pw_gecos|\"\"|" Modules/pwdmodule.c
- Modules/socketmodule.c: 需要去掉一些#if,不然头文件里没有定义,或者直接去$ANDROID的include文件夹把相应.h文件补充完整也可以。
... Py_BEGIN_ALLOW_THREADS #ifdef USE_GETHOSTBYNAME_LOCK PyThread_acquire_lock(netdb_lock, 1); #endif h = gethostbyaddr(ap, al, af); Py_END_ALLOW_THREADS ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af); #ifdef USE_GETHOSTBYNAME_LOCK PyThread_release_lock(netdb_lock); #endif return ret; ...
make然后make -i install,好啦,python编译出来啦!
下面就是放到android上跑了。
需要Android是root的,不root也可以,就是得找个地方放。
需要把python编译好的文件夹打包放到android上,还有sqlite里的那个so文件。
root的话可以在/system/bin里软链接一个python。当然,sqlite.so.3要放在/system/lib里。
其实sqlite是可以不编译的,但是我们的Django需要它,所以还是弄出来吧,ssl也可以不用,但是为了服务器支持https,还是编译下吧。
这样就可以运行python了。
# python >>> 1+2 3然后下载setuptools (https://pypi.python.org/pypi/setuptools/7.0) 和 pip (https://pypi.python.org/pypi/pip/1.5.6) 解压并安装:
tar zxf setuptools-7.0.tar.gz cd setuptools-7.0 python setup.py build python setup.py install tar zxf pip-1.5.6.tar.gz cd pip-1.5.6 python setup.py build python setup.py install把pip软链接到/system/bin。好了,python有了pip,哈哈,随心安装包吧。先来个pip install virtualenv
接下去可以安装django django-sslserver,把django-admin软链接到/system/bin,就可以写网站啦:
django-admin startproject test001 cd test001 python manage.py migrate python manage.py runserver 0.0.0.0:8000不安装django也可以直接对一个文件夹提供http服务:
python -m SimpleHTTPServer
有了server,在家庭里就可以搭建平台啦,如果有多个手机,连上wifi,就可以不用接线,完成无线分布式服务器,赶快练习loadbalance吧。
嗯嗯,看看需不需要用手机服务器随时监控家里的活动,然后插上SIM卡还能自动给我发短信,嘿嘿。
后面我们来想象怎么解决pip install有时需要编译c文件的问题。其实有团队已经解决了这个问题。
下载Droid for GCC plugin的apk:http://www.liqucn.com/rj/228351.shtml (这个不是官网,最好去google play下载)
把apk解压,然后找到gcc的压缩包,里面就有gcc了,把它放到Android上:
#include <stdio.h> int main() { printf("hello world!\n"); return 0; }然后gcc -o test test.c,并运行./test,完美输出hello world。赶紧软链接到/system/bin里吧。
好了,这样numpy都可以编译安装了。还可以编译下erl,把rabbitmq编译下,弄个分布式也不是问题。最好移植一下lxc,然后把raspberry里的arm版java搬过来就无敌啦。
总体来说,可以搭建移动服务器了,以后写一些网页版小应用,想用的时候android开个热点,电脑一连,开始enjoy!
让服务器无处不在吧,从家里开始~
2014.11.26
J.Y.Liu
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。