1. 程式人生 > >交叉編譯詳解 一 概念篇

交叉編譯詳解 一 概念篇

第 1 章 交叉編譯簡介

1.1 什麼是交叉編譯

對於沒有做過嵌入式程式設計的人,可能不太理解交叉編譯的概念,那麼什麼是交叉編譯?它有什麼作用?

在解釋什麼是交叉編譯之前,先要明白什麼是本地編譯。

本地編譯

本地編譯可以理解為,在當前編譯平臺下,編譯出來的程式只能放到當前平臺下執行。平時我們常見的軟體開發,都是屬於本地編譯:

比如,我們在 x86 平臺上,編寫程式並編譯成可執行程式。這種方式下,我們使用 x86 平臺上的工具,開發針對 x86 平臺本身的可執行程式,這個編譯過程稱為本地編譯。

交叉編譯

交叉編譯可以理解為,在當前編譯平臺下,編譯出來的程式能執行在體系結構不同的另一種目標平臺上,但是編譯平臺本身卻不能執行該程式:

比如,我們在 x86 平臺上,編寫程式並編譯成能執行在 ARM 平臺的程式,編譯得到的程式在 x86 平臺上是不能執行的,必須放到 ARM 平臺上才能執行。

1.2 為什麼會有交叉編譯

之所以要有交叉編譯,主要原因是:

  • Speed: 目標平臺的執行速度往往比主機慢得多,許多專用的嵌入式硬體被設計為低成本和低功耗,沒有太高的效能
  • Capability: 整個編譯過程是非常消耗資源的,嵌入式系統往往沒有足夠的記憶體或磁碟空間
  • Availability: 即使目標平臺資源很充足,可以本地編譯,但是第一個在目標平臺上執行的本地編譯器總需要通過交叉編譯獲得
  • Flexibility: 一個完整的Linux編譯環境需要很多支援包,交叉編譯使我們不需要花時間將各種支援包移植到目標板上

1.3 為什麼交叉編譯比較困難

交叉編譯的困難點在於兩個方面:

不同的體系架構擁有不同的機器特性

  • Word size: 是64位還是32位系統
  • Endianness: 是大端還是小端系統
  • Alignment: 是否必修按照4位元組對齊方式進行訪問
  • Default signedness: 預設資料型別是有符號還是無符號
  • NOMMU: 是否支援MMU

交叉編譯時的主機環境與目標環境不同

  • Configuration issues:
  • HOSTCC vs TARGETCC:
  • Toolchain Leaks:
  • Libraries:
  • Testing:

第 2 章 交叉編譯鏈

2.1 什麼是交叉編譯鏈

明白了什麼是交叉編譯,那我們來看看什麼是交叉編譯鏈。

首先編譯過程是按照不同的子功能,依照先後順序組成的一個複雜的流程,如下圖:

編譯流程

那麼編譯過程包括了預處理、編譯、彙編、連結等功能。既然有不同的子功能,那每個子功能都是一個單獨的工具來實現,它們合在一起形成了一個完整的工具集。

同時編譯過程又是一個有先後順序的流程,它必然牽涉到工具的使用順序,每個工具按照先後關係串聯在一起,這就形成了一個鏈式結構。

因此,交叉編譯鏈就是為了編譯跨平臺體系結構的程式程式碼而形成的由多個子工具構成的一套完整的工具集。同時,它隱藏了預處理、編譯、彙編、連結等細節,當我們指定了原始檔(.c)時,它會自動按照編譯流程呼叫不同的子工具,自動生成最終的二進位制程式映像(.bin)。

注意:嚴格意義上來說,交叉編譯器,只是指交叉編譯的gcc,但是實際上為了方便,我們常說的交叉編譯器就是交叉工具鏈。本文對這兩個概念不加以區分,都是指編譯鏈

2.2 交叉編譯鏈的命名規則

我們使用交叉編譯鏈時,常常會看到這樣的名字:

arm-none-linux-gnueabi-gcc
arm-cortex_a8-linux-gnueabi-gcc
mips-malta-linux-gnu-gcc

其中,對應的字首為:

