交叉編譯 python

本文來自 我的博客。博客的文章保持更新,此文可能不是最新狀態。

下載、解壓 python 源代碼

從 python.org 下載。

導入交叉編譯 patch

參考自 python-2.7-001-support-for-build.patch,2.7.11 的修改地方有稍微變化,詳見如下 patch。

Python 雖然使用 autoconf,但是事實上代碼中已經包含 configure 文件,因此下文代碼給出的是修改 configure.ac 並執行 autoconf 後生成的 configure 文件。

patch 的使用方法,在 python 源代碼根目錄下執行:

patch -p1 < ../0001-cross-compile.patch

python 2.7.11 交叉編譯 patch:

diff --git a/Makefile.pre.in b/Makefile.pre.in
index ee73edd..730db7e 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -237,7 +237,8 @@ LIBFFI_INCLUDEDIR=  @LIBFFI_INCLUDEDIR@
 
 ##########################################################################
 # Parser
-PGEN=      Parser/pgen$(EXE)
+BUILDPGEN=     Parser/pgen$(EXE)
+PGEN_FOR_BUILD=    @PGEN_FOR_BUILD@
 
 PSRCS=     \
        Parser/acceler.c \
@@ -635,14 +636,14 @@ Modules/pwdmodule.o: $(srcdir)/Modules/pwdmodule.c $(srcdir)/Modules/posixmodule
 
 $(GRAMMAR_H): $(GRAMMAR_INPUT) $(PGENSRCS)
        @$(MKDIR_P) Include
-       $(MAKE) $(PGEN)
-       $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
+       $(MAKE) $(BUILDPGEN)
+       $(PGEN_FOR_BUILD) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
 $(GRAMMAR_C): $(GRAMMAR_H) $(GRAMMAR_INPUT) $(PGENSRCS)
        $(MAKE) $(GRAMMAR_H)
        touch $(GRAMMAR_C)
 
-$(PGEN):   $(PGENOBJS)
-       $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
+$(BUILDPGEN):  $(PGENOBJS)
+       $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(BUILDPGEN)
 
 Parser/grammar.o:  $(srcdir)/Parser/grammar.c \
                $(srcdir)/Include/token.h \
diff --git a/configure b/configure
index 7dab897..bf16c0e 100755
--- a/configure
+++ b/configure
@@ -734,6 +734,7 @@ UNIVERSALSDK
 CONFIG_ARGS
 SOVERSION
 VERSION
+PGEN_FOR_BUILD
 PYTHON_FOR_BUILD
 host_os
 host_vendor
@@ -2911,6 +2912,13 @@ else
 fi
 
 
+if test "$cross_compiling" = yes; then
+    PGEN_FOR_BUILD="${PGEN_FOR_BUILD}"
+else
+    PGEN_FOR_BUILD='$(BUILDPGEN)'
+fi
+
+
 
 if test "$prefix" != "/"; then
     prefix=`echo "$prefix" | sed -e 's/\/$//g'`
@@ -6334,6 +6342,12 @@ fi
 
 
 # Enable PGO flags.
+
+
+
+
+
+
 # Extract the first word of "llvm-profdata", so it can be a program name with args.
 set dummy llvm-profdata; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-- 
1.9.1

創建 build 目錄

在 python 源代碼下創建 build-pcbuild-mips 目錄,分別用於編譯 PC pgen(交叉編譯時用到)與交叉編譯 mips python。該目錄做 configure、make、make install,編譯時用於保存臨時生成的文件,保證 python 源代碼乾淨。

編譯本地 Python 與 pgen

用於生成 grammar 所需要文件用。

cd build-pc

../configure CC=gcc CXX=g++ AR=ar RANLIB=ranlib LDFLAGS="-L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64" CFLAGS="-I/usr/include -I/usr/local/include"
 
make python Parser/pgen

配置

配置交叉編譯環境變量

比如 CC、CFLAGS、LDFLAGS 等。

configure 配置

配置命令如下:
configure 的 prefix 只支持絕對路徑。

cd build-mips

../configure --host=mips64-octeon-linux-gnu --build=x86_64-linux-gnu --prefix=/home/sunyongfeng/python-install --disable-ipv6 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no ac_cv_have_long_long_format=yes PGEN_FOR_BUILD=../build-pc/Parse/pgen

問題:

  • --enable-FEATURE,不清楚有哪些 features ,怎麼配置;
  • --enable-PACKAGE,不清楚有哪些 package,怎麼配置。

