Linux系統的交叉編譯工具鍊用來将源代碼變成bin檔案或者庫檔案的一個軟體。一般大家預設工具鍊等于gcc或者arm-linux-gcc,但是實際上,gcc隻是工具鍊的編譯器部分,不是全部,制作一個工具鍊的原材料,除了gcc,還需要linux核心,libc庫等一系列的軟體包。所謂萬事開頭難,如何在Buildroot中使用自己的交叉編譯工具鍊則是第一道難關。
Buildroot支援從零開始用原材料軟體包自動構造工具鍊,也支援直接使用第三方制作好的工具鍊。
toolchain-buildroot 從零開始自動制作工具鍊
在make menuconfig –> Toolchain –>Toolchain type中,有2個選項,選擇buildroot toolchain則是使用buildroot預設的自動化腳本從零開始制作交叉編譯工具鍊,如果是選擇externaltoolchain 則是使用外部制作好的工具鍊。

Figure 1 toolchain type 選項
在mini2440_defconfig的配置檔案中,我們可以看到,它并沒有toochain相關的選項,隻是在cpu指令集部分選擇了ARM920T ,這種情況它會采用buildroot-toolchain也就是buildroot預設的自動化腳本,從零開始制作工具鍊。實際上,你隻要make toolchain然後等待幾分鐘,Buildroot就會将制作好的全新工具鍊放到output/host/目錄下了。
Figure 2 mini2440_defconfig配置部分截圖
整個工具鍊自動化制作過程可以參考toolchain/ 目錄下的toolchain-buildroot/ 、toolchain.mk、helpers.mk、toolchain-wrapper.mk等幾個腳本,我就不詳細說了。但是有幾個關鍵點我還是強在下面列一下。總之制作過程還是很複雜的,是以如果是初學者,用手工方法從零開始做交叉編譯工具鍊,将是多大的挑戰。
a). 從圖3中我們可以看到制作交叉工具鍊大概需要的原材料軟體包
Figure3 制作交叉工具鍊的原材料
工具鍊主要的原材料包括:gcc,、libc庫,、linux核心頭檔案、binutils以及一系列自動建構打包工具如m4、gmp、mpc等。
另外要強調的是,從工具鍊的原材料可以知道為什麼Linux核心、驅動以及應用軟體要用同一個工具鍊編譯,為什麼核心版本要适配它的工具鍊。這是因為工具鍊本身的制作依賴于特定版本的Linux核心和libc庫。
b). 從圖1的makemenuconfig –> Toolchain這一系列選項可以看到,制作工具鍊還可以選擇libc庫(uclibc還是glibc,自己添加Android特有的Bionic libc),不同的libc性能,size,效率,穩定性以及GPL協定支援上有着一定的差異,需要使用者謹慎選擇和測試。mini2440直接采用buildroot提供的預設的uclibc,不保證其穩定性和bug。
另外,toolchain後面還有Linux核心版本以及MMUsupport以及gcc版本的選擇,可見如果需要定制特定的Linux核心(比如不帶MMU的實時版),除了移植核心之外,還需要特别為其定制工具鍊。
c). make menuconfig –> Target option 中的選項也是與交叉工具鍊密切相關的。
其中晶片的CPU的大小端,是否編譯成elf格式,指令集,ABI的類型(EABI是Embeded ABI的意思,EABIHF是采用硬浮點的ABI),以及軟硬浮點特性(軟浮點不會有編譯相容性問題,但是在支援硬浮點的進階嵌入式晶片,采用軟浮點配置,很多性能會發揮不佳,但是ARM9這種低端平台用軟浮點應該OK)等等選項,都是應該考慮的點。
Figure4 與交叉工具鍊相關的target option選項
toolchain-external 使用第三方現成工具鍊
這節用友善的Tiny4412開發闆官方提供的工具鍊為例,介紹如何将外部第三方工具鍊移植到到Buildroot的編譯環境。Tiny4412開發闆用的SOC晶片的基于ARM-Cortex-A9核心的三星Exyons-4412 真四核SOC晶片,曾經是三星旗艦手機Galaxy-S3的主打SOC。
從友善官方提供的交叉編譯工具鍊的包命名來看,工具鍊使用的gcc版本是4.5.1,有vfp則說明工具鍊支援應付點編譯。V6應該是指令集是ARMV6,但是ARM-V6實際上是ARM11的指令集,Cortex-A9的應該是ArmV7才對, 這裡應該是命名出錯了,算是一個小漏洞吧。
Figure5 友善官方提供的tiny4412交叉編譯工具鍊
移植步驟如下:
1. 為了不産生命名誤導,我們将工具鍊的壓縮包中4.5.1/* 目錄下的是以内容拷貝出來,放到一個叫toolchain-tiny4412重新壓縮成名字為arm-linux-gcc-4.5.1-tiny4412.tar.bz2的壓縮包,将其cp到/mnt/sdb/3rd-pkg目錄下,細心的朋友已經發現,根據前面一篇Buildroot快速入門的内容,這個檔案夾是我儲存第三方軟體包的專門檔案夾,待會Buildroot會用file的方法從該檔案夾中把工具鍊cp到buildroot/dl/目錄下的。
Figure6 儲存在/mnt/sdb/3rd-pkg 目錄下的工具鍊壓縮包
2. 在make menuconfig –> Toolchain –>Toolchain type中選中external toolchain,下面的Toolchain欄中的arm-linux-gcc-4.5.1for tiny4412選項,實際上原本是沒有的,是我自己加上去的。
Figure7 Toolchain的選擇
3. 那麼如何把自己的工具鍊加上去呢?cd buildroot/toolchain/toolchain-external/檔案夾,根據前一篇文章快速上手的經驗,要加自己的工具鍊,肯定是該配置,再改mk檔案啦!
在該目錄的Config.in檔案的108行,有一個現成的第三方ARM cortex-A9 第三方交叉工具鍊的配置代碼。
Figure8 buildroot/toolchain/toolchain-external/Config.in中的ARM Cortex-A9現成參考配置
我們可以參考模仿這段代碼,稍微修改,在這段代碼後面加入我們自己的配置代碼:
注意,命名很重要,變量名一定是BR2_TOOLCHAIN_EXTERNAL_開頭,後面加上自己的工具鍊名。
Figure9 Config.in中參考修改的tiny4412工具鍊配置代碼
在我的修改中,出來提示字元串和help部分的相關注釋和提示文字,主要是把主機gcc版本的最低要求降低到4.5,再去掉了核心頭檔案最低版本限制(這裡其實是友善官方的疏忽,友善在制作工具鍊的時候,采用的Linux核心頭檔案版本很低,和編譯的核心版本不比對,導緻頭檔案版本檢查會報錯,因而我去掉了最低版本的限制,這也是潛在漏洞之一吧)。
4. 配置交叉工具鍊字首名。在Config.in的690行左右,為剛才添加的BR2_TOOLCHAIN_EXTERNAL_TINY4412_ARM選擇工具鍊字首名。
字首名的格式組成是這樣的:目标cpu-廠商-作業系統-庫和abi格式,我們參考之前模仿的配置,選擇arm-nonelinux-gnueabi,
實際上,友善官方給的工具鍊就是以arm-nonelinux-gnueabi作為字首命名的。
Figure10 工具鍊字首名配置
Figure11 tiny4412官方的工具鍊命名
5. 修改toolchain-external.mk 檔案,加入自己配置。在296行,仿照前面一個工具鍊的變量配置,為BR2_TOOLCHAIN_EXTERNAL_TINY4412_ARM的配置增加下載下傳位址和壓縮包的名字,壓縮包名字在第一步已經做好。至于下載下傳位址,直接抄過來就行了,友善提供的定制化工具鍊,網上下載下傳不到的。
Figure12 為toolchain-external.mk 加入tiny4412工具鍊的配置
事實上,打開那個位址,我們可以看到由sourcery官方維護的很多現成制作好的工具鍊,是以嘛直接拿來用就好了,自己從零制作工具鍊多麻煩啊!當然這些工具鍊的穩定性還是需要自己測試一番。
Figure13 sourcery網上可下載下傳的現成工具鍊
6. 在menuconfig中設定下載下傳的鏡像位址。這個和前一篇文章一樣,将本地儲存工具鍊的位址,按照格式,設定為file的鏡像位址。實際上,Buildroot的下載下傳腳本,預設的規定是優先去本地的file鏡像位址找軟體包,找不到之後,才會走git或者網站下載下傳等其它方法。當然網上肯定是下載下傳不到的,但是先從本地找到就OK,這也是第一步為什麼要儲存工具鍊壓縮包到該位址的原因。
關于Buildroot下載下傳軟體包的順序,可以參考package/pkg-download.mk的腳本,在214行可以看到,隻有在本地file路徑找不到了,才會采用配置的(PKG)_SITE_METHOD方法去擷取軟體包。
Figure14 工具鍊的下載下傳鏡像位址
Figure15 Buildroot自動下載下傳腳本的下載下傳過程
7. menuconfig中的幾項配置。修改完配置腳本和編譯建構mk腳本後,還得在menuconfig中把修改的東西配置進去。
在target Option的配置中,注意上一節提到的幾點。但是這裡有幾個新的選項需要注意
a). CPU架構選擇的是Cortex-A9
b) vfp友善官方給的工具鍊是支援的,是以這裡可以打開,這樣就能支援硬浮點了
c) NEON SIMD是CPU支援的高性能多媒體引擎的功能,這是4412這種級别的多媒體處理器的殺手級功能,但是我們現在并不了解它的特性,也不知道友善的工具鍊在制作的有沒有把該功能加上去,因而暫時不打開。但是專業的工程師要去了解這項功能,以便發揮SOC和CPU的潛能。
d). VFP硬浮點的版本,這一項由于友善的資料不明确,暫時選VFPv3-D16版本,根據說明,Coretex-A9對這個版本都會支援的。
e). ABI的問題,根據圖11的内容,友善的工具鍊應該隻是用了EABI來做的,沒有用EABIhf。這幾項是什麼意思呢?浮點選項其實有軟浮點、硬浮點EABI(softfp)和硬浮點EABIhf三個。
軟浮點就是用軟體模拟浮點運算
硬浮點EABI就是用浮點指令,但是為了相容舊版本的軟浮點編譯出來的庫還是用整數寄存器傳遞浮點數,這樣犧牲了一些效率,但是在工具鍊中存在舊的軟浮點庫時,是可以相容并不會出現編譯錯誤的。
硬浮點EABIhf則是使用純粹的硬浮點指令和浮點寄存器來計算浮點數,這樣效率會更高,但是不再相容工具鍊中舊版的軟浮點下編譯出來的庫,如果不重新制作硬浮點EABIhf的工具鍊,可能會出現編譯問題。
EABIhf需要知道整個工具鍊的庫的相容特性,目前看起來友善官方工具鍊不支援這個選項,其工具鍊命名也是EABI,但是有支援vfp,因而我們選擇硬浮點EABI的配置。具體要如何支援EABIhf,可以搜其它相關文章,這個可能需要重新制作整個工具鍊。
以上這些選項實際上都是編譯toolchain-wrapper傳遞的,toolchain-wrapper是一個中間層,負責編譯時,傳遞某些特定選項給工具鍊,以上這些選項确定後,都會被toolchain-wrapper以參數的時候在編譯時傳遞給交叉工具鍊的。
Figure 16 menuconfig -->target option的配置
Figure 17 menuconfig -->toolchain的配置
在加入了tiny4412的配置後,最後在toolchani中選擇自己的工具鍊,選上MMU功能,然後用pipe選項進行編譯加速。
最後,make toolchain ,你就可以看到Buildroot系統如何建構出tiny4412的工具鍊了。
小結
整體而言,從零制作一個工具鍊,對嵌入式的知識掌握還是需要深入的掌握,另外,工具鍊對整個系統代碼的穩定性有着極大的影響,是以直接用自動制作的工具鍊,一定要經過嚴格的壓力測試,否則容易出現各種隐患。
因而,采用第三方制作好的,有專門公司維護的工具鍊,應該是一個更為有效的開發方式。