arm-none-linux-gnueabi-
arm-cortex_a8-linux-gnueabi-
mips-malta-linux-gnu-

這些交叉編譯鏈的命名規則似乎是通用的,有一定的規則:

arch-core-kernel-system
  • arch: 用於哪個目標平臺。
  • core: 使用的是哪個CPU Core,如Cortex A8,但是這一組命名好像比較靈活,在其它廠家提供的交叉編譯鏈中,有以廠家名稱命名的,也有以開發板命名的,或者直接是none或cross的。
  • kernel: 所執行的OS,見過的有Linux,uclinux,bare(無OS)。
  • systen:交叉編譯鏈所選擇的庫函式和目標映像的規範,如gnu,gnueabi等。其中gnu等價於glibc+oabi;gnueabi等價於glibc+eabi。

注意:這個規則是一個猜測,並沒有在哪份官方資料上看到過。而且有些編譯鏈的命名確實沒有按照這個規則,也不清楚這是不是歷史原因造成的。如果有誰在資料上見到過此規則的詳細描述,歡迎指出錯誤。

第 3 章 包含的工具

3.1 Binutils

Binutils是GNU工具之一,它包括連結器、彙編器和其他用於目標檔案和檔案的工具,它是二進位制程式碼的處理維護工具。

Binutils工具包含的子程式如下:

  • ld GNU聯結器the GNU linker.
  • as GNU彙編器the GNU assembler.
  • addr2line 把地址轉換成檔名和所在的行數
  • ar A utility for creating, modifying and extracting from archives.
  • c++filt Filter to demangle encoded C++ symbols.
  • dlltool Creates files for building and using DLLs.
  • gold A new, faster, ELF only linker, still in beta test.
  • gprof Displays profiling information.
  • nlmconv Converts object code into an NLM.
  • nm Lists symbols from object files.
  • objcopy Copys and translates object files.
  • objdump Displays information from object files.
  • ranlib Generates an index to the contents of an archive.
  • readelf Displays information from any ELF format object file.
  • size Lists the section sizes of an object or archive file.
  • strings Lists printable strings from files.
  • strip Discards symbols

3.2 GCC

GNU編譯器套件,支援C, C++, Java, Ada, Fortran, Objective-C等眾多語言。

3.3 GLibc

Linux上通常使用的C函式庫為glibc。glibc是linux系統中最底層的api,幾乎其它任何執行庫都會依賴於glibc。glibc除了封裝linux作業系統所提供的系統服務外,它本身也提供了許多其它一些必要功能服務的實現。

因為嵌入式環境的資源及其緊張,所以現在除了glibc外,還有uClibc和eglibc可以選擇,三者的關係可以參見這兩篇文章:

3.4 GDB

GDB用於除錯程式

第 4 章 如何得到交叉編譯鏈

既然明白了交叉編譯鏈的功能,那麼在針對嵌入式系統開發時,我們需要的交叉編譯鏈從哪兒得到?

主要有三個方式可以獲取

4.1 下載已經做好的交叉編譯鏈

使用其他人針對某些CPU平臺已經編譯好的交叉編譯鏈。我們只需要找到合適的,下載下來使用即可。

常見的交叉編譯鏈下載地址:

廠家提供的工具一般是經過了嚴格的測試,並打入了一些必要的補丁,所以這種方式往往是最可靠的工具來源。

4.2 使用工具定製交叉編譯鏈

使用現存的製作工具,以簡化製作交叉編譯鏈這個事情的複雜度。我們只需要瞭解有哪些工具可以實現,並選個合適的工具,搞懂它的操作步驟即可。

  1. crosstool-NG
  2. Buildroot
  3. Embedded Linux Development Kit (ELDK)

工具還有很多,各有各的優勢和劣勢,大家可以慢慢研究,在這就不細說了。

4.3 從零開始構建交叉編譯鏈

這個是最困難也最耗時間的,畢竟製作交叉編譯鏈這樣的事情,需要對嵌入式的編譯原理了解的比較透徹,至少要知道出了問題要往哪個方面去翻閱資料。而且,也是最考耐心和細心的地方,配錯一個選項或是一個步驟,都可能出現以前從來沒見過的問題,而且這些問題往往還無法和這個選項或步驟直接聯絡起來。