配置完了之後,在 Modules 目錄會生成 Setup 文件。x86 的默認編譯會編譯到必須的模塊,而 mips64 的交叉編譯很多模塊沒有編譯下,如 socket 等。修改 Modules/Setup 文件,定製想編譯的內置模塊。以下是基礎模塊,目前還不清楚如果不想內置的話要如何編譯。
定製內置模塊,參見這篇博文 《定製 Python 嵌入 C++: (四) 定製 Python 內建模塊》,講述各個內置模塊的功能。

# Modules that should always be present (non UNIX dependent):                                       
                                                                                                    
array arraymodule.c # array objects                                                                 
cmath cmathmodule.c _math.c # -lm # complex math library functions                                  
math mathmodule.c _math.c # -lm # math library functions, e.g. sin()                                
_struct _struct.c   # binary structure packing/unpacking                                            
time timemodule.c # -lm # time operations and variables                                             
operator operator.c # operator.add() and similar goodies                                            
_testcapi _testcapimodule.c    # Python C API test module                                           
_random _randommodule.c # Random number generator                                                   
_collections _collectionsmodule.c # Container types                                                 
_heapq _heapqmodule.c       # Heapq type                                                            
itertools itertoolsmodule.c # Functions creating iterators for efficient looping                    
strop stropmodule.c     # String manipulations                                                      
_functools _functoolsmodule.c   # Tools for working with functions and callable objects             
_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c  # elementtree accelerator
#_pickle _pickle.c  # pickle accelerator                                                            
datetime datetimemodule.c   # date/time type                                                        
_bisect _bisectmodule.c # Bisection algorithms                                                      
                                                                                                    
unicodedata unicodedata.c    # static Unicode character database

編譯

簡單的 make 命令即可。

安裝

命令 make install -i,安裝 binlibshareman 等目錄至 ./configure 中配置的 prefix 目錄。

sunyongfeng@R04220:~/python-install$ ls
bin  include  lib  share
sunyongfeng@R04220:~/python-install$ ls -al *
bin:
總用量 9612
drwxr-xr-x 2 sunyongfeng sunyongfeng    4096  5月 13 16:51 .
drwxr-xr-x 6 sunyongfeng sunyongfeng    4096  5月 15 10:58 ..
-rwxrwxr-x 1 sunyongfeng sunyongfeng     123  5月 13 16:38 2to3
-rwxrwxr-x 1 sunyongfeng sunyongfeng     121  5月 13 16:38 idle
-rwxrwxr-x 1 sunyongfeng sunyongfeng     106  5月 13 16:38 pydoc
lrwxrwxrwx 1 sunyongfeng sunyongfeng       7  5月 13 16:51 python -> python2
lrwxrwxrwx 1 sunyongfeng sunyongfeng       9  5月 13 16:51 python2 -> python2.7
-rwxr-xr-x 1 sunyongfeng sunyongfeng 9793952  5月 13 16:51 python2.7
-rwxr-xr-x 1 sunyongfeng sunyongfeng    1709  5月 13 16:51 python2.7-config
lrwxrwxrwx 1 sunyongfeng sunyongfeng      16  5月 13 16:51 python2-config -> python2.7-config
lrwxrwxrwx 1 sunyongfeng sunyongfeng      14  5月 13 16:51 python-config -> python2-config
-rwxrwxr-x 1 sunyongfeng sunyongfeng   18569  5月 13 16:38 smtpd.py

include:
總用量 12
drwxr-xr-x 3 sunyongfeng sunyongfeng 4096  5月 13 16:51 .
drwxr-xr-x 6 sunyongfeng sunyongfeng 4096  5月 15 10:58 ..
drwxr-xr-x 2 sunyongfeng sunyongfeng 4096  5月 13 16:51 python2.7

lib:
總用量 16312
drwxr-xr-x  4 sunyongfeng sunyongfeng     4096  5月 13 16:51 .
drwxr-xr-x  6 sunyongfeng sunyongfeng     4096  5月 15 10:58 ..
-r-xr-xr-x  1 sunyongfeng sunyongfeng 16670684  5月 13 16:51 libpython2.7.a
drwxr-xr-x  2 sunyongfeng sunyongfeng     4096  5月 13 16:51 pkgconfig
drwxr-xr-x 28 sunyongfeng sunyongfeng    20480  5月 13 16:51 python2.7

share:
總用量 12
drwxr-xr-x 3 sunyongfeng sunyongfeng 4096  5月 13 16:51 .
drwxr-xr-x 6 sunyongfeng sunyongfeng 4096  5月 15 10:58 ..
drwxr-xr-x 3 sunyongfeng sunyongfeng 4096  5月 13 16:51 man
sunyongfeng@R04220:~/python-install$ 

