i.MX6ULL開發板原始碼自制交叉編譯器
前言
文章基於HD-IMX6ULL-MB 系列開發板測試驗證,該開發板由武漢芯路遙科技有限公司與武漢永珍奧科電子有限公司合作推出。此開發板基於 NXP iMX6ULL 系列 Cortex-A7 高效能處理器設計,適用於快速開發一系列具有創新性的產品如人機介面工業 4.0 掃描器、車載終端以及行動式醫療裝置。
自己製作交叉編譯器
早期(2009年以前)我們在做嵌入式系統開發時,第一件事就是自己製作交叉編譯器。當時做交叉編譯器 需要自己下載gcc、glibc、binutils等相關工具的原始碼,然後一個一個原始碼編譯安裝。製作交叉編譯器的 過程中最痛苦的莫過於各個軟體之間的版本依賴關係,如gcc 4.6.2 依賴 glibc 2.13,如果你選定 gcc 4.7 則可能編譯製作失敗,然後再嘗試一個新的版本重新編譯,直至找到一個合適的版本為止。
後來為了方便交叉編譯器的製作,有很多組織或個人開始編寫這些製作交叉編譯器的指令碼或框架,並測 試解決這些軟體版本之間的依賴關係。當時最知名的莫過於基於
glibc 的
crosstool 和 基於
uclibc 的
buildroot 了。在開始講解如何製作交叉編譯器之前,我們首先來了解一下
C執行庫。
1.嵌入式C執行庫
1.1glibc庫
glibc是gnu釋出的libc庫,也即c執行庫。glibc是linux 系統中最底層的api(應用程式開發介面),幾乎其它任何的執行庫都會倚賴於glibc。glibc除了封裝linux作業系統所提供的系統服務外,它本身也提供了 許多其它一些必要功能服務的實現,主要的如下:
-
string,字串處理
-
signal,訊號處理
-
dlfcn,管理共享庫的動態載入
-
direct,檔案目錄操作
-
elf,共享庫的動態載入器,也即interpreter
-
iconv,不同字符集的編碼轉換
-
inet,socket介面的實現
-
intl,國際化,也即gettext的實現
-
io
-
linuxthreads
-
locale,本地化
-
login,虛擬終端裝置的管理,及系統的安全訪問
-
malloc,動態記憶體的分配與管理
-
nis
-
stdlib,其它基本功能
gcc 是編譯器,基本上 Linux 下所有的程式(包括核心)都是 gcc 編譯的,libc 當然也是。gcc 和 libc 是互相依賴的兩個軟體,它們合作的方式類似 Linux 系統的 "自舉"。先在一個可以執行的帶有老 libc 和
gcc 的系統上,用老 gcc 編譯出一個新版本的 gcc + 老 libc,再用這個新 gcc 編譯出一個新 gcc + 新
libc,再用這套新的組合編譯整個新系統。
1.2 uClibc庫
PC上常用的標準庫glibc是一個非常寵大而完整的庫,但早期對於嵌入式系統來說,由於Flash和RAM的 儲存空間有線,其體積顯得過於大了一些。uClibc的出現就是為了解決這個問題,uClibc儘可能的相容
Glibc,大多數應用程式可以在很小或完全不修改的情況下就可能使用uClibc替代glibc。透過uClibc來代 替Glibc,可以在不改變應用程式功能的前提下,大大減少釋出檔案的大小,無論應用程式以靜態連結來 編譯,還是以動態連結形式編譯。
uClibc比一般用於Linux發行版的C庫GNU C Library (glibc)要小得多,glibc目標是要支援最大範圍的硬體和核心平臺的所有C標準,而uClibc專注於嵌入式Linux.很多功能可以根據空間需求進行取捨。現在uClibc更多執行於標準的以及無MMU的Linux系統上,支援i386,x86 64,ARM (big/little endian), AVR32,Blackfin,h8300,m68k,MIPS (big/little endian), PowerPC,SuperH (big/little endian),
SPARC,和v850等處理器。
由於當前嵌入式系統硬體效能的提升,用於儲存程式的Flash空間和用於執行程式的RAM空間都有了大幅 提升,為了保證程式更大的相容性,uClibc也逐步退出了歷史的舞臺了。
uClibc早期官網: uClibc最新官網:
1.3 eglibc庫
EGLIBC(Embedded GLIBC,縮寫為EGLIBC)是glibc的原創作組織FSF所新推出的glibc的一種變體, 目的在於將glibc用於嵌入式系統。它是GNU C 庫(glibc)的一個分支,也採用GNU寬通用公共許可證
(LGPL)釋出。它希望能應用於嵌入式系統,但它的原始碼與可執行檔案仍然保持與glibc一致。它的作 者宣稱它不是glibc的一個分支,而是用來容納glibc核心開發者拒絕採納的patch。
2009年5月6日,因為與glibc核心開發者之間對程式發展方向的爭議,Debian開發者宣佈將要採用EGLIBC來取代glibc。Ubuntu自9.10後也採用了EGLIBC,Ark Linux也使用它。2014年初,官網上宣佈,eglibc已經停止開發,因為現在的目標是在glibc上直接解決問題(goals are now being addressed directly in GLIBC),Debian開發者也恢復到使用glibc了。
1.4 newlib庫
在做一些微控制器的裸機程式開發時,有時候最想要的是實現一個printf列印函式,以便及時輸出各種信 息。除去底層的裝置驅動不說,printf本身的實現就有夠麻煩,如果平時有儲存相關的程式碼還好,不然就 很浪費時間。除此之外,還有一些諸如strlen、strcpy之類的函式,我們不願意自己寫,既麻煩而且效率 不高,如果能借助已有的程式碼或庫就好了。
Newlib 就滿足了這點需求,它是一個面向嵌入式系統的C執行庫。最初是由Cygnus Solutions收集組裝的一個原始碼集合,取名為newlib,現在由Red Hat維護。對於與GNU相容的嵌入式C執行庫,Newlib 並不是唯一的選擇,但是從成熟度來講,newlib是最優秀的。newlib具有獨特的體系結構,具有可移植 性強,具有可重入特性、功能完備等特點,使得它能夠非常好地滿足深度嵌入式系統的要求。
Newlib 庫是一個開源的c函式庫,包括libc和libm兩部分。它支援ANSI C庫標準,針對不同處理器架構進行最佳化,輕量級,適用於嵌入式系統。其特點如下:
-
支援printf和最佳化的字串操作
-
支援malloc和free等記憶體操作
-
支援函式可重入功能(不過這種支援對記憶體有壓力,總之是感覺弊大於利)
-
支援libm數學庫(不過一般嵌入式用不到浮點數,而且用模擬的開銷略大)
-
newlib的函式是分檔案實現的,如果用不到,絕不加入連結,一般不會造成目標檔案猛增的情況。
-
newlib C庫一般在製作微控制器裸機開發的交叉編譯器時,使用得比較多。
2 Crosstool-ng製作交叉編譯器
Crosstool早期是個很不錯的交叉編譯器製作工具,但是後來完善得不夠好,於是有人弄出了個更好的
——
crosstool-ng(crosstool Next Generation)。其特點如下:
支援menuconfig(類似於Linux核心配置) 支援眾多的架構
可選多種不同的C庫等模組提供示例配置
支援多種主機編譯環境:各種Linux發行版,Cygwin等。
接下來,我們學習瞭解一下如何使用
crosstool-ng 來製作一個ARM交叉編譯器。
2.1 Crosstool-NG 編譯與安裝
接下來進入到原始碼路徑下,開始Linux系統下原始碼安裝的三部曲:
./configure、
make、
make install
。 這裡在configure 時透過
--prefix 選項指定將編譯生成的檔案安裝到當前路徑下即可。在進行
./configure 時可能會提示 help2man、 libtool 找不到,這可能是系統沒有安裝或者安裝的版本過低導致的,直接使用
sudo apt install 命令安裝相關係統命令即可。
上面命令成功編譯安裝之後,可執行程式將會放到
install 資料夾下,接下來我們可以測試
ct-ng 命令是否能夠成功執行。接下來我們將會使用該程式來製作交叉編譯器。
2.2 交叉編譯器配置
在Crosstool-NG的安裝路徑下,有很多參考的交叉編譯器示例配置,我們沒有必要所有的選項都自己從
0開始配置,可以在某個示例配置的基礎上來修改。
因為i.MX6ULL是ARM CortexA7核的處理器,但在上面的示例配置中並沒有該架構的相關配置,這樣我們在 A8的基礎上來進行修改,這兩種架構大致都差不多。我們將ARM CortexA8的示例配置複製一份並命名為
.config, 接下來的
ct-ng menuconfig 將會預設讀取該配置檔案。
接下來使用
export 命令匯出
ct-ng 命令所在的路徑,如果是使用
SecureCRT 遠端登入到Linux伺服器上操作的話,還需要
export TERM=vt100 命令配置TERM環境變數,否則接下來的配置可能不能輸入。接下來再執行
ct-ng menuconfig 對交叉編譯器製作進行配置。
下面是Crosstool-NG的配置介面,我們接下來需要在這裡進行修改。在配置的過程中,
上、下方向鍵 用來選擇相應選項,
TAB
鍵 用來選擇底下的
<Select> 或
<Exit>:
在
Paths and misc options 選項中,我們主要要修改如下幾個選項,修改指定下載的軟體包存放路徑
${PWD}/tarballs 和 交叉編譯器的安裝路徑
/opt/xtools/cortexA7:
在
Target options 選項中,我們主要修改 “
Floating point” 選項,因為 iMX6ULL處理器帶有
FPU,這裡為了保持相容性,選擇
softfp (FPU)。
在
Toolchain options 選項中,如果想複製該交叉編譯器給別的機器使用,則可以選中"
Build Static Toolchain",另外修改 "
Tuple's vendor string" 選項中指定交叉編譯器名稱。
在
Operating System 選項中,因為我們移植的Linux核心目標版本為 5.10.x, 所以這裡核心的版本選擇要跟開發板上移植的版本保持一致,否則今後編譯Linux核心時可能會出現相容性問題。在這裡, crosstool-NG的預設核心版本較低,這裡需要修改配置為我們想要的版本。下面的這些選項配置,依賴
Paths and misc options 選單中的
[*] Try features marked as EXPERIMENTAL選項。
"
Source of linux" 選擇
(Custom location)
"
Custom source location" 裡設定 Linux路徑為
(${PWD}/tarballs/linux-5.10.tar.xz) ,接下來我們將會手動下載相應的Linux核心原始碼壓縮包到這裡;
"
Version of linux" 裡選擇
(newer than anything below) ;
在
C-library 選項中,
C library 選擇
(glibc) ,其他使用預設
剩餘的其它選項,我們就不作任何修改採用預設配置。關於
C compiler 編譯器裡的相關選項,大家也可以瞭解一下。
配置完成後回到主選單,使用
Tab
鍵 切換到
< Exit > ,然後選擇儲存退出即可。交叉編譯器配置完成之後,接下來我們就準備開始交叉編譯器的編譯過程。
2.3 交叉編譯器編譯
在前面的配置中,我們計劃將交叉編譯器安裝到系統的
/opt/xtools 路徑下,這裡我們首先需要使用
root 許可權建立這個資料夾,並給所有其他使用者
寫 許可權。
CrossTool-NG在編譯過程中,會下載製作交叉編譯器所需要的軟體原始碼包,但有些軟體包的下載地址可 能已經失效,這時我們可以自己找到相關軟體的相應版本軟體包,然後手動下載到指定的壓縮包存放路 徑下,如前面配置中指定的
${PWD}/tarballs 。下面是一些已知的失效檔案,我們提前手動下載好,其它所需要的軟體包將會在開始編譯後自動下載。
接下來我們就開始交叉編譯的編譯製作過程,這個過程的時間依賴PC的效能。我的Linux伺服器處理器 是Intel(R) Xeon(R) CPU E31235 @ 3.20GHz,4核8執行緒,所以我這裡使用
ct-ng build.8 命令用8個程式同時編譯。
交叉編譯器編譯完成之後,我們可以使用下面命令檢視製作好的交叉編譯器相關版本資訊:
2.4 交叉編譯器測試
接下來我們使用製作好的交叉編譯器,交叉編譯之前寫好的
hello.c 測試程式,並放到 ARM 開發板上執行測試。需要注意的是因為新制作的交叉編譯器跟開發板上執行的C執行庫版本不一致,這裡必須加上 -
static 進行靜態連結,這樣編譯生成的程式才能在開發板上執行。
ARM 開發板上下載執行測試:
版權宣告
本文件所有內容文字資料由凌雲實驗室郭工編著,主要用於凌雲嵌入式Linux教學內部使用,版權歸屬 作者個人所有。任何媒體、網站、或個人未經本人協議授權不得轉載、連結、轉帖或以其他方式複製釋出/發表。已經授權的媒體、網站,在下載使用時必須註明來源,違者本人將依法追究責任。
Copyright (C)2021 凌雲物網智科實驗室·郭工
Author: GuoWenxue
guowenxue@gmail.com
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70009145/viewspace-2849529/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- i.MX6ULL開發板原始碼交叉編譯器介紹原始碼編譯
- i.MX6ULL開發板-Buildroot製作交叉編譯器UI編譯
- i.MX6ULL開發板原始碼編譯原始碼編譯
- i.MX6ULL開發板原始碼編譯燒錄原始碼編譯
- RK3568開發板原始碼編譯原始碼編譯
- 虛擬機器-Linux開發板交叉編譯問題記錄虛擬機Linux編譯
- 嵌入式GDB除錯Linux C程式或交叉編譯(開發板)除錯LinuxC程式編譯
- 如何對 Neuron 原始碼進行交叉編譯原始碼編譯
- 如何根據自己的開發板型號下載和配置交叉編譯鏈編譯
- 編譯器的自展和自舉、交叉編譯編譯
- 交叉編譯編譯
- 11_QT跨平臺執行之把QT程式交叉編譯到ARM開發板QT編譯
- lazarus交叉編譯編譯
- GDB交叉編譯編譯
- golang交叉編譯Golang編譯
- 09_QT系統移植之交叉編譯QT原始碼和觸控原始碼QT編譯原始碼
- Android NDK 提供的交叉工具鏈手動編譯原始碼Android編譯原始碼
- Android 基於ffmpeg開發簡易播放器 - NDK交叉編譯ffmpegAndroid播放器編譯
- 交叉編譯入門編譯
- go 交叉編譯,部署Go編譯
- 淺談交叉編譯編譯
- ubuntu下編譯交叉編譯工具鏈Ubuntu編譯
- Vue3原始碼分析——編譯模組和編譯器Vue原始碼編譯
- qgroundcontrol開發環境搭建原始碼編譯開發環境原始碼編譯
- i.MX6ULL開發板無線網路測試
- Hi3516開發筆記(七):Hi3516虛擬機器交叉開發環境搭建之交叉編譯Qt筆記虛擬機開發環境編譯QT
- 交叉編譯和 RPC編譯RPC
- wifidog交叉編譯WiFi編譯
- android NDK 交叉編譯Android編譯
- golang初學:交叉編譯Golang編譯
- python開發編譯器Python編譯
- 小白自制Linux開發板 九. 修改開機LogoLinuxGo
- Rust 交叉編譯與條件編譯總結Rust編譯
- 交叉編譯-Mac環境使用NDK編譯FFmpeg編譯Mac
- 迅為i.MX6ULL 開發板開機進度條修改文件
- 自制編譯器——cbc安裝後使用出問題編譯
- 使用 goxc 方便的進行交叉編譯分發Go編譯
- 小白自制Linux開發板 十. NES遊戲玩起來Linux遊戲