當然如果搭建出來,肯定也是收穫最大的,至少對於編譯的流程和依賴都比較清楚了,細節上的東西可能還需要去翻看相應的協議或標準,但至少骨架會比較清楚。

詳細的搭建過程可以參看後續的文章,這裡面有詳細的引數和步驟:
交叉編譯詳解 二 從零製作交叉編譯鏈

為了方便大家搭建交叉編譯鏈,我寫了一個一鍵生成的指令碼(包括原始碼下載和自動編譯)。如果大家自己一直搭建不成功,不妨試試這個指令碼,然後對比下自己的流程是否一致,引數是否有差異,也許能幫大家邁過這個障礙:
交叉編譯詳解 三 使用指令碼自動生成交叉編譯鏈

4.4 對比三種構建方式

專案 使用已有交叉編譯鏈 自己製作交叉編譯鏈
安裝 一般提供壓縮包 需要自己打包
原始碼版本 一般使用較老的穩定版本,對於一些新的GCC特性不支援 可以使用自己需要的GCC特性的版本
補丁 一般都會打上修復補丁 普通開發者很難辨別需要打上哪些補丁,資深開發者可以針對自己的需求合入補丁
原始碼溯源 可能不清楚原始碼版本和補丁情況 一切都可以定製
升級 一般不會升級 可以隨時升級
優化 一般已經針對特定CPU特性和效能進行優化 一般無法做到比廠家優化的更好,除非自己設計的CPU
技術支援 可以通過FAE進行支援,可能需要收費 只能通過社群支援,免費
可靠性驗證 已經通過了完善的驗證 自己驗證,肯定沒有專業人士驗證的齊全

參考資料

[6] 交叉編譯鏈下載地址

相關推薦

交叉編譯 概念

第 1 章 交叉編譯簡介 1.1 什麼是交叉編譯 對於沒有做過嵌入式程式設計的人,可能不太理解交叉編譯的概念,那麼什麼是交叉編譯?它有什麼作用? 在解釋什麼是交叉編譯之前,先要明白什麼是本地編譯。 本地編譯 本地編譯可以理解為,在當前編譯平臺下,編

交叉編譯

arch soft inf 詳解 處理 cortex a8 del ldr 研究 第 1 章 交叉編譯簡介 1.1 什麽是交叉編譯 對於沒有做過嵌入式編程的人,可能不太理解交叉編譯的概念,那麽什麽是交叉編譯?它有什麽作用? 在解釋什麽是交叉編譯之前,先要明白什麽是本地編譯。

【強化學習】--強化學習案例

AC 沒有 技術 技術分享 ron png strong http mage 一、前述 本文通過一個案例來講解Q-Learning 二、具體 1、案例 假設我們需要走到5房間。 轉變為如下圖:先構造獎勵,達到5,即能夠走得5的action則說明獎勵比較高設置成100,沒有

Shell---搞定

1.1 前言 1.1.1 為什麼學Shell Shell指令碼語言是實現Linux/UNIX系統管理及自動化運維所必備的重要工具, Linux/UNIX系統的底層及基礎應用軟體的核心大都涉及Shell指令碼的內容。每一個合格 的Linux系統管理員或運維工程師,都需要能夠

lotou:基本概念

lotou是一個基於golang的支援分散式的輕量級遊戲伺服器框架,主要提供遊戲伺服器叢集的訊息轉發程式碼倉庫 lotou提供了三種不同的訊息傳送方式: 1.Send 用於普通的訊息推送,不需要返回,傳送之後就不再關注 2.Request 非同步非阻塞請

Android編譯系統()——build/envsetup.sh

http://www.cloudchou.com/android/post-134.html 準備好編譯環境後,編譯Rom的第一步是 source build/envsetup.sh,該步驟把envsetup.sh裡的函式宣告為當前會話終端可用的命令。這些命令能讓我們

Android 原始碼編譯】:伺服器硬體配置及機型推薦-2016/06

做 Android系統開發多年,開發環境都是入職就搭建好了,入職時拿個賬號密碼就直接開始搞開發了,年初換了新公司,所有的專案都是剛起步,一切環境都要重新搭建,有幸當此重任,因為自己之前也只是用過,並沒

