移植环境:
HOST: Fedora 12
交叉编译器:Sourcery G++ Lite 2009q3-67 for ARM GNU/Linux
交叉编译程序:Sqlite 3.6.23.1,Python 2.6.5
下载源码:
Sqlite 3.6.23.1 http://www.sqlite.org/sqlite-3.6.23.1.tar.gz
Python 2.6.5 http://www.python.org/ftp/python/2.6.5/Python-2.6.5.tar.bz2

由于sqlite是python的标准组件所以我们要先进行sqlite的移植。
交叉编译sqlite:
配置编译选择:

1
2
3
4
5
tar xvf sqlite-3.6.23.1.tar.gz mkdir sqlite-build
cd sqlite-3.6.23.1
./configure --host=arm-linux --prefix=/home/lzz/working/apps/sqlite-build --enable-shared --disable-readline --disable-dynamic-extensions

以上的命令我们先解压了源码,然后进入源码目录执行configure来配置编译选项, 各个参数的意思是:–host=arm-linux 说明我们要编译arm版本的sqlite;–prefix=/home/lzz/working/apps/sqlite-build 说明我们要把编译好的sqlite安装到sqlite-build目录;–enable-shared 生成动态链接库;–disable-readline 禁用sqlite的readline;–disable-dynamic-extensions 禁用sqlite的动态扩展。
编译和安装:

1
2
Make
Make install

这两个命令就不用解释了吧。执行完这两个命令后就可以在sqlite-build目录下看到三个目录分别是bin,include和lib目录,把bin目录下的sqlite3拷到文件系统的bin目录下,把lib目录下的内容拷到文件系统的lib目录下就ok了(注意:如果出现sqlite不能在开发板上运行的情况,很可能是由于缺少相应的库文件导致的,你只需要按照错误提示在你的交叉编译环境中找到相应的库文件拷到文件系统的lib目录下即可)。下图是在我的tq2440上运行的效果

交叉编译Python:
解压Python

1
2
tar xvf Python-2.6.5.tar.bz2 mkdir python-build

编译PC版的Python:

1
2
3
4
5
cd Python-2.6.5
mkdir python-pc
cd python-pc
../configure
make

有人可能会问,我们为什么要编译pc版的python。其实原因是这样的,在python编译过程中,第一阶段会产生一个python的可执行版本,然后会进入第二阶段去按照setup.py来定义去编译附加的python模块。而在处理setup.py时其实就需要用到python解析器了,但是我们如果是在编译嵌入式版本的话,那么第一阶段产生的python可执行程序是arm版本的,它不能运行在我们的pc机上所以不能用它来处理setup.py。所以我们要提前编译一个pc 上的python来处理setup.py。
这时在当前的python-pc目录下就会出现python解释器了。
修改configure文件:
由于configure文件在检测编译器的printf是否支持%zd的时候如果发现是在cross compile就会退出,所以我们要先去掉这段检测代码用vim打开configure文件查找%zd printf()就会发现如下代码:

1
2
3
4
{ 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 { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling

然后往下找,一直找到这里

1
2
3
4
5
6
( exit $ac_status ) { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi

删掉或注释掉这两段以及中间的部分就可以了。
编译arm版本的python:

1
2
3
4
mkdir python-arm
cd python-arm
../configure --host=arm-linux --prefix=/home/lzz/working/apps/python-build --disable-ipv6 --enable-shared

上面的编译选项的意思和sqlite的相同就不再解释了。
然后我们修改生成的Makefile文件去掉调试信息,方法是在Makefile文件中查找OTP找到 OPT= -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 这一行把-g选项去掉,如果空间紧张的话,还可以把-O3改成-O2。
继续查找PGEN,在PGEN = Parser/pgen$(EXE)一行的下面添加PGEN_HOST= ../build-pc/Parser/pgen$(EXE)
在要使用PGEN进行解释的地方使用PGEN_HOST大约在Makefile文件的540

1
2
3
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) -@$(INSTALL) -d Include -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)

改为

1
2
3
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) -@$(INSTALL) -d Include -$(PGEN_HOST) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)

修改所有使用新生成的arm版的python的地方,把所有./$(BUILDPYTHON)的地方都改成../build-pc/python$(EXE),这样的地方比较多,大家可以用在vim在打:号然后输入%s/\.\/\$(BUILDPYTHON)/\.\.\/build-pc\/python\$(EXE)/g命令来替换。
修改setup.py文件:
setup.py负责编译python的各个扩展模块。但是,由于python完全没有考虑cross compile,所以要做一些修改。
我们需要修改 PyBuildExt类中的几个部分
build_extension函数:
这个函数在编译了所有的extension后,会去load这些刚编译好的extension, 但我们在i686的电脑上显然不能load,所以要跳过这些操作。 大概在238行在 build_ext.build_extension(self, ext)后面直接写一个return,不做load。
去掉无用的搜索目录:
函数的前两行是把/usr/local加到搜索目录中,我们的cross compiler一般不会直接安装在 /usr/local里面的,所以这两行去掉(大概在314行):

1
2
add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')

去掉不被支持的模块
由于python本身的问题,现在ctypes还不能在除i386以外的机器上运行,所以去掉 ctypes。大概在1275行,把它注释掉就可以了

1
self.detect_ctypes(inc_dirs, lib_dirs)

还可以根据自己的需要去掉不用的模块,方法是在detect_modules函数中注释掉相应的项,比如我要去掉cmath模块

1
2
# complex math library functions exts.append( Extension('cmath', ['cmathmodule.c'],libraries=math_libs) )

就可以把上面几行注释掉就可以了。
修改sqlite的编译选项
我们要把setup.Py文件中对sqlite的引用路径改成我们安装sqlie的目录,大概在910行,我们把

1
for d in inc_dirs + sqlite_inc_paths:

改成

1
for d in ['/home/lzz/working/apps/sqlite-build/include']:

修改main函数
最后我们把main函数中的scripts那一部分改成空,大大概在1913行把

1
2
3
scripts = ['Tools/scripts/pydoc', 'Tools/scripts/idle', 'Tools/scripts/2to3', 'Lib/smtpd.py']

改成
scripts=[]
编译安装python:
最后

1
2
make
make install

就可以了,编译完成后我们会在python-build目录下发现四个目录,我们只要bin和lib目录中的内容。我们把bin目录中的文件拷到我们的文件系统的/usr/bin目录,然后把lib目录中的文件拷到文件系统的/usr/lib目录中就ok了。

注意:如果出现python不能运行的情况很可能是缺少相应的库,你需要到你的交叉编译环境中去拷相应的库文件。
如果出现下面的错误提示就是你没有设置python的环境变量

1
2
Could not find platform dependent libraries <exec_prefix>                      
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]

这时你需要设置PYTHONHOME,如果出现下面的错误
‘import site faild’
这时你需要设置PYTHONPATH 。
最好是在你的文件系统的etc目录下的profile文件中加入下面的语句

1
2
3
export PYTHONHOME=/usr/lib/python2.6
export PYTHONPATH=.:$PYTHONHOME:$PYTHONHOME/site-packages
export PATH=$PATH:$PYTHONHOME:$PYTHONPATH

这样就不会出现上面的错误了。
裁减python:
我们发现我们编译出来的python的库文件有57M,如果你空间紧张可以删除库文件中扩展名为py和pyc的文件,只留下pyo的文件。不过这样做之后我们运行python就要加上-OO的参数如下图就是带-OO选项的运行情况

参考文章:
http://wiki.woodpecker.org.cn/moin/LeoJay/HOWTOCrossCompilePythonForARM
http://ifis.blog.hexun.com/44254479_d.html

12-30 01:14