構建gcc交叉編譯工具鏈
如何構建一個GCC交叉編譯工具鏈
GCC不僅是一個編譯器,它是一個開源工程,可以讓你建立各種編譯器。一些編譯器支援多執行緒,一些支援共享庫,一些支援Multilib(典型的應用是在64位機上執行32位應用程式),這些都取決於在編譯 編譯器 時的配置。
本文件將說明怎麼建立一個交叉編譯器。你需要一個已經安裝gcc的Unix-like環境。
一、需要的包
Debian系統,首先需要安裝一些包
$ sudo apt-get install g++ make gawk
其他的包將使用原始碼來編譯。在根檔案系統的某個地方新建一個資料夾,下載下面的包。本文是2014年寫的,你看到時,可能有更新的包可以使用,所以你可以使用更新的包。
$ wget http://ftpmirror.gnu.org/binutils/binutils-2.24.tar.gz
$ wget http://ftpmirror.gnu.org/gcc/gcc-4.9.2/gcc-4.9.2.tar.gz
$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.17.2.tar.xz
$ wget http://ftpmirror.gnu.org/glibc/glibc-2.20.tar.xz
$ wget http://ftpmirror.gnu.org/mpfr/mpfr-3.1.2.tar.xz
$ wget http://ftpmirror.gnu.org/gmp/gmp-6.0.0a.tar.xz
$ wget http://ftpmirror.gnu.org/mpc/mpc-1.0.2.tar.gz
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.12.2.tar.bz2
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz
最開始的四個包:binutils、gcc、Linux kernel和glibc是主要要用的包。後面三個mpfr、gmp、mpc你可以使用系統自帶的package manager安裝,但是可能比較舊。最後兩個包ISL和CLooG是可選的,它們支援一些優化。
二、它們是怎麼有機結合在一起的呢?
當我們完成時,我們會構建如下的程式和庫。首先,構建左邊的工具,然後使用這些工具來構建右邊的程式和庫。我們將不構建目標系統的Linux kernel,但是我們需要kernel header來構建目標系統標準C庫。
左邊的編譯器將調用匯編器和連結器。其他的包MPFR、GMP和MPC將連線到編譯器中。
右邊圖中的a.out,執行在目標OS上,使用交叉編譯器,連線目標系統標準C庫和C++庫。C++標準庫呼叫標準C庫,C庫直接呼叫Linux kernel。
注意,除了使用glibc外,還可以使用其他替代的C庫實現,比如Newlibc,uclibc等,其他替代的C庫用在嵌入式中較多,比glibc庫要小,功能沒有glibc全面。
三、構建步驟
解壓所有的包。
$ for f in *.tar*; do tar xf $f; done
建立一些其他目錄的符號連線,這5個包依附於gcc,如果存在符號連線,gcc指令碼將自動build這些包。
$ cd gcc-4.9.2
$ ln -s ../mpfr-3.1.2 mpfr
$ ln -s ../gmp-6.0.0 gmp
$ ln -s ../mpc-1.0.2 mpc
$ ln -s ../isl-0.12.2 isl
$ ln -s ../cloog-0.18.1 cloog
$ cd ..
選擇一個安裝路徑,確保有寫的許可權。下面步驟中,我將安裝新的工具鏈到/opt/cross
$ sudo mkdir -p /opt/cross
$ sudo chown jeff /opt/cross
整個構建過程中,確保安裝的bin子目錄在你的PATH環境變數中。後續你可以從PATH中移除該目錄,但是大部分構建步驟將會預設通過PATH來查詢aarch64-linux-gcc和其他host工具。
$ export PATH=/opt/cross/bin:$PATH
注意/opt/cross/aarch64-linux/目錄下的檔案。該目錄被認為是虛擬的aarch64 linux目標系統的根目錄。理論上,可以使用裡面所有的標頭檔案和庫。
1. Binutils
構建binutils、安裝交叉彙編器、連結器和其他工具的步驟:
$ mkdir build-binutils
$ cd build-binutils
$ ../binutils-2.24/configure --prefix=/opt/cross --target=aarch64-linux --disable-multilib
$ make -j4
$ make install
$ cd ..
我們制定aarch64-linux作為目標系統型別,binutils的配置指令碼將識別到它與正在進行編譯的主機系統不一樣,配置一個交叉彙編器和交叉連結器。這些工具將安裝到/opt/cross/bin,名字以arm-linux-開頭。
--disable-multilib意味著我們只希望我們的程式和庫使用aarch64指令集,而不使用aarch32的指令集。
2. Linux Kernel Headers
將Linux kernel 標頭檔案安裝到/opt/cross/aarch64-linux/include, 使用新工具鏈構建的程式會呼叫這些目標環境中的aarch64 kernel。
$ cd linux-3.17.2
$ make ARCH=arm64 INSTALL_HDR_PATH=/opt/cross/aarch64-linux headers_install
$ cd ..
我們也可以在構建binutils之前做這件事。
儘管第4步,configure指令碼期望linux kernel header依據安裝,但是實際上在步驟6之前,當我們編譯標準C庫時,linux kernel headers不會被用到。
因為Linux kernel和其他開源工程不一樣,它有一個不同的方式來識別目標CPU架構: ARCH=arm
剩下的步驟涉及構建GCC和Glibc。這裡有個道道,就是部分gcc需要部分glibc被構建,而部分glibc又需要gcc被構建。我們不能一步搞定這些編譯,而是要分成幾步。我們要這幾個包之間來往幾次。
3. C/C++ Compilers
該步將構建gcc的C和C++編譯器,並安裝到/opt/cross/bin,目前還不能引用這些編譯器來構建庫。
$ mkdir -p build-gcc
$ cd build-gcc
$ ../gcc-4.9.2/configure --prefix=/opt/cross --target=aarch64-linux --enable-languages=c,c++ --disable-multilib
$ make -j4 all-gcc
$ make install-gcc
$ cd ..
因為我們指定了--target=aarch64-linux,構建指令碼會依據aarch64-linux-字首查詢第一步安裝的binutils工具。同樣,C/C++編譯器的名字也會帶上aarch64-linux-字首。
--enable-languages=c,c++避免了在GCC套件中出現其他的編譯器,比如Fortran、Java等。
4. Standard C Library Headers and Startup Files
安裝標準C庫標頭檔案到/opt/cross/aarch64-linux/include。我們會使用第三步構建的C編譯器來編譯庫的startup files並安裝到/opt/cross/aarch64-linux/lib。最後我們建立幾個傀儡檔案,libc.so和stubs.h,在第5步會用到,但是第6步會替換為真的。
$ mkdir -p build-glibc
$ cd build-glibc
$ ../glibc-2.20/configure --prefix=/opt/cross/aarch64-linux --build=$MACHTYPE --host=aarch64-linux --target=aarch64-linux --with-headers=/opt/cross/aarch64-linux/include --disable-multilib libc_cv_forced_unwind=yes
$ make install-bootstrap-headers=yes install-headers
$ make -j4 csu/subdir_lib
$ install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross/aarch64-linux/lib
$ aarch64-linux-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /opt/cross/aarch64-linux/lib/libc.so
$ touch /opt/cross/aarch64-linux/include/gnu/stubs.h
$ cd ..
--prefix=/opt/cross/aarch64-linux告訴configure指令碼它要安裝標頭檔案和庫到這裡。注意這個和普通的--prefix。
Glibc的configure需要我們制定所有的--build,--host和--target系統型別。
$MACHTYPE是一個預定義的環境變數,表示正在執行build指令碼的機器。--build=$MACHTYPE是必須的,因為在第六步中,該build指令碼將編譯一些額外的工具,這些工具是build程序的一部分。
--host,在glibc的configure中,--host和--target選項都指glibc庫最終執行的系統。
我們手動安裝C庫startup檔案,ctr1.o ctri.o和ctrn.o。其他的方法好像都有副作用。
5. Compiler Support Library
使用第三步的交叉編譯器構建compiler support library,編譯器支援的庫包含一些C++異常處理樣板程式碼等等。該庫依賴第四步安裝的startup file。第六步需要該庫。不像其他的指導手冊,我們不需要重新執行gcc configure。只需要在相同配置下構建額外的target即可。
$ cd build-gcc
$ make -j4 all-target-libgcc
$ make install-target-libgcc
$ cd ..
兩個靜態庫,libgcc.a和libgcc_eh.a,安裝到/opt/cross/lib/gcc/aarch64-linux/4.9.2.
共享庫,lingcc_s.so,安裝到/opt/cross/aarch64-linux/lib64.
6. Standard C Library
這步完成glibc的安裝。安裝標準C庫到/opt/cross/aarch64-linux/lib中。靜態庫名字為libc.a,動態庫為libc.so
$ cd build-glibc
$ make -j4
$ make install
$ cd ..
7. Standard C++ Library
最後完成gcc的安裝,構建標準C++庫,安裝到/opt/cross/aarch64-linux/lib64。它依賴第六步的C庫。目標靜態庫名字為libstdc++.a,動態庫為libstdc++.so。
$ cd build-gcc
$ make -j4
$ make install
$ cd ..
http://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/