SpringBoot第二:配置檔案

前言   SpringBoot 完全摒棄了xml配置的模式,幾乎做到了“零配置”。說是“幾乎”,是因為一般情況下預設的配置足夠滿足日常開發所需,但是在特殊的情況下,我們往往需要用到自定義屬性配置、自定義檔案配置、多環境配置、外部命令引導等一系列功能。   SpringBoot 使用的全域性配置檔案 appli

MyBatis 就夠啦

第1章MyBatis框架配置檔案詳解 1.1 typeHandlers型別轉換器   每當MyBatis 設定引數到PreparedStatement 或者從ResultSet 結果集中取得值時,就會使用TypeHandler 來處理資料庫型別與java 型別之間轉換。下表描述了預設 TypeHandl

GCC 編譯

stand 空間 error 支持 預處理 -a 三級 net 錯誤 常用選項-E:只進行預處理,不編譯-S:只編譯,不匯編-c:只編譯、匯編,不鏈接-g:包含調試信息-I:指定include包含文件的搜索目錄-o:輸出成指定文件名 高級選項-v:詳細輸出編譯過程中所采用的

Canny邊緣檢測算法原理及其VC實現()

常用 差分 實現圖 還需要 鏈接 傳感器 出了 關系 位置 轉自:http://blog.csdn.net/likezhaobin/article/details/6892176 圖象的邊緣是指圖象局部區域亮度變化顯著的部分,該區域的灰度剖面一般可以看作是一個階躍,既從

Java線程()

線程 thread runnable 程序、進程、線程的概念 程序(program):是為完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼,靜態對象。 進程(process):是程序的一次執行過程,或是正在運行的一個程序。動態過程:有它自身的產生、存在和消亡的過程。 如

lamp編譯

時間 ror develop trac print 要求 tex pcre 授權 首先確認系統環境:centos6.4 min版本 1、安裝需要的開發環境 yum groupinstall "Development Tools" "Server Platform Dev

Java反射機制

java 反射 反射機制 工廠模式 1反射機制是什麽反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。在面向對象的世界裏,萬事萬物皆對象.在ja

WebSocket安卓客戶端實現()–連接建立與重連

ask 應該 header oid mha 主動推送 未收到 compile tde http://blog.csdn.net/zly921112/article/details/72973054 前言 這裏特別說明下因為WebSocket服務端是公司線上項目所以這裏ur

Redis () StackExchange.Redis Client

pack 線程 ttr 使用場景 sdk ins get http arc 這期我們來看StackExchange.Redis,這是redis 的.net客戶端之一。Redis是一個開源的內存數據存儲,可以用來做數據庫,緩存或者消息代理服務。目前有不少人在使用Service

[數據庫事務與鎖]: 徹底理解數據庫事務

存儲 數量 情況 一個數 就是 可能 發生 http 舉例 註明: 本文轉載自http://www.hollischuang.com/archives/898 事務 事務(Transaction),一般是指要做的或所做的事情。在計算機術語中是指訪問並可能更新數據庫中各種

Centos 6 apache httpd 2.2 主要配置( )

apache 2.2 httpd2.2 centos 6 實驗環境:VMware Workstation Pro 14(試用版) 系統平臺: CentOS release 6.9 (Final) 內核 2.6.32-696.el6.x86_64 Server versio

Tkprof工具(轉載)

depth ber 官方 Go ble 不可 _id sys 避免 在數據庫生成的oracle trace文件中,可讀性是比較差的,此時可使用tkprof工具來格式化trace文件,tkprof是一個命令行工具,作用就是把原始的跟蹤trace文件作為輸入,然後格式化一個可讀

三:python 對象類型:數字(上)

結果 dom 運行 精度 升級 方法 函數 般的 代碼 一:python 的數字類型: a)整數和浮點數 b)復數 c)固定精度的十進制數 d)有理分數 e)集合 f)布爾類型 g)無窮的整數精度 h)各種數字內置函數和模塊 二:各種數字類型的詳解   1,數字常量:pyt