打包放到目標機上,配置目標機的 PATH,加上 python 的 bin 目錄。

問題

編譯依賴

交叉編譯的時候,如果沒有配置好 CFLAGS、LDFLAGS 之類的變量,可能找不到 python 編譯所依賴的頭文件或庫文件。最終體現在編譯的結果(此處可能因不同的變量配置而不同):

Python build finished, but the necessary bits to build these modules were not found:
_bsddb             _curses            _curses_panel   
_sqlite3           _ssl               _tkinter        
bsddb185           bz2                dbm             
dl                 gdbm               imageop         
linuxaudiodev      ossaudiodev        readline        
sunaudiodev        zlib                               
To find the necessary bits, look in setup.py in detect_modules() for the module's name.
  • sqlite3 依賴配置

修改 python 源碼根目錄下的 setup.py 文件,在 detect_modules 函數下,找到 sqlite3 的頭文件配置,添加上交叉編譯下的 sqlite3 頭文件目錄。

        sqlite_inc_paths = [ '/usr/include',                                                        
                             '/usr/include/sqlite',                                                 
                             '/usr/include/sqlite3',                                                
                             '/usr/local/include',                                                  
                             '/usr/local/include/sqlite',                                           
                             '/usr/local/include/sqlite3',                                          
                           ]                                                                        
        if cross_compiling:                                                                         
            sqlite_inc_paths = [ '/home/sunyongfeng/workshop/prj/images/header/',
                                 '/home/sunyongfeng/workshop/prj/images/header/sqlite',
                                 '/home/sunyongfeng/workshop/prj/images/header/sqlite3',
                               ] 
  • ssl 依賴配置

類似 sqlite3,在 setup.py 文件的 detect_modules 函數下,找到 ssl 相關的頭文件與庫文件配置,添加上交叉編譯下的 ssl 頭文件與庫文件目錄。

        # Detect SSL support for the socket module (via _ssl)                                       
        search_for_ssl_incs_in = [                                                                  
                              '/usr/local/ssl/include',                                             
                              '/usr/contrib/ssl/include/',                                          
                              '/home/sunyongfeng/workshop/prj/images/header/',
                             ]                                                                      
        ssl_incs = find_file('openssl/ssl.h', inc_dirs,                                             
                             search_for_ssl_incs_in                                                 
                             )                                                                      
        if ssl_incs is not None:                                                                    
            krb5_h = find_file('krb5.h', inc_dirs,                                                  
                               ['/usr/kerberos/include'])                                           
            if krb5_h:                                                                              
                ssl_incs += krb5_h                                                                  
        ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,                                 
                                     ['/usr/local/ssl/lib',                                         
                                      '/usr/contrib/ssl/lib/',                                      
                                      '/home/sunyongfeng/workshop/prj/images/rootfs/lib64'
                                     ] ) 
  • ncurses

維基百科 ncurses(new curses)是一個程序庫,它提供了API,可以允許程序員編寫獨立於終端的基於文本的用戶界面。它是一個虛擬終端中的“類GUI”應用軟件工具箱。它還優化了屏幕刷新方法,以減少使用遠程shell時遇到的延遲。

  • readline

如果 readline 模塊編譯失敗,會導致退格鍵、方向鍵等不可用。下面錯誤中"^"位置是退格鍵。
交叉編譯 python 前需要先編譯好 libreadline ,並將頭文件和庫文件放到默認可索引到的路徑。

>>> print "abc"
  File "<stdin>", line 1
    print "abc"
               ^
SyntaxError: invalid syntax
>>> 

環境變量

目前還不清楚爲何 export $PATH 後,運行 python 命令找不到 python lib 庫,而且找不到 site 模塊。而使用絕對路徑訪問 python 沒有問題。

/tmp/bin # python
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
ImportError: No module named site

/tmp/bin # /tmp/bin/python
Python 2.7.11 (default, May 16 2016, 17:11:59) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

通過配置環境變量解決:

export PYTHONHOME=/usr/lib/python2.7
export PYTHONPATH=.:$PYTHONHOME:$PYTHONHOME/site-packages
export PATH=$PATH:$PYTHONHOME:$PYTHONPATH

裁剪考慮

  • lib/libpython2.7.a, 16M
  • lib/test, 30M

附一:Python 內建模塊功能說明

