\
當編譯器運行在一個為另一系統產生可執行程序的系統上時,就會出現交叉編譯——當目標系統沒有編譯工具的本地設置時,或者當主機系統更快或具有更多資源時,這是一個重要的概念。在這篇 how-to 文章中,Peter Seebach 討論了交叉編譯環境的初始設置(使用 Sharp Zaurus 手持計算機作為焦點),並且介紹了工具的安裝、基本編譯、在 Sharp Zaurus 手持計算機上安裝程序,以及像創建使用 configure 腳本的程序這樣的高級問題。 通常,程序是在一台計算機上編譯,然後再分布到將要使用的其他計算機上。當主機系統(運行編譯器的系統)和目標系統(產生的程序將在其上運行的系統)不兼容時,該過程就叫做交叉編譯。 除了兼容性這個明顯的好處之外,交叉編譯還由於以下兩個原因而非常重要: 當目標系統對其可用的編譯工具沒有本地設置時。 當主機系統比目標系統要快得多,或者具有多得多的可用資源時。 在這篇文章中,我將使用手持計算機的 Sharp Zaurus 系列作為焦點,討論交叉編譯環境的初始設置。我將介紹工具的安裝、基本編譯問題、如何在手持計算機上安裝程序,以及像創建使用 configure 腳本的程序這樣的高級問題。如果按照文章的組織順序閱讀,您將最大地從本文受益,因為本文類似於一個教程,每一步都以邏輯順序相連。 首先,我將給出交叉編譯的一個簡潔的概覽。 理解交叉編譯 如果您熟悉交叉編譯環境,則可以跳過這一節。但是如果不了解交叉編譯,則請繼續往下閱讀。 我使用的開發系統是 x86 體系結構的 Linux 系統。我在 SuSE Linux 8.2 上測試了這些指令。測試的目標系統是 Sharp Zaurus SL-5600 和 C700。本文假設您具有 Unix 開發實踐的工作背景,並使用過命令行。 正如我前面提到的,當編譯器運行在一個為另一個系統產生可執行程序的系統上而且兩個系統使用不同的操作環境時就會出現交叉編譯。 另外,當目標系統不具有它自己的編譯工具時,或者當開發者可以平衡主機系統潛在更好的性能或更多的資源時,交叉編譯是有用的。 當提到交叉編譯器時,我不僅僅是指將一種編程語言的代碼轉換成對象代碼的軟件,還指其他必要的開發工具: 一個匯編器,它是編譯器工具鏈後端的一部分。 一個鏈接器,它是編譯器工具鏈後端的另一部分。 用於處理可執行程序和庫的一些基本工具,比如strings。 例如,strings 實用工具(它輸出對象模塊的文本字符串)可能是有用的,但是主機環境版本對目標環境二進制系統並不怎麼有用。Zaurus 的交叉開發工具中包含 strings。 在 Zaurus 上本地運行編譯器是可能的,但是系統的局限性阻礙有效的工作,這也是使交叉編譯為開發者帶來福音的另一個原因。典型台式機的顯示器和鍵盤非常有利於編輯工作。另外,台式機的內存、處理器和存儲容量也更能滿足編譯的資源需要。 現在,讓我們來安裝所需的工具。 安裝工具 開始,您必須下載幾個軟件包。可以從 Sharp 的 Web 站點(在 參考資料 部分有到該站點的鏈接)得到這些軟件包,並且必須下載為 RPM。您需要以下主要的軟件包: 交叉編譯器 (gcc)。 庫 (glibc)。 包含文件 (頭文件)。 “其他工具”——一個包含交叉開發環境中常用工具的軟件包 。 接下來,安裝 RPM。要做這一點,需要 root 權限。建議的安裝方法是為每個文件重復 rpm -Uvh filename.rpm。 文件安裝在 /opt/Embedix 目錄中。該目錄有一個稍微不尋常的結構——實際的二進制文件安裝在 /opt/Embedix/tools/bin 目錄中,具有到安裝在 /opt/Embedix/tools/arm-linux/bin 目錄中的這些二進制文件的符號鏈接。例如,/opt/Embedix/tools/arm-linux/bin/gcc 是到 /opt/Embedix/tools/bin/arm-linux-gcc 的一個符號鏈接。二者都可以使用。 編譯一個簡單的測試程序,快速測試已經正確地安裝了工具。我推薦傳統的 "Hello, world!" 程序,這易於測試: 清單 1. 測試正確的安裝 #include < stdio.h> int main(void) { printf("Hello, world!"); return 0; } 將該測試程序保存在一個叫做 hello.c 的文件中,並編譯它。到編譯器的兩條路徑都可以工作——我喜歡使用 /opt/Embedix/tools/arm-linux/bin/gcc。編譯完程序之後,利用 file 命令檢查輸出文件的類型。 清單 2. 使用 file 命令檢查輸出的類型 $ /opt/Embedix/tools/arm-linux/bin/gcc -o hello hello.c $ file hello hello: ELF 32-bit LSB executable, ARM, version 1 (ARM), dynamically linked (uses shared libs), not stripped 您可能對這一簡短的偏離主題感興趣。還記得我什麼時候提到過 strings 程序嗎?我們來試一試該程序。 首先, 在您的二進制系統上運行本地 strings 程序: 清單 3. 運行本地 strings 程序 $ /usr/bin/strings hello 接下來,在相同的二進制系統上運行 ARM 版本: 清單 4. ARM 版本 $ /opt/Embedix/tools/arm-linux/bin/strings hello 在我的測試系統上,這些產生了稍微不同的結果。特定於 ARM 的 strings 程序發現一個特定於 i386 的版本未發現的新字符串。 現在,我們在目標系統上測試該程序。 在目標系統上安裝應用程序 將文件移動到目標系統有幾種方式: 使用標准的 Zaurus sync 軟件進行轉移。 復制到介質上。 通過網絡移動。 使用無線卡或以太網適配器可能是移動文件最容易的方式。如果這樣不行,將文件復制到 CompactFlash 或 SecureDigital 介質上也是相當方便的。不幸的是,在發布本文時,Sharp 還未正式在 Linux 下支持 sync,但是復制到介質隨處可用。 根據您的 Zaurus 上的 ROM 版本的不同,系統可能不識別或安裝 ext2fs 卡。因此,通過 FAT16 格式化的卡復制文件可能更實用一些。CF 和 SD 卡一般在出廠前已經這樣格式化了,所以它們可以開箱即用。 (簡要的術語提示:ext2fs 卡是為 Linux 文件系統格式化過的存儲卡。FAT16格式化的卡是為老式的 MS-DOS 文件系統格式化過的存儲卡。CF 卡是 CompactFlash,這是一些數碼相機使用的一種介質標准。多數 CF 設備是存儲設備,但是 CF Ethernet、無線和串行適配器也存在。SD(或者叫做 Secure Digital)卡是 MultiMediaCard 技術與我們的目的之間的一個聯系,SD 卡就像一個永久保存10%空間的 MMC 卡。) 就將您的可執行文件復制到一個已安裝的卡。當將該卡移動到 Zaurus 時,它就會自動地安裝為 /usr/mnt.rom/cf。現在您就可以從卡運行應用程序了。 清單 5. 從卡運行應用程序 $ /usr/mnt.rom/cf/hello Hello, world! 現在您已經嘗試了該程序,不過您可能更喜歡 Zaurus 的 ipkg 二進制軟件包格式。ipkg 文件只是一個包含三個其他文件的 tar 文件: 第一個文件,即 data.tar.gz,是一個壓縮的 tar 文件,其中包含將被安裝到正確目錄結構中的多個文件。 第二個文件,即 control.tar.gz,是一個壓縮的 tar 文件,其中包含安裝腳本和信息。 第三個文件,即 debian-binary,是一個純文本文件,其中包含字符串“2.0”。該文件目前不真正做任何事情,但是一些工具期望該文件可用。 盡管有一個方便的腳本可為您做這項工作,但是您也可以手動創建 ipkg 文件。為防萬一您確實想要手動創建一個 ipkg 文件,所以我將簡要討論這種軟件包的格式。利用您將使用的標准軟件安裝器,該軟件包將正確地安裝 "hello" 程序。 創建一個名叫 h 的新目錄用於保存文件。名稱並不一定要叫 h,但是因為後面老要鍵入它,所以使用一個簡短的名稱。 創建一個名叫 h/opt/QtPalmtop/bin 的子目錄,並將您的 "hello" 可執行文件復制到該目錄。這對於顯示所安裝的程序是一個好目錄。 創建一個名叫 h/CONTROL 的目錄。該目錄形成 control.tar.gz 文件的內容;h 中的其他東西都放入 data.tar.gz 文件中。在該目錄中,您只需要一個文件,叫做 control。將以下數據放入該文件中: 清單 6. 將要放入 control 文件中的信息 Package: hello Priority: optional Section: Misc Version: 1.0 Architecture: arm Maintainer: Your name ([email protected]) Depends: libc6 Description: Just as stores have greeters, so to do PDAs have greeters. This is a longer description, separate from the first one, which can be multiple lines long, with each line indented by a single space. 還有其他可以放入到 CONTROL 目錄中的文件,但是您並不需要這些文件。請參考 參考資料,在 Zaurus 開發者文檔中了解該主題的附加信息。 運行 ipkg_build.sh h。如果前面所做的每一件事情都正確,您應該得到一個名叫 hello_1.0_arm.ipk 的文件。將該文件復制到您的 Zaurus ——不管如何復制都無所謂——並在 Zaurus 上運行 Add/Remove Software 程序。 安裝 hello,即您應該在軟件包列表中看到的版本 1.0 文件。現在就可以從命令行運行它了;它已經被復制到 /opt/QtPalmtop/bin 目錄中了。如果您將它安裝到一個介質插槽中而不是內部閃存中,它將在該卡上的 QtPalmtop/bin 目錄中。例如,如果安裝到 SD,它將被安裝為 /usr/mnt.rom/card/QtPalmtop/bin/hello。 ipkg_build.sh shell 腳本對產生錯誤消息比較有效,但是它們可能會有些容易混淆。實際上,如果您在 control 文件中放入注釋(我就是這樣做的!),# 字符就會被解釋為一個字段名稱,從而產生以下錯誤消息: 清單 5. 啊呀!請不要在 control 文件中放入注釋 *** Error: The following fields in CONTROL/control are missing a ':' ### ipkg-build: This may be due to a missing initial space for a multi-line field value 當我第一次看到該消息時有些被搞胡塗了。 復雜編譯 一旦您讓編譯器創建了在目標系統上正確運行的可執行程序,您就會開始遇到令人激動的問題了。 使用 autoconf 的程序可能不支持交叉創建。當已編譯的二進制文件被使用在創建過程中時,就會出現惟一真正固定不變的情況。不幸的是,對於使用 autoconf 的程序,這是一種相當常見的情況。 對於一個相當標准的沒有太多依賴性的程序,您可能只是忽略選擇 C 編譯器。FIGlet 是一個程序,用於從平常的文本制造出大字母,如圖 1 所示,通過更改 makefile 中的 CC=... 行可以創建該程序。但是,安裝稍微有些有趣。
圖 1. 文本 "like this" 的 FIGlet 輸出樣例
FIGlet 想要找到一些數據文件,所以您必須安裝數據文件和程序。makefile 文件中對應的行是 DEFAULTFONTDIR = /usr/local/share/figlet。 (注意,有兩行設置 DEFAULTFONTDIR;在設置時請確保只使用其中一行。) 一旦利用更改的 makefile 創建了 figlet,就可以創建它的一個軟件包了。創建一個新的目錄(這裡叫做 f)。 這時,創建一個二進制目錄和一個數據目錄。二進制目錄是 f/opt/QtPalmtop/bin,而數據目錄是 f/usr/local/share/figlet。將 figlet、chkfont 和 showfigfonts 復制到 f/QtPalmtop/bin 中;然後將 fonts/* 復制到 f/usr/local/share/figlet 中。從上一個項目復制到 CONTROL 目錄,並編輯 control 文件以給出軟件包的名稱和版本。同樣,build-ipkg.sh 可以為您完成這份苦差使。 有些程序可能需要更多的技巧。例如,要創建 pdksh,您使用 CC=/opt/Embedix/tools/bin/arm-linux-gcc sh configure。該創建過程犯了一個小小的錯誤——它將兩個宏 SIZEOF_INT 和 SIZEOF_LONG 都定義為 0。它們應該是 4。 這些宏是通過試圖編譯和運行輸出 sizeof(int) 的測試程序而定義的,但是當然,arm-processor 程序不運行在 x86 主機上,所以這些測試失敗。在這種情況下,您可以只是編輯 confdefs.h 文件,更改宏,然後繼續。只要知道出了什麼錯就不難糾正,但是出了什麼錯並不是那麼明顯。當它確定一個類型的大小為 0 時,讓配置腳本以重大錯誤異常終止可能還要好一些。 使用一個聰明的 hack,autoconf 的一些最近版本可以解決該問題。只是在 configure.in 文件上重新運行一個當前的 autoconf 就可以幫助解決一些問題,尤其是當軟件包過期時, 但是在老的 configure.in 文件中有時會有一些腐舊的東西。 在比較一般的情況下,您可能只是要手動編輯配置腳本或設置程序,以迫使它們獲得正確的結果。在極端的情況下,可能有必要試圖進行費事的程序“挖口”,比如在一台安裝了本地開發工具的 Zaurus 上本地運行配置腳本,然後將所有文件移回桌面開發系統 ,更改編譯路徑,並從這裡啟動。 結束語 很多開發者還在猶豫是否嘗試交叉編譯,因為它聽起來比實際要難得多。本文通過給出交叉編譯的一個概覽,幫助您開始了解交叉編譯技術。本文提供了一些例子,講述設置一個系統以實現交叉編譯的程序。本文還提供了一些參考資料,以幫助您設置一個為 Sharp Zaurus 手持計算機進行開發的系統。