1. 程式人生 > >構建gcc交叉編譯工具鏈

構建gcc交叉編譯工具鏈

如何構建一個GCC交叉編譯工具鏈

GCC不僅是一個編譯器,它是一個開源工程,可以讓你建立各種編譯器。一些編譯器支援多執行緒,一些支援共享庫,一些支援Multilib(典型的應用是在64位機上執行32位應用程式),這些都取決於在編譯 編譯器 時的配置。

本文件將說明怎麼建立一個交叉編譯器。你需要一個已經安裝gccUnix-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

最開始的四個包:binutilsgccLinux kernelglibc是主要要用的包。後面三個mpfrgmpmpc你可以使用系統自帶的package manager安裝,但是可能比較舊。最後兩個包ISLCLooG是可選的,它們支援一些優化。

二、它們是怎麼有機結合在一起的呢?

當我們完成時,我們會構建如下的程式和庫。首先,構建左邊的工具,然後使用這些工具來構建右邊的程式和庫。我們將不構建目標系統的Linux kernel,但是我們需要kernel header來構建目標系統標準C庫。

左邊的編譯器將調用匯編器和連結器。其他的包MPFRGMPMPC將連線到編譯器中。

右邊圖中的a.out,執行在目標OS上,使用交叉編譯器,連線目標系統標準C庫和C++庫。C++標準庫呼叫標準C庫,C庫直接呼叫Linux kernel

注意,除了使用glibc外,還可以使用其他替代的C庫實現,比如Newlibcuclibc等,其他替代的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

剩下的步驟涉及構建GCCGlibc。這裡有個道道,就是部分gcc需要部分glibc被構建,而部分glibc又需要gcc被構建。我們不能一步搞定這些編譯,而是要分成幾步。我們要這幾個包之間來往幾次。


3. C/C++ Compilers

該步將構建gccCC++編譯器,並安裝到/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套件中出現其他的編譯器,比如FortranJava等。

4. Standard C Library Headers and Startup Files

安裝標準C庫標頭檔案到/opt/cross/aarch64-linux/include。我們會使用第三步構建的C編譯器來編譯庫的startup files並安裝到/opt/cross/aarch64-linux/lib。最後我們建立幾個傀儡檔案,libc.sostubs.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

Glibcconfigure需要我們制定所有的--build--host--target系統型別。

$MACHTYPE是一個預定義的環境變數,表示正在執行build指令碼的機器。--build=$MACHTYPE是必須的,因為在第六步中,該build指令碼將編譯一些額外的工具,這些工具是build程序的一部分。

--host,在glibcconfigure中,--host--target選項都指glibc庫最終執行的系統。

我們手動安裝Cstartup檔案,ctr1.o ctri.octrn.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.alibgcc_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/