Linux 交叉編譯簡介


Linux 交叉編譯簡介

主機,目標,交叉編譯器

主機與目標

編譯器是將源代碼轉換為可執行代碼的程序。像所有程序一樣,編譯器運行在特定類型的計算機上,輸出的新程序也運行在特定類型的計算機上。

運行編譯器的計算機稱為主機,運行新程序的計算機稱為目標。當主機和目標是同一類型的機器時,編譯器是本機編譯器。當宿主和目標不同時,編譯器是 交叉編譯器

 

為什么要交叉編譯?

某些設備構建程序的PC,用戶可以獲得適當的目標硬件(或模擬器),啟動 Linux Release版,在該環境中進行本地編譯。這是一種有效的方法(在處理 Mac Mini時甚至可能是一個好主意),但對於 linksys 路由器,或 iPod,有一些突出的缺點:

  • 速度- 目標平台通常比主機慢一個數量級或更多。大多數專用嵌入式硬件是為低成本和低功耗而設計的,而不是高性能。由於在高性能桌面硬件上運行,現代模擬器(如 qemu)實際上比模擬的許多現實世界的硬件要快。
  • 性能- 編譯非常耗費資源。目標平台通常沒有台式機GB 內存和數百 GB 磁盤空間;甚至可能沒有資源來構建“hello world”,更不用說大而復雜的包了。
  • 可用性-未運行過的硬件平台上運行 Linux,需要交叉編譯器。即使在 Arm 或 Mips 等歷史悠久的平台上,給定目標找到最新的全功能預構建本機環境很困難。如果平台通常不用作開發工作站,可能沒有現成的最新預構建Release版,如果有,則可能已經過時。如果必須先為目標構建Release版,才能在目標上進行構建,無論如何都將返回交叉編譯。
  • 靈活性- 功能齊全的 Linux Release版,由數百個軟件包組成,但交叉編譯環境可以從大多數方面依賴於主機的現有Release版。交叉編譯的重點是構建要部署的目標包,不是花時間獲取在目標系統上運行的僅構建先決條件。
  • 方便-用戶界面不友好,debug構建中斷不方便。從 CD 安裝到沒有 CD-ROM 驅動器的機器上,在測試環境和開發環境之間來回重新啟動。

 

 

 為什么交叉編譯很難?

便攜式本機編譯很困難。

大多數程序是在 x86 硬件上開發的,在本地編譯的。交叉編譯會遇到兩種類型的問題:程序本身的問題和構建系統的問題。

第一類問題會影響所有非 x86 目標,包括本機和交叉構建。大多數程序對運行的機器類型做出假設,必須與相關平台匹配,否則程序將無法運行。常見的假設包括:

  • Word size - 將指針復制到 int 可能會在 64 位平台上丟失數據,通過乘以 4 而不是 sizeof(long) ,確定 malloc 的大小不好。整數溢出導致細微安全漏洞,ala“if (x+y < size) memset(src+x,0,y);”,當 x=1000 時,在 32 位硬件上產生 4 GB 的 memset y=0xFFFFFFF0...
  • Endianness - 不同的系統用不同的方式在內部存儲二進制數據,從磁盤或網絡中,讀取 int 或 float 數據可能需要轉換。
  • Alignment - 某些平台(例如 arm)只能從 4 字節的偶數倍的地址,讀取或寫入整數,否則出現段錯誤。處理任意alignment的處理,未alignment的數據都較慢,編譯器通常會填充結構alignment變量。將結構視為可以發送到磁盤或通過網絡發送的數據塊,需要額外的工作確保一致的表示。
  • 默認簽名- “char”數據類型,默認為有符號或無符號,因平台而異(從編譯器到編譯器),導致一些非常令人驚訝的錯誤。簡單解決方法是提供一個編譯器參數,如“-funsigned-char”,強制默認值為已知值。
  • NOMMU - 如果目標平台沒有內存管理單元,需要更改幾項內容。需要 vfork(),不是 fork(),只有某些類型的 mmap() 工作(共享或只讀,但不能在寫入時復制),堆棧不會動態增長。

大多數包的目標是在本地編譯時可移植,至少會接受補丁,修復提交到適當的開發郵件列表的任何上述問題(NOMMU 問題除外)。

然后是交叉編譯。

 

 

 除了本機編譯的問題外,交叉編譯還有其自身的一系列問題:

  • 配置問題- 具有單獨配置步驟的包(標准 configure/make/make install 的“./configure”部分),通常會測試字節順序或頁面大小等內容,在本機編譯時可移植。交叉編譯時,這些值在主機系統和目標系統之間不同,在主機系統上運行測試,給出錯誤的答案。當目標沒有該軟件包或版本不兼容時,配置檢測主機上,是否存在軟件包支持。
  • HOSTCC vs TARGETCC -構建過程需要編譯在主機系統上運行,如上述配置測試,或生成代碼的程序(如創建 .h 文件的 C 程序,在main構建期間 #included )。用目標編譯器替換主機編譯器,破壞在構建過程中運行庫。這樣的庫需要訪問主機和目標編譯器,需要說明何時使用。
  • 工具鏈泄漏- 配置不當的交叉編譯工具鏈,將主機系統的一些內容泄漏到已編譯的程序中,導致通常易於檢測,但難以診斷和糾正的故障。工具鏈可能 #include 錯誤的頭文件,或在鏈接時搜索錯誤的庫路徑。共享庫通常依賴於其它共享庫,可能會潛入對主機系統的意外鏈接時引用。
  • - 動態鏈接的程序必須在編譯時,訪問適當的共享庫。目標系統的共享庫,需要添加到交叉編譯工具鏈中,以便程序可以鏈接到。
  • 測試- 在本機構建上,開發系統提供了方便的測試環境。交叉編譯時,確認“hello world”構建成功,可能需要(至少)配置引導加載程序,內核,根文件系統和共享庫。

 

腳注 1:計算機類型之間最顯着的區別是執行程序的處理器,其它差異包括庫 ABI(例如 glibc 與 uClibc),具有可配置字節序的機器(arm 與 armeb),或不同模式的機器,可以運行 32 位和 64 位代碼(例如 x86 上的 x86-64)。

腳注 2:在構建編譯器時,第三種類型稱為“加拿大交叉”,一種不在主機系統上運行的交叉編譯器。加拿大交叉構建了一個編譯器,該編譯器在一個目標平台上運行,另一台目標機器生成代碼。首先創建從主機到第一個目標的臨時交叉編譯器,作為第二個目標構建另一個交叉編譯器構建這樣的外部編譯器。第一個交叉編譯器的目標成為運行新編譯器的主機,第二個目標是新編譯器生成輸出的平台。這種技術通常用於為目標平台交叉編譯新的本機編譯器。

腳注 3:現代桌面系統足夠快,模擬目標在模擬器下進行本地編譯,實際上是一種可行的策略。比交叉編譯慢得多,需要為目標查找或生成本機構建環境(無論如何都必須設置交叉編譯器),可能會因模擬器和要部署的真實硬件之間的差異崩潰。

腳注 4:交叉編譯工具鏈傾向於為其實用程序的名稱加上前綴,ala “armv5l-linux-gcc”。如果簡單地稱為“gcc”,主機和本機編譯器就不能同時在 $PATH 中。

 

 

 

 

 

 

參考鏈接:

http://landley.net/writing/docs/cross-compiling.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM