1 移植需求
需求:在Arm9上运行python2.5.4。
ARM Target环境:
S3C2410A & arm-linux-2.4.18,和 AT91SAM9261 & arm-linux-2.6.20。
host编译环境:
RHEL5U3, gcc 4.1.2, arm-linux-gcc 2.95.3,arm-linux-gcc 3.4.4
需要cross compile的软件包:
sqlite 3.6.14, python 2.5.4, boa-0.94.13.
2 交叉编译sqlite
先到 http://www.sqlite.org/download.html 下载最新的sqlite源代码,我这里用的是3.6.14版本。
推荐使用amalgamation版本的源代码,这个代码只有几个文件而已,编译起来方便,而且据说编译器好的话,还可能编译出更高效的代码。我下载的是
http://www.sqlite.org/sqlite-amalgamation-3.6.14.tar.gz
先运行以下几步:
tar zxf sqlite-amalgamation-3.6.14.tar.gz
cd sqlite-3.6.14
(arm-linux-gcc version 3.4.4:)
./configure --host=arm-linux --prefix=/usr/local/arm/3.4.4 --enable-shared --disable-readline --disable-dynamic-extensions
(arm-linux-gcc version 2.95.3:)
./configure --host=arm-linux --prefix=/usr/local/arm/2.95.3 --enable-shared --disable-readline --disable-dynamic-extensions
以上是把sqlite解压缩,然后做一些配置,这里,希望sqlite到时候安装到/usr/local/arm/3.4.4里,要生成动态链接库,不要readline,不要sqlite的动态扩展。 sqlite到时候安装到/usr/local/arm/3.4.4里。
如果要做进文件系统,则作如下设置:
(arm-linux-gcc version 3.4.4:)
./configure --host=arm-linux --prefix=$(pwd)/_install_gcc3 --enable-shared --disable-readline --disable-dynamic-extensions
(arm-linux-gcc version 2.95.3:)
./configure --host=arm-linux --prefix=$(pwd)/_install_gcc2 --enable-shared --disable-readline --disable-dynamic-extensions
然后编辑Makefile,把CFLAGS和CXXFLAGS中的-g去掉,我们不用debug sqlite。
接下来就可以编译和安装sqlite了:
make
make install
3 交叉编译python
3.1 下载
先去http://www.python.org/download/下载最新版本的python源代码,我这里下载的是:
http://www.python.org/ftp/python/2.5.4/Python-2.5.4.tgz
3.2 编译并安装pc版本
交叉编译,也需要HOST机上的python版本为2.5.4,执行如下命令:
tar -zxvf Python-2.5.4.gz
cd Python-2.5.4
make clean
./configure --prefix=/usr
make
make install
3.3 编译pc版本的语法解析器
由于在编译python的时候,需要先编译一个叫pgen的程序出来,用于生成语法解析器,所以要先生成一个pc版本的pgen:
mkdir build.pc
cd build.pc
../configure
make Parser/pgen
然后ls Parser一下,应该就能看到有pgen了。
3.4 Arm-linux-gcc-3.4.4版本编译
3.4.1 修改和运行configure
configure在检测编译器的printf是否支持%zd的时候,如果发现是在cross compile,就直接不干活了。这还了得?
把这一部分的检测代码去掉。这段代码起始于:
echo "$as_me:$LINENO: checking for %zd printf() format support" >&5
echo $ECHO_N "checking for %zd printf() format support... $ECHO_C" >&6
if test "$cross_compiling" = yes; then
结束于:
cat >>confdefs.h <</_ACEOF
#define PY_FORMAT_SIZE_T "z"
_ACEOF
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
把这两段以及中间的内容都删除掉就可以了。
有了语法解析器,就可以开始编译arm版本的python了。
(arm-linux-gcc version 3.4.4:)
cd ..
./configure --prefix=$(pwd)/_install_gcc3 --disable-ipv6 --host=arm-linux --enable-shared
./configure --prefix=/usr/ztian/_install_gcc3 --disable-ipv6 --host=arm-linux --enable-shared
3.4.2 修改Makefile
之后就要对Makefile做一些修改:
(1)把
# OPT= -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
OPT= -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
一行中,去掉-g,我们不要debug python,-O3改为-O2,空间紧张O2就可以了。
(2)在:
PGEN= Parser/pgen$(EXE)
一行的下面加上:
# PGEN_HOST= ../build.pc/Parser/pgen$(EXE)
PGEN_HOST= build.pc/Parser/pgen$(EXE)
表明我们在HOST上运行的pgen。
(3)在要使用PGEN的地方改为PGEN_HOST:
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
-$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
改为:
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
-$(PGEN_HOST) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
(4)修改所有使用新生成的python的地方。
所有如./$(BUILDPYTHON)的地方,都改为python,如:
platform: $(BUILDPYTHON)
$(RUNSHARED) ./$(BUILDPYTHON) -E -c 'import sys ; from distutils.util import get_platform ; print get_platform()+"-"+sys.version[0:3]' >platform
改为:
platform: $(BUILDPYTHON)
$(RUNSHARED) python -E -c 'import sys ; from distutils.util import get_platform ; print get_platform()+"-"+sys.version[0:3]' >platform
这种地方比较多,共11处,需小心修改。
3.4.3 修改setup.py
setup.py负责编译python的各个扩展模块。但是,由于python完全没有考虑cross compile,所以要做一些修改。
PyBuildExt类:
build_extension函数:
这个函数在编译了所有的extension后,会去load这些刚编译好的extension,但我们在i686的电脑上显然不能load,所以要跳过这些操作。在 build_ext.build_extension(self, ext)后面直接写一个return,不做load。
detect_modules函数:
函数的前两行是把/usr/local加到搜索目录中,我们的cross compiler一般不会直接安装在 /usr/local里面的,所以这两行去掉:
add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
lib_dirs, inc_dirs的设定中,把中括号里的那些都去掉。以下所有模块都不要:
cmath, _ctypes, _testcapi, pwd, grp, spwd, mmap, audioop, imageop, rgbimg, readline,ssl, openssl, bdb, dbm, termios, nsl, ncurses, bz2, linuxaudiodev, ossaudiodev, _tkinter
由于python本身的问题,现在ctypes还不能在除i386以外的机器上运行,所以ctypes也去掉:
disabled_module_list = ['cmath', '_ctypes', '_testcapi', 'pwd', 'grp', 'spwd', 'mmap', 'audioop', 'imageop', 'rgbimg', 'readline','ssl', 'openssl', 'bdb', 'dbm', 'termios', 'nsl', 'ncurses', 'bz2', 'linuxaudiodev', 'ossaudiodev', '_tkinter']
编译sqlite的地方:
for d in inc_dirs + sqlite_inc_paths:
改为:
for d in ['/usr/local/arm/3.4.4/include']:
因为sqlite3安装在这里,如果这里不改的话,setup.py会在我的电脑上找sqlite
main函数:
setup函数调用的时候,把要安装的scripts那一部分去掉
之后就可以make && make install了。
make
make install
3.5 Arm-linux-gcc-2.95.3版本编译
3.5.1 修改和运行configure
arm-linux-gcc version 2.95.3:
cd ..
./configure --prefix=$(pwd)/_install_gcc2 --disable-ipv6 --host=arm-linux --enable-shared
3.5.2 修改Makefile
之后就要对Makefile做一些修改,把
# OPT= -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
OPT= -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
一行中,去掉-g,我们不要debug python,-O3改为-O2,空间紧张O2就可以了。 -fwrapv
在
PGEN= Parser/pgen$(EXE)
一行的下面加上
# PGEN_HOST= ../build.pc/Parser/pgen$(EXE)
PGEN_HOST= build.pc/Parser/pgen$(EXE)
表明我们在HOST上运行的pgen
在要使用PGEN的地方改为PGEN_HOST:
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
-$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
改为:
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
-$(PGEN_HOST) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
修改所有使用新生成的python的地方。
所有如 ./$(BUILDPYTHON) 的地方,都改为python
如:
platform: $(BUILDPYTHON)
$(RUNSHARED) ./$(BUILDPYTHON) -E -c 'import sys ; from distutils.util import get_platform ; print get_platform()+"-"+sys.version[0:3]' >platform
改为:
platform: $(BUILDPYTHON)
$(RUNSHARED) python -E -c 'import sys ; from distutils.util import get_platform ; print get_platform()+"-"+sys.version[0:3]' >platform
这种地方比较多,共11处,需小心修改。
3.5.3 修改setup.py
setup.py负责编译python的各个扩展模块。但是,由于python完全没有考虑cross compile,所以要做一些修改。
PyBuildExt类:
build_extension函数:
这个函数在编译了所有的extension后,会去load这些刚编译好的extension,但我们在i686的电脑上显然不能load,所以要跳过这些操作。在 build_ext.build_extension(self, ext)后面直接写一个return,不做load。
detect_modules函数:
函数的前两行是把/usr/local加到搜索目录中,我们的cross compiler一般不会直接安装在 /usr/local里面的,所以这两行去掉:
add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
lib_dirs, inc_dirs的设定中,把中括号里的那些都去掉。以下所有模块都不要:
cmath, _ctypes, _testcapi, pwd, grp, spwd, mmap, audioop, imageop, rgbimg, readline, ssl, openssl, bdb, dbm, termios, nsl, ncurses, bz2, linuxaudiodev, ossaudiodev, tkinter
由于python本身的问题,现在ctypes还不能在除i386以外的机器上运行,所以ctypes也去掉:
disabled_module_list = ['cmath', '_ctypes', '_testcapi', 'pwd', 'grp', 'spwd', 'mmap', 'audioop', 'imageop', 'rgbimg', 'readline','ssl', 'openssl', 'bdb', 'dbm', 'termios', 'nsl', 'ncurses', 'bz2', 'linuxaudiodev', 'ossaudiodev', '_tkinter']
编译sqlite的地方:
for d in inc_dirs + sqlite_inc_paths:
改为:
for d in ['/usr/local/arm/2.95.3/include']:
因为我的sqlite3安装在这里,如果这里不改的话,setup.py会在我的电脑上找sqlite
main函数:
setup函数调用的时候,把要安装的scripts那一部分去掉
之后就可以make && make install了。
#make
make install
其实到 make 这一步通不过,可能是python2.5.4对gcc的版本要求较高,不支持Arm-linux-gcc-2.95.3,所以前面这些工作大概是白废,如果有哪位牛人编译通过了,麻烦告知小弟,感激不尽。
4 文件系统的移植
4.1 更新文件系统
执行# make install后,python会被复制到_install_gcc3目录下,将_install_gcc3目录下的bin目录和lib目录下的所有文件分别复制到S3C2410A & arm-linux-2.4.18文件系统的/bin目录和/lib目录下:
# cp –a bin/* /bin/
# cp –a lib/* /lib/
这样文件系统即被安装到arm-linux下。
4.1.1 更新S3C2410A & arm-linux-2.4.18的lib文件
对于S3C2410A & arm-linux-2.4.18,lib文件都是arm-linux-gcc-2.95.3对应的库文件,此时运行python会提示找不到glibc2.3:
python: /lib/libc.so.6: version `GLIBC_2.3' not found (required by /usr/lib/lib)
需要拷贝arm-linux-gcc-3.4.4库文件中的以下6个文件到 ARM板文件系统/lib目录下:
libc.so.6, libc-2.3.5.so,
ld-2.3.5.so, ld-linux.so.2,
libpthread.so.0, libpthread-0.10.so
过程记录如下:
[/u@/h /W]/$ cp /usr/lib_g3/libc-2.3.5.so /lib/
[/u@/h /W]/$ python
python: /lib/libc.so.6: version `GLIBC_2.3' not found (required by /usr/lib/lib)
[/u@/h /W]/$ cp -a /usr/lib_g3/libc.so.6 /lib/
[/u@/h /W]/$ python
python: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by /lib)
[/u@/h /W]/$ cp -a /usr/lib_g3/ld-2.3.5.so /lib/
[/u@/h /W]/$ python
python: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by /lib)
[/u@/h /W]/$ cp -a /usr/lib_g3/ld-linux.so.2 /lib/
[/u@/h /W]/$ python
python: relocation error: /lib/libpthread.so.0: symbol __libc_sigaction, versioe
[/u@/h /W]/$ cp -a /usr/lib_g3/libpthread.so.0 /lib/
[/u@/h /W]/$ python
python: error while loading shared libraries: libpthread.so.0: cannot open shary
[/u@/h /W]/$ cp -a /usr/lib_g3/libpthread-0.10.so /lib/
[/u@/h /W]/$ python
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
'import site' failed; use -v for traceback
Python 2.5.4 (r254:67916, May 19 2009, 21:12:45)
[GCC 3.4.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
对于AT91SAM9261 & arm-linux-2.6.20,其lib文件不用更新,即可顺利运行。
4.2 导出环境变量
python如果安装在/bin和/lib目录下,则需导出环境变量:
export PYTHONHOME=/lib/python2.5
export PYTHONPATH=.:$PYTHONHOME:$PYTHONHOME/site-packages:$PYTHONHOME/lib-dynload
export PATH=$PATH:$PYTHONHOME:$PYTHONPATH
如果安装在/usr/bin和/usr/lib目录下,则导出:
export PYTHONHOME=/usr/lib/python2.5
export PYTHONPATH=.:$PYTHONHOME:$PYTHONHOME/site-packages
export PATH=$PATH:$PYTHONHOME:$PYTHONPATH
[/u@/h /W]/$ cp _install/lib/python2.5/site* /lib/python2.5/
cp: omitting directory '_install/lib/python2.5/site-packages'
[/u@/h /W]/$ python test.py
'import site' failed; use -v for traceback
warning: Not importing directory '/lib/python2.5/encodings': missing __init__.py
hello, python!
hello, arm-linux!
[/u@/h /W]/$ cp -a _install/lib/python2.5/encodings /lib/python2.5/
[/u@/h /W]/$ python test.py
'import site' failed; use -v for traceback
hello, python!
hello, arm-linux!
[/u@/h /W]/$ cp -a _install/lib/python2.5/__ /lib/python2.5/
到这一步,python基本可以在两个ARM9平台上顺利运行了:
/ # python
Python 2.5.4 (r254:67916, May 19 2009, 21:12:45)
[GCC 3.4.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 3+5
8
>>>
但还是碰到一些问题,详细问题请见下一章。
5 移植遗留问题
5.1 Import module问题
有些module不能正常import,例如当import sqlite3时:
>>> import sqlite3
import sqlite3 # directory /lib/python2.5/sqlite3
# /lib/python2.5/sqlite3/__init__.pyc matches /lib/python2.5/sqlite3/__init__.py
import sqlite3 # precompiled from /lib/python2.5/sqlite3/__init__.pyc
# /lib/python2.5/sqlite3/dbapi2.pyc matches /lib/python2.5/sqlite3/dbapi2.py
import sqlite3.dbapi2 # precompiled from /lib/python2.5/sqlite3/dbapi2.pyc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/ztian/work/python/Python-2.5.4/build.arm/_install/lib/python2.5/sq>
File "/usr/ztian/work/python/Python-2.5.4/build.arm/_install/lib/python2.5/sq>
ImportError: No module named datetime
直接import datetime时:
>>> import datetime
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named datetime
Import pdb时:
>>> import pdb
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/lib/python2.5/pdb.py", line 11, in <module>
from repr import Repr
File "/lib/python2.5/repr.py", line 6, in <module>
from itertools import islice
ImportError: No module named itertools
不能import的module还有:time、socket、operator等。
可以import的module有:
>>> import re
>>> import os
>>> import sys
等等。
5.2 Boa服务器运行python CGI无法import
在ARM板上用boa搭建了一个WEB服务器,并用python编写CGI脚本,写一段测试程序如下:
#!/bin/python
print """Content-type: text/html
<html xmlns = "http://www.w3.org/1999/xhtml">
<head><title>Hello, arm-linux-web-python!</title></head>
<body>"""
print "<p>Hello, arm-linux-web-python!</p>"
print "</body></html>"
通过WEB访问这个CGI,可以正常执行:Hello, arm-linux-web-python!
如果在代码中加入一个import,如:
#!/bin/python
import os
print """Content-type: text/html
<html xmlns = "http://www.w3.org/1999/xhtml">
<head><title>Hello, arm-linux-web-python!</title></head>
<body>"""
print "<p>Hello, arm-linux-web-python!</p>"
print "</body></html>"
此时通过WEB执行CGI,会无法执行,浏览器报错如下:
502 Bad Gateway
The CGI was not CGI/1.1 compliant.
我还希望能通过WEB界面访问arm-linux下的boa服务器,通过cgi-bin下的python写的cgi来操作sqlite数据,完成一个小型嵌入式数据库的插入、修改、删除等,但问题和上面这个“Hello, arm-linux-web-python!”CGI程序的问题一样:
测试CGI源码如下:
#! /bin/python
import sqlite3
def runTest():
cx = sqlite3.connect("test_sqlite3.db")
cu = cx.cursor()
#create
cu.execute('''create table catalog(
id integer primary key,
pid integer,
name varchar(10) unique
)''')
#insert
cu.execute('insert into catalog values(0,0,"tian!")')
cu.execute('insert into catalog values(1,0,"hello")')
cx.commit()
#select
cu.execute('select * from catalog')
print '1:',
print cu.rowcount
rs = cu.fetchmany(1)
print '2:',
print rs
rs = cu.fetchall()
print '3:',
print rs
#delete
cu.execute('delete from catalog where id = 1 ')
cx.commit()
cu.execute('select * from catalog')
rs = cu.fetchall()
print '4:',
print rs
#select count
cu.execute("select count(*) from catalog")
rs = cu.fetchone()
print '5:',
print rs
cu.execute("select * from catalog")
cu.execute('drop table catalog')
cx.close()
if __name__ == '__main__':
runTest()
此程序在arm-linux平台下通过控制台是可以成功运行的,但是通过boa服务器访问,这不能成功运行,浏览器报错如下:
502 Bad Gateway
The CGI was not CGI/1.1 compliant.
[1] HOWTO Cross Compile Python for ARM -- by Leo Jay
http://wiki.woodpecker.org.cn/moin/LeoJay/HOWTOCrossCompilePythonForARM
[2] Cross Compile Python 2.5.2 For ARM
http://blog.csdn.net/borderj/archive/2008/08/03/2761188.aspx
[3] Porting Python http://wiki.osdev.org/Porting_Python
[4] Learning Python Python语言入门
[5] LeoJay/PyPackage http://wiki.woodpecker.org.cn/moin/LeoJay/PyPackage
[6] http://groups.google.com/group/python-cn/browse_thread/thread/89f7de96b5ea72dc
[7] 中国ZOPE用户组 http://blog.czug.org/
[8] http://python.net/crew/mhammond/win32/Downloads.html
[9] Linux添加环境变量与GCC编译器添加INCLUDE与LIB环境变量 http://hi.baidu.com/rainfish_tju/blog/item/9a8723037ceddfe408fa93a0.html