在linux中,交叉編譯是指在一個平台上產生另一個平台上的可執行程式碼,即編譯原始碼的平台和執行原始碼編譯後程式的平台是兩個不同的平台。使用交叉編譯的原因:1、目標系統沒有能力在其上進行本地編譯;2、有能力進行原始碼編譯的平台與目標平台不同。
本教學操作環境:linux5.9.8系統、Dell G3電腦。
交叉編譯
所謂"交叉編譯(Cross_Compile)",是指編譯原始碼的平台和執行原始碼編譯後程式的平台是兩個不同的平台。例如,在Intel x86架構/Linux(Ubuntu)平台下、使用交叉編譯工具鏈產生的可執行文件,在ARM架構/Linux下運作。
簡單來說,就是在一個平台上產生另一個平台上的 執行程式碼。同一個 體系結構可以運作不同的作業系統;同樣,同一個作業系統也可以在不同的體系結構上運作。
交叉編譯是相對複雜的,必須考慮以下幾個問題:
CPU架構:例如ARM,x86,MIPS等等;
位元組序:大端(big-endian)和小端(little-endian);
浮點數的支援;
應用程式二進位介面(Application Binary Interface,ABI);
為什麼要使用交叉編譯呢?主要有兩個原因:
交叉編譯的目標系統一般都是記憶體較小、顯示設備簡陋甚至沒有,沒有能力在其上進行本地編譯;
有能力進行原始碼編譯的平台CPU架構或作業系統與目標平台不同;
交叉編譯工具鍊是進行交叉編譯的必必不可少的工具,是嵌入式開發人員必須熟練的技能。
為什麼交叉編譯很難?
可攜式本機編譯很困難。
大多數程式是在 x86 硬體上開發的,在本地編譯的。交叉編譯會遇到兩種類型的問題:程式本身的問題和建置系統的問題。
第一類問題會影響所有非 x86 目標,包括本機和交叉建置。大多數程式對運行的機器類型做出假設,必須與相關平台匹配,否則程式將無法運行。常見的假設包括:
Word size - 將指標複製到int 可能會在64 位元平台上遺失數據,透過乘以4 而不是sizeof(long) ,確定malloc 的大小不好。整數溢位導致細微安全漏洞,ala“if (x y
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 中。
相關推薦:《Linux影片教學》
以上是什麼是linux交叉編譯的詳細內容。更多資訊請關注PHP中文網其他相關文章!