1. 程式人生 > >編譯工具鏈製作神器

編譯工具鏈製作神器

深呼吸,深呼吸 - XXXX

Hello,大家好。
最近一直忙著除錯Bug,一直無果。很讓人傷心,多模組糅合,Ps. 驅動 使用者態 硬體全方位定位,搞的人很累。所以一直沒有寫點東西;
以前我一直以為要寫東西就必須寫的高大上的東東,後來才發現,高大上的東東搞起來除了很費力以外,反而可能讓人覺得你不也是COPY過來的嗎?你不是也是TS過來的嗎? 拽什麼拽啦。。

鑑於此,我決定寫點通俗易懂,能引來吃西瓜觀眾的tech文章。
始於此吧,今天我們來講一下怎麼製作自己的交叉鏈子

做嵌入式開發的小夥伴可能對“交叉工具鏈子”這個詞很敏感,可能是一道面試題啊(也許會和編譯原題一來聊出來)。那麼究竟什麼是交叉工具鏈子呢?工具鏈子是軟體開發專案中的一個重要組成部分,其會將正在開發的程式碼進行編譯、彙編和連結。一些工具鏈中的碎片將最終在生成的二進位制:譬如靜態庫。簡而言之就是可以在宿主機上,編譯生成可在目標機上的執行的,可執行程式的編譯器統稱(集編譯,連結,彙編,除錯,反彙編等等)。所以呢,工具鏈子本身是一個非常敏感的工具。

在實際開發中,很多人可能都沒有遇見過讓自己去做一個鏈子的情況,畢竟鏈子基本上都是現成的,編譯指令碼也是現成的,配置也是現成的。就算要做,網上也有一些零零散散的製作過程,那麼我為什麼還要寫這麼製作文章呢? 豈不是顯得脫褲子放屁;以上已知存在的製作鏈子的方法有以下幾點限制:
- 1、雖然這些鏈子可以通用,但是由於配置檔案一致,它不能為您優化某些特定場景,
- 2、它們可以編寫一個特定的目標,
- 3、它們可能使用的是比較老的元件(C 庫,配置等等),無法支援較新CPU的特性;
但是呢,這些鏈子還是有一些好處:
- 1、已經準備好,方便配置和使用,
- 2、既然能被廣泛使用,也說明它們的穩定性;

但是如果你想把你的程式執行在指定的硬體上,那麼你最起碼要學會如何製作工具鏈;

有很多種方法可以做鏈子,這裡我推薦一個製作交叉鏈子神器 - crosstool-ng
ct-ng 告別了過去製作交叉鏈子複雜的過程,把製作交叉鏈子做成了一套自動化部署工具,沒有門檻,想怎麼改就怎麼改。
如果在配合buildroot 或者 ptxdist,簡直分分鐘做出一套屬於自己的Linux Embedded 發行版呀有木有。
咳咳,製造發行版的這個事情我們後面在來care,下面我們來看看怎麼利用神器製作自己的交叉鏈子。

crosstool-ng版本眾多,這裡我們選用最新的版本,版本號是1.22.0。

[email protected]:~$ mkdir crosstool-ng-source 
[email protected]:~$ cd crosstool-ng-source
[email protected]:~/crosstool-ng-source$ wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2

此步驟可以跳過

[email protected]:~/crosstool-ng-source$ tar xvf crosstool-ng-1.22.0.tar.bz2
[email protected]:~/crosstool-ng-source$ mkdir crosstool-ng
[email protected]:~/crosstool-ng-source$ cd crosstool-ng
[email protected]:~/crosstool-ng-source/crosstool-ng$ ./configure --prefix=/usr/ct-ng/

此處如果不指定–prefix 那麼預設目錄是/usr/local

[email protected]:~/crosstool-ng-source/crosstool-ng$ make && sudo make install

上述如果指定了–prefix,記得新增到環境變數

[email protected]:~/crosstool-ng-source/crosstool-ng$ export PATH=/usr/ct-ng/bin:$PATH

下面開始製作,我以x86_64 為demo;其它的工具鏈方法都一樣。