直接引自 定製 Python 嵌入 C++: (四) 定製 Python 內建模塊,內容可能已過時,不過有參考價值。

  1. array (Modules/arraymodule.c) (http://docs.python.org/library/array.html) 一個可以存放基本類型的高效數組, 提供了和序列類似的操作. 使用放法類似於 a = array.array('b', [10, 20, 30]), 不常使用, 可以考慮去除.
  2. _ast (Python/Python-ast.c) (http://docs.python.org/library/ast.html) 抽象語法樹, 供 Python 程序解析處理 Python 語法相關的庫, 這個模塊的源代碼是由腳本自動生成的. 由於 Python-ast.c 本身還會被解釋器的其它地方引用, 不能刪除, 所以, 如果是爲了壓縮解釋器大小, 保留這個庫也沒關係. 如果是爲了定製 python 的功能, 也可以屏蔽這個庫, 但是源代碼需要保留, 不能從工程中刪掉.
  3. audioop (Modules/audioop.c) (http://docs.python.org/library/audioop.html) 一個音頻處理的庫, 僅 Win32 平臺有效.
  4. binascii (Modules/binascii.c) (http://docs.python.org/library/binascii.html) 提供二進制和 ASCII 碼的轉換, 會被 uu, base64, binhex 這些庫引用. 建議保留.
  5. cmath (Modules/cmathmodule.c) (http://docs.python.org/library/cmath.html) 提供複數操作的函數
  6. errno (Modules/errnomodule.c) (http://docs.python.org/library/errno.html) 提供標準的錯誤碼定義, 在很多地方中都會使用, 需要保留.
  7. future_builtins (Modules/future_builtins.c) (http://docs.python.org/library/future_builtins.html) 對那些在 Python2.x 和 Python3 中都有但是意義不一樣的函數提供的包裝. 使用這裏面的函數可以保證調用了正確的版本的函數.
  8. gc (Modules/gcmodule.c) (http://docs.python.org/library/gc.html) Python 的垃圾收集接口. 當然保留.
  9. imageop (Modules/imageop.c) (http://docs.python.org/library/imageop.html) 一些圖像處理的函數.
  10. math (Modules/mathmodule.c) (http://docs.python.org/library/math.html) 提供了 C 標準庫中的那些數學函數.
  11. _md5 (Modules/md5module.c) 提供了 MD5 算法.
  12. nt (Modules/posixmodule.c) 一些操作系統習慣的函數, 比如打開文件等等.
  13. operator (Modules/operator.c) (http://docs.python.org/library/operator.html) 提供了操作符的等價函數
  14. signal (Modules/signalmodule.c) (http://docs.python.org/library/signal.html) 信號機制, 提供異步事件的回調.
  15. _sha, _sha256, _sha512 三種 SHA 的加密算法模塊.
  16. strop (Modules/stropmodule.c) 提供了一些優化的字符串操作.
    17.time (Modules/timemodule.c) (http://docs.python.org/library/time.html) 時間操作庫.
  17. thread (Modules/threadmodule.c) Python 線程的底層模塊, threading 會使用 thread 庫.
  18. cStringIO (Modules/cStringIO.c) (http://docs.python.org/library/stringio.html) StringIO 的高效版本.
  19. cPickle (Modules/cPickle.c) (http://docs.python.org/library/pickle.html) Python 的序列化模塊.
  20. msvcrt (PC/msvcrtmodule.c) (http://docs.python.org/library/msvcrt.html) VC 運行時庫的包裝, 包括一些文件和屏幕操作函數.
  21. _locale (Modules/_localemodule.c) 提供本地化支持的模塊.
  22. _subprocess (PC/_subprocess.c) (http://docs.python.org/library/subprocess.html) 操作子進程的庫, 平臺相關的.
  23. _codecs (Modules/_codecsmodule.c) (http://docs.python.org/library/codecs.html) 定義了 Python 的編碼器相關接口.
  24. _weakref (Modules/_weakref.c) (http://docs.python.org/library/weakref.html) 創建對象的弱引用.
  25. _hotshot (Modules/_hotshot.c) (http://docs.python.org/library/hotshot.html) 類似於 Profiler 模塊, 而且將來可能被移除, 現在把它去掉也不錯.
  26. _random (Modules/_randommodule.c) 隨機數模塊.
  27. _bisect (Modules/_bisectmodule.c) (http://docs.python.org/library/bisect.html) 一個基於二分算法, 可以讓插入一個數據島排序的序列後序列仍然有序的庫.
  28. _heapq (Modules/_heapqmodule.c) (http://docs.python.org/library/heapq.html) 實現堆棧數據結構算法的庫.
  29. _lsprof (Modules/_lsprof.c) (http://docs.python.org/library/profile.html) Profiler 模塊, 統計程序執行的性能.
  30. itertools (Modules/itertoolsmodule.c) (http://docs.python.org/library/itertools.html) 一些迭代器操作的模塊.
  31. _collections (Modules/_collectionsmodule.c) (http://docs.python.org/library/collections.html) 提供了幾個高級的容器類.
  32. _symtable (Modules/symtablemodule.c) (http://docs.python.org/library/symtable.html) 符號表管理模塊.
  33. mmap (Modules/mmapmodule.c) (http://docs.python.org/library/mmap.html) 文件內存映射支持模塊.
  34. _csv (Modules/_csv.c) (http://docs.python.org/library/csv.html) 爲 CSV 模塊的內部支持. CSV 模塊提供了讀寫 CSV 文件的功能.
  35. _sre (Modules/_sre.c) 正則表達式的匹配引擎.
  36. parser (Modules/parsermodule.c) (http://docs.python.org/library/parser.html) 操作 Python 語法樹的模塊.
  37. _winreg (PC/_winreg.c) Windows 註冊表操作模塊.
  38. _struct (Modules/_struct.c) 提供在 Python 和 C 之間轉換數據類型的功能.
  39. datetime (Modules/datetimemodule.c) (http://docs.python.org/library/datetime.html) 日期時間操作函數.
  40. _functools (Modules/_functoolsmodule.c) (http://docs.python.org/library/functools.html) 函數相關操作模塊.
  41. _json (Modules/_json.c) (http://docs.python.org/library/json.html) JSON 數據格式操作模塊.
  42. xxsubtype (Modules/xxsubtype.c) 這是一個測試相關的模塊. 運行 test_descr.py 時會用到.
  43. zipimport (Modules/zipimport.c) 這個模塊主要用於從 zip 文件中導入 Python 的模塊.
  44. zlib (Modules/zlibmodule.c) 這個模塊提供了 zip 壓縮和解壓功能, 基於 GNU zip 實現.
  45. _multibytecodec, _codecs_cn, _codecs_hk, _codecs_iso2022, _codecs_jp, _codecs_kr, _codecs_tw (Modules/cjkcodecs/*) 這些模塊提供了 CJK(中日韓統一表意文字) 的編碼和解碼. 去掉這部分可以減小 python 解釋器 600 多 K.
  46. marshal (Python/marshal.c) (http://docs.python.org/library/marshal.html) 爲 Python 對象提供序列化的模塊.
  47. imp (Python/import.c) (http://docs.python.org/library/imp.html) 這個模塊提供了 Python 裏的 import 語句的實現.
  48. main, builtin, sys, exceptions, _warnings 這部分模塊在 config.c 設置裏只是一個名字佔位符.
  49. _io (Modules/_iomodule.c) (http://docs.python.org/library/io.html) 新版本的 Python 輸入輸出模塊, 在 Python 3 中爲默認的輸入輸出處理方法.

附二:Python 最佳編譯依賴

直接譯自 Python Deployment

鍵入如下命令自動安裝一些依賴:

$ sudo apt-get build-dep python2.7

確認安裝如下列下的其他 -dev 包。

  • python-dev
  • libncurses5-dev
  • libsqlite3-dev
  • libbz2-dev
  • libreadline-dev
  • libdb4.8-dev
  • tcl8.5-dev,tk8.5-dev

下面這個包在 ubuntu 早期版本(如 10.04)並沒有自動安裝,需確認一下。

  • libssl-dev
  • libexpat1-dev
  • libreadline6-dev
  • libgtk2.0-dev

如果想支持 xml 相關:

  • libxml2-dev
  • libxslt1-dev

如果想支持 MySQLdb (在 pypi 中實際命令爲 MySQL-python):

  • libmysqlclient-dev

最終的 make 結果(編譯結果)如能如下:

Python build finished, but the necessary bits to build these modules were not found:
_tkinter           bsddb185           dl
gdbm               imageop            sunaudiodev
To find the necessary bits, look in setup.py in detect_modules() for the module's name.

這個編譯 log 提示哪些模塊沒有被編譯到,注意其中有一些並不是必需的或過時的:

  • bsddb185: Older version of Oracle Berkeley DB. Undocumented. Install version 4.8 instead.
  • dl: For 32-bit machines. Deprecated. Use ctypes instead.
  • imageop: For 32-bit machines. Deprecated. Use PIL instead.
  • sunaudiodev: For Sun hardware. Deprecated.
  • _tkinter: For tkinter graphy library, unnecessary if you don't develop tkinter programs.

參考文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章