注:下文的CSU是我们一个嵌入式单板的名称。
作者的话:
本人非常喜欢python,一直梦想可以移植到CSU中。但是python诞生之初并没有想到要应用在嵌入式领域,因此,python的交叉编译比较复杂。python的交叉编译花费了我一些时间进行摸索,这篇文章是在查阅了N多资料,进行了N多尝试后成功的,就在想彻底放弃的时候,NEVER GIVE UP的信念让我进行前进,而恰恰是这前进的一步,转暗为明,相继研究出来CSU的NFS与CSU的Python!这是让自己非常振奋的!
这里以python2.7.6进行陈述。
下载python的linux版本源码包,解压到/opt中。
为了最大的稳定性,建议更新虚拟机上的版本与交叉编译的版本一致。由于下载的源码包版本肯定是最新的,因此,顺便更新一下虚拟机的python版本也是一件好事。
传统三部曲。
./configure
make
make install
由于源码包需要生成pc版的python和arm版的python,因此,需要隔离开,这个非常关键。
pc版采用原有路径,不改变。
arm则在源码包下
mkdir arm_build
由于configure会在当前目录下生成Makefile等文件,因此,不能在源码包下直接configure,必须在arm_build里执行。这点非常重要。
cd arm_build
由于交叉编译中,需要明确如下两个变量的值,因此,这里必须人工定义。ptmx就是虚拟串口的意思,由于我的单板以后要用到这个,因此,设为yes。
设为no一样是可以的。
echo ac_cv_file__dev_ptmx=yes > config.site
echo ac_cv_file__dev_ptc=yes >> config.site
export CONFIG_SITE=config.site
建好arm版python要安装到的文件夹。
arm_install=/opt/arm_python
mkdir $arm_install
configure如下:
../configure --host=arm-none-linux-gnueabi --build=i686-linux-gnu --target=arm-none-linux-gnueabi --disable-ipv6 --prefix=$arm_install --enable-shared --silent
其中,arm的gcc采用2011版本;
由于ipv6支持有问题,因此,必须关闭;
--silent去掉configure过程中的垃圾信息,只输出warning及以上的关键信息,我特别喜欢这个。
--build是必须填的,怎么知道这个build信息呢,最简单的方法就是
gcc –v
里面会有gcc的configure信息,里面就有--build的信息,复制过来就万无一失。
--target其实可以不写,系统可以猜出来的,但这里还是写上。
这个非常关键。
在configure之后make或make Parsr/pgen。
可以在arm_build的Parser文件夹里发现pgen这个执行文件,它是python的语法分析器之类东西,但问题来了。
这个东西是不能用的,因为是交叉编译版本的pgen,在虚拟机下用不了。
最简单的解决方法如下:
回到源码包路径
cd ../
生成pc版本的pgen
make Parser/pgen
复制到arm_build的Parser里面
cd arm_build
cp ../Parser/pgen Parser
下面这一步非常关键而且非常巧妙
touch –t 12312359 Parser/pgen
意思是:将pgen文件的日期改为今年的最后一分钟生成的。
为什么需要这一步?
很简单:
因为,arm版python在make时,会生成它的pgen,就会把刚才复制过来的给替换掉了,改了未来的时间,就会忽略跳过,非常巧妙的技巧!
现在可以make(或make python)了。
我喜欢加上--silent,这样可以减少很多垃圾信息。
make完成后,注意:
这里,使用make install一般会出错,显示缺失_struct的类型错误。
使用make -i install 才能搞定。
-i 就是ignore错误的意思,继续前进。这里可能的问题是:前面需要某模块,但是install中却在后面才安装这个模块,导致了前面找不到模块的错误,其实,整个完成后,是完整的。
这一招对这种时序问题,或install中出现的时序问题比较难解决时,能帮上大忙。
现在,查看/opt/arm_python这个安装目录,可以发现已经有相关python文件了。
python容易使用的一大特点就是自由开放的库很多,官方不可能全部纳入自己的标准库中,因此,安装自己需要的第三方库是必要的。
举例:
这里安装第三方xlrd库,这个库可以非常方便的读取excel文件的内容,即使不在windows下,即使没有安装excel,也可以,而且速度非常的快。
下载源码包后解压,cd到那个路径下。
python setup.py install
就可以完成第三方库的安装了。这里的install其实就是包括build和install。
对于虚拟机,会安装到
/usr/local/lib/python3.3/site-packages
第三方库基本默认安装在site-packages里。
那如何安装到我们的arm的python里呢。
很简单:
python setup.py install --prefix=/opt/arm_python
(默认情况下,这个前缀为/usr/local/)
如果没有正确安装,当程序需要这个库时,会报找不到模块的error。
由于python的库文件很大,直接拷贝到CSU是不现实的。裁剪库也很麻烦,而且消弱了功能。因此,这里采用NFS。python的bin、lib等文件,以及自己编写的代码文件都放在虚拟机上。CSU通过NFS使用python即可。
CSU侧:
mkdir /mnt/python
mount –o nolock 10.9.102.23:/opt/arm_python /mnt/python
在/etc/profile里
在export PATH一行后面加入
:/mnt/python/bin
在export LD_LIBRARY_PATH 一行后面加入:/mnt/python/lib
这样就可以使用python了。
python –V就可以看到python的版本信息了。
python回车后
就可以进入python的shell了,可以在命令中输入python语句。
由于这个CSU上的python的shell非常不好用,打错字无法修正,⊙﹏⊙b汗,因此,我一般都在虚拟机上写代码,CSU上运行就行了。(注,python的shell退出方式是输入exit()指令)
例如:
mkdir /opt/arm_python/code
在code写入helloworld.py的文件
在CSU中:
python /mnt/python/code/helloworld.py
就可以看到输出了。
同python2。
虚拟机是支持同时安装两个版本的python的,它们的路径会通过版本号进行区分。
arm版的python也一样,在/opt/arm_python会进行版本的区分。
默认python链接指向python2,如果需要更改,rm后ln到python3即可。
又是将书变薄的时候了,以下是精华,即自动化交叉编译脚本。
#prepare
echo "prepare stage"
arm_install=/opt/arm_python
arm_build=`pwd`/arm_build
mkdir $arm_build
mkdir $arm_install
cd `pwd`
#arm comfigure
echo "arm confiure stage"
cd $arm_build
echo ac_cv_file__dev_ptmx=yes > config.site
echo ac_cv_file__dev_ptc=yes >> config.site
export CONFIG_SITE=config.site
../configure --host=arm-none-linux-gnueabi --build=i686-linux-gnu --target=arm-none-linux-gnueabi --disable-ipv6 --prefix=$arm_install --enable-shared --silent
#pc pgen
echo "pc pgen stage"
cd -
./configure --silent
for args in $@
do
if [ $args = "all" ];then
make --silent && make install --silent
break
fi
done
make Parser/pgen --silent
cd -
cp ../Parser/pgen Parser
#change the pgen time,
# or else the cross compile will replace this pc version pgen. important!!
touch -t 12312359 Parser/pgen
#make
echo "make stage"
make python --silent && make -i install
#make it smaller
#arm-none-linux-gnueabi-strip -s $arm_install/bin/python3.3
exit 0
使用方法:
chmod +x arm_python
复制到源码包路径下(或ln到源码包路径下);
执行./arm_python 即可。
默认安装在/opt/arm_python里。
(当加入参数all时,脚本会顺便更新虚拟机上的python)
执行如下测评语句:
import time
start_time=time.clock()
for i in range(1000):
print('good')
end_time = time.clock()
print('total time is ', end_time-start_time)
结果对比:
CPU |
OS |
Time |
奔腾E6700(酷睿core2) |
Windows7 |
0.03s |
奔腾E6700(酷睿core2) |
Virtual Ubuntu |
0.01s |
AMD炫龙双核 |
Ubuntu |
0.003s |
AT9260(Arm9) |
Linux |
0.6s |
AM335(A8) |
Linux |
0.18s |
结果在我的预测范围里,即CSU的处理能力只有主流台式2核cpu的几百分之一,属于可以接受的范围。
(有趣的是,ubuntu的执行速度远高于windows!python虽然是跨平台语言,但是在linux环境下,却有明显的优势)
另一个将数据字典自动转为XML的程序对比:
win7:0.35s
A8:8s
执行1000次相加与输出:
C语言代码如下:
1 #include
2 #include
3 void main(void){
4 struct timeval start,end;
5 gettimeofday(&start,NULL);
6 int i,sum=0;
7 for(i=0;i<1000;++i){
8 sum+=i;
9 printf("%d\n",sum);
10 }
11 gettimeofday(&end,NULL);
12 printf("total time is %d\n",1000000*(end.tv_sec-start.tv_sec)+end.tv _usec-start.tv_usec);}
Python代码如下:
1 import time
2 start_time = time.clock()
3 sum=0
4 for i in range(1000):
5 sum=i+sum
6 print(sum)
7 end_time = time.clock()
8 print('time is ',end_time-start_time )
C一共使用:34毫秒;
Python一共使用:180毫秒。
Python为C速度的20%左右,属于可以接受的范围内。