[email protected]:~/crosstool-ng-source/crosstool-ng$ cd ..
[email protected]:~/crosstool-ng-soucrce$ mkdir x86_64-cross
[email protected]:~/crosstool-ng-soucrce$ cd x86_64-cross
[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng list-samples

然後就會列出下面推薦的已知工具鏈的名稱:

Status  Sample name
[G..]   alphaev56-unknown-linux-gnu
[G..]   alphaev67-unknown-linux-gnu
[G..]   arm-bare_newlib_cortex_m3_nommu-eabi
[G..]   arm-cortex_a15-linux-gnueabi
[G..]   arm-cortex_a8-linux-gnueabi
[G.X]   arm-cortexa5-linux-uclibcgnueabihf
[G.X]   arm-cortexa9_neon-linux-gnueabihf
[G..]   arm-unknown-eabi
[G..]   arm-unknown-linux-gnueabi
[G.X]   arm-unknown-linux-musleabi
[G..]   arm-unknown-linux-uclibcgnueabi
[G.X]   arm-unknown-linux-uclibcgnueabihf
[G..]   armeb-unknown-eabi
[G..]   armeb-unknown-linux-gnueabi
[G..]   armeb-unknown-linux-uclibcgnueabi
[G..]   armv6-rpi-linux-gnueabi
[G..]   armv7-rpi2-linux-gnueabihf
[G..]   avr
[G..]   i586-geode-linux-uclibc
[G..]   i586-mingw32msvc,i686-none-linux-gnu
[G..]   i686-nptl-linux-gnu
[G.X]   i686-w64-mingw32
[G..]   m68k-unknown-elf
[G..]   m68k-unknown-uclinux-uclibc
[G..]   mips-ar2315-linux-gnu
[G..]   mips-malta-linux-gnu
[G..]   mips-unknown-elf
[G..]   mips-unknown-linux-uclibc
[G..]   mips64el-n32-linux-uclibc
[G..]   mips64el-n64-linux-uclibc
[G..]   mipsel-sde-elf
[G..]   mipsel-unknown-linux-gnu
[G.X]   i686-w64-mingw32,nios2-spico-elf
[G..]   powerpc-405-linux-gnu
[G..]   powerpc-860-linux-gnu
[G..]   powerpc-e300c3-linux-gnu
[G..]   powerpc-e500v2-linux-gnuspe
[G..]   powerpc-unknown-linux-gnu
[G..]   powerpc-unknown-linux-uclibc
[G..]   powerpc-unknown_nofpu-linux-gnu
[G..]   powerpc64-unknown-linux-gnu
[G.X]   s390-ibm-linux-gnu
[G..]   s390x-ibm-linux-gnu
[G..]   sh4-unknown-linux-gnu
[G..]   sparc-unknown-linux-gnu
[G.X]   x86_64-w64-mingw32,x86_64-pc-linux-gnu
[G..]   x86_64-unknown-linux-gnu
[G..]   x86_64-unknown-linux-uclibc
[G.X]   x86_64-w64-mingw32
[G..]   xtensa-unknown-linux-uclibc
 L (Local)       : sample was found in current directory
 G (Global)      : sample was installed with crosstool-NG
 X (EXPERIMENTAL): sample may use EXPERIMENTAL features
 B (BROKEN)      : sample is currently broken

這裡我們選x86_64-unknown-linux-gnu 的吧。

[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng show-x86_64-unknown-linux-gnu 

會顯示此工具鏈子的一些庫資訊:

[G..]   x86_64-unknown-linux-gnu
    OS             : linux-4.3
    Companion libs : gmp-6.0.0a mpfr-3.1.3 mpc-1.0.3 expat-2.1.0 ncurses-6.0
    binutils       : binutils-2.25.1
    C compilers    : gcc  |  5.2.0
    Languages      : C,C++
    C library      : glibc-2.22 (threads: nptl)
    Tools          : gdb-7.10

下面讓我們生成配置檔案

[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng x86_64-unknown-linux-gnu

這樣子會在目錄下生成.config 檔案。
我們可以和配置核心程式碼一樣對此配置進行修改

[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng menuconfig
[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng build

這個過程時間比較長(取決於您的網速),因為還要下載相應的原始碼包。
為了節省時間,我這裡提供原始碼包以及配置檔案,具體連結在後面的附錄中,只需要將原始碼包放在您的工作區即可。

[email protected]:~/crosstool-ng-soucrce$ cp -rf cross-src/src   x86_64-cross/
[email protected]:~/crosstool-ng-soucrce$ cp cross-src/x86_64-config   x86_64-cross/.config
[email protected]:~/crosstool-ng-soucrce$ cd x86_64-cross
[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng  build

上述操作顯然就塊了很多。

最後全部完成後,會在當前目錄的x86_64-bin 目錄下生成我們需要的工具鏈:

[email protected]:~/crosstool-ng-soucrce/x86_64-cross$/x86_64-bin/bin$ ls
x86_64-unknown-linux-gnu-addr2line     x86_64-unknown-linux-gnu-dwp         x86_64-unknown-linux-gnu-gcov       x86_64-unknown-linux-gnu-objcopy
x86_64-unknown-linux-gnu-ar            x86_64-unknown-linux-gnu-elfedit     x86_64-unknown-linux-gnu-gcov-tool  x86_64-unknown-linux-gnu-objdump
x86_64-unknown-linux-gnu-as            x86_64-unknown-linux-gnu-g++         x86_64-unknown-linux-gnu-gprof      x86_64-unknown-linux-gnu-populate
x86_64-unknown-linux-gnu-c++           x86_64-unknown-linux-gnu-gcc         x86_64-unknown-linux-gnu-ld         x86_64-unknown-linux-gnu-ranlib
x86_64-unknown-linux-gnu-c++filt       x86_64-unknown-linux-gnu-gcc-5.2.0   x86_64-unknown-linux-gnu-ld.bfd     x86_64-unknown-linux-gnu-readelf
x86_64-unknown-linux-gnu-cc            x86_64-unknown-linux-gnu-gcc-ar      x86_64-unknown-linux-gnu-ld.gold    x86_64-unknown-linux-gnu-size
x86_64-unknown-linux-gnu-cpp           x86_64-unknown-linux-gnu-gcc-nm      x86_64-unknown-linux-gnu-ldd        x86_64-unknown-linux-gnu-strings
x86_64-unknown-linux-gnu-ct-ng.config  x86_64-unknown-linux-gnu-gcc-ranlib  x86_64-unknown-linux-gnu-nm         x86_64-unknown-linux-gnu-strip

簡單測試一下是否可用;
[email protected]:~/crosstool-ng-soucrce/x86_64-crossexportPATH=PWD/x86_64-bin/bin:PATHhole@hole2016:/crosstoolngsoucrce/x8664cross x86_64-unkonw-linux-gnu-gcc -v
由於我們使用的是最新的LIB庫,所以可能在我們自己的宿主機上編譯出來的程式是無法使用;

3、Q & A

我們在做環境的時候經常會大大小小的遇見一些錯誤,上述我就遇到一個錯誤;
此錯誤只有在32位的環境上編譯64位鏈子的時候才會產生。
1、錯誤資訊

[INFO ]  Installing GMP for host
[EXTRA]    Configuring GMP
[ERROR]    configure: error: Oops, mp_limb_t is 32 bits, but the assembler code
[ERROR]
[ERROR]  >>
[ERROR]  >>  Build failed in step 'Installing GMP for host'
[ERROR]  >>        called in step '(top-level)'
[ERROR]  >>
[ERROR]  >>  Error happened in: CT_DoExecLog[scripts/[email protected]]
[ERROR]  >>        called from: do_gmp_backend[scripts/build/companion_libs/[email protected]]
[ERROR]  >>        called from: do_gmp_for_host[scripts/build/companion_libs/[email protected]]
[ERROR]  >>        called from: do_companion_libs_for_host[scripts/build/[email protected]]
[ERROR]  >>        called from: main[scripts/[email protected]]
[ERROR]  >>
[ERROR]  >>  For more info on this error, look at the file: 'build.log'
[ERROR]  >>  There is a list of known issues, some with workarounds, in:
[ERROR]  >>      '/usr/local/share/doc/crosstool-ng/crosstool-ng-1.22.0/B - Known issues.txt'
[ERROR]
[ERROR]  (elapsed: 1:51.70)
[01:52] / /usr/local/bin/ct-ng:152: recipe for target 'build' failed

根據提示我們發現是在安裝GMP這個包的時候報錯,提示資訊也很明確;我首先就想到是GMP這個包的配置步驟有BUG,尋找一下最開始我們安裝crosstool-ng的目錄有沒有關於gmp相關的資訊;

    [email protected]:~/crosstool-ng-soucrce/x86_64-cross$ cd ../crosstool-ng
    [email protected]:~/crosstool-ng-soucrce/crosstool-ng$ find -name *gmp*
    ./config/companion_libs/gmp.in
    ./scripts/build/companion_libs/100-gmp.sh
    ./patches/ppl/0.11.2/200-fix-build-with-local-gmp.patch
    ./patches/ppl/0.11.2/400-fix-build-with-gmp-5.1.patch
    ./patches/ppl/0.10.2/200-fix-build-with-local-gmp.patch
    ./patches/ppl/0.10.2/100-fix-configure-with-gmp-5_0_1.patch
    ./patches/ppl/0.11.1/200-fix-build-with-local-gmp.patch
    ./patches/ppl/0.11/200-fix-build-with-local-gmp.patch
    ./patches/gmp

上述和build 以及配置相關只有

    ./scripts/build/companion_libs/100-gmp.sh

根據此指令碼我們鎖定了gmp 資料夾目錄

[email protected]:~/crosstool-ng-soucrce/x86_64-cross/.build/src/gmp-6.0.0a

根據提示我們修改了GMP 的配置選項
新增一個配置選項到 ./scripts/build/companion_libs/100-gmp.sh

    --disable-assembly

讓我們在重複上述安裝crosstool-ng的步驟,

[email protected]:~/crosstool-ng-soucrce/crosstool-ng$ make distclean 
[email protected]:~/crosstool-ng-soucrce/crosstool-ng$ ./configure
[email protected]:~/crosstool-ng-soucrce/crosstool-ng$  make && sudo make install

然後在重複上述製作交叉鏈子的步驟;

[email protected]:~/crosstool-ng-soucrce/x86_64-cross$  ct-ng clean
[email protected]:~/crosstool-ng-soucrce/x86_64-cross$  cp ../cross-srs/x86_64-config .config
[email protected]:~/crosstool-ng-soucrce/x86_64-cross$ ct-ng  build

好了,問題解決了;

囉嗦一點,在那個宿主機上生成的,就在那個宿主機上進行交叉編譯。

* Ps.. *
一個交叉鏈子就這麼容易的被我們製作成功了,那麼下一步我們玩什麼呢?
上述我們說如果在配合buildroot 或者 pdxditst 那麼我們簡直分分鐘定製一個發行版的Linux 有木有;

說玩就玩,下一節我們就來看看buildroot怎麼玩??;

附錄Ⅰ - 上述安裝所用安裝包

原始碼包地址:戳這兒
密碼: axs7