1. 程式人生 > >python移植到arm的單板

python移植到arm的單板

python移植到arm的單板

2017年09月22日 09:05:55 mania_yan 閱讀數:3068

注:下文的CSU是我們一個嵌入式單板的名稱。

前言

作者的話:

本人非常喜歡python,一直夢想可以移植到CSU中。但是python誕生之初並沒有想到要應用在嵌入式領域,因此,python的交叉編譯比較複雜。python的交叉編譯花費了我一些時間進行摸索,這篇文章是在查閱了N多資料,進行了N多嘗試後成功的,就在想徹底放棄的時候,NEVER GIVE UP的信念讓我進行前進,而恰恰是這前進的一步,轉暗為明,相繼研究出來CSU的NFS與CSU的Python!這是讓自己非常振奮的!

交叉編譯

這裡以python2.7.6進行陳述。

下載python的linux版本原始碼包,解壓到/opt中。

2.1 更新虛擬機器上的python版本

為了最大的穩定性,建議更新虛擬機器上的版本與交叉編譯的版本一致。由於下載的原始碼包版本肯定是最新的,因此,順便更新一下虛擬機器的python版本也是一件好事。

傳統三部曲。

./configure

make

make install

2.2 配置arm的configure

由於原始碼包需要生成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其實可以不寫,系統可以猜出來的,但這裡還是寫上。

2.3 pgen準備

這個非常關鍵。

在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,就會把剛才複製過來的給替換掉了,改了未來的時間,就會忽略跳過,非常巧妙的技巧!

2.4 make && make install

現在可以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

就可以看到輸出了。

python3的移植

同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 [email protected]
do
if [ $args = "all" ];then
make --silent && make install --silent
break
fi
done
make Parser/pgen --silent
cd -
mkdir Parser
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)

[Guangwei] 上述指令碼是為32位Ubuntu寫的,如果是64為Ubuntu,還需要注意2點:

1。 configure 的“--build=x86_64-linux-gnu”,這個要用“gcc -v”檢視。

2。 arm gcc是32位的編譯器,不能直接在64位的機器上執行,需要下載支援庫。可以參考如下解決方案,

 arm-hisiv600-linux-gcc編譯出現提示:No such file or directory
實際就是:64位ubuntu不相容32bit工具問題。

解決辦法如下:
apt-get update
sudo apt install lib32z1-dev
apt-get install lib32z1 lib32ncurses5
apt-get install lib32stdc++6
#apt-get install lib32bz2-1.0
apt-get install gcc-multilib g++-multilib 

 

附錄(效能測評)

7.1 不同cpu與系統的對比

執行如下測評語句:

    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

7.2 python與C的對比

執行1000次相加與輸出:

C語言程式碼如下:

  1 #include <stdio.h>

  2 #include <sys/time.h>

  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%左右,屬於可以接受的範圍內