1. 程式人生 > >交叉工具鏈製作至尊寶典

交叉工具鏈製作至尊寶典

一些必須知道的基礎知識

Debian 作業系統 以及 aptitude 命令autoconf and automake什麼是交叉編譯,configure 的幾個引數 build host target

build:
編譯程式碼的機器,的CPU指令集

host:
編譯生成的東西,的CPU指令集(目標板上的CPU的指令集)

target:
編譯生成的東西,他編譯生成的的東西,的指令集(所以此選項一般不用,大多隻有在做交叉工具鏈時使用)

0、以Expert mode 安裝Debian

不要升級,確保環境是一個純淨的環境

1、宣告環境變數 

export IS_TARGET=arm-linux
export DIR_SRC=/root/cross_toolchains/src
export PREFIX=/opt/cross_toolchains/arm
export CONFIGURE_BASE="../configure --prefix=$PREFIX --with-sysroot=$PREFIX"

2、下載製作交叉工具鏈所必須的的程式碼

binutils
ftp://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.gz
gcc
ftp://ftp.gnu.org/gnu/gmp/gmp-5.0.2.tar.gz
ftp://ftp.gnu.org/gnu/mpfr/mpfr-3.0.1.tar.gz
http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz
ftp://ftp.gnu.org/gnu/gcc/gcc-4.6.1/gcc-4.6.1.tar.gz
glibc
ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.gz
ftp://ftp.gnu.org/gnu/glibc/glibc-ports-2.13.tar.gz
linux kernel
http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.2.tar.bz2

3、安裝(解除安裝)必要的的軟體包

aptitude install build-essential automake bison flex texinfo gawk g\+\+
aptitude remove mawk

4、解壓、歸檔軟體包

cd $DIR_SRC
tar -xf binutils-2.21.tar.gz
tar -xf gmp-5.0.2.tar.gz
tar -xf mpc-0.9.tar.gz
tar -xf mpfr-3.0.1.tar.gz
tar -xf gcc-4.6.1.tar.bz2
tar -xf glibc-2.14.tar.gz
tar -xf glibc-ports-2.13.tar.gz
tar -xf linux-2.6.39.2.tar.bz2
mv gmp-5.0.2 gcc-4.6.1/gmp
mv mpc-0.9 gcc-4.6.1/mpc
mv mpfr-3.0.1 gcc-4.6.1/mpfr
mv glibc-ports-2.13 glibc-2.14/ports

5、編譯 BINUTILS

cd $DIR_SRC
cd binutils-2.21
mkdir build
cd build
$CONFIGURE_BASE --target=$IS_TARGET --disable-nls --enable-shared --disable-multilib
make configure-host
make
make install
export PATH=$PATH:$PREFIX/bin

問題:
編譯binutils一般不會遇到什麼問題,但是,如果前面步驟3中安裝的軟體不全會出現問題

6、建立用於編譯C庫的GCC

cd $DIR_SRC
cd gcc-4.6.1
mkdir build 
cd build
$CONFIGURE_BASE \
--target=$IS_TARGET \
--disable-nls \
--disable-shared \
--without-headers \
--with-newlib \
--enable-languages=c \
--disable-threads \
--disable-multilib \
--disable-decimal-float \
--disable-libgomp \
--disable-libmudflap \
--disable-libssp
make all-gcc all-target-libgcc
make install-gcc install-target-libgcc
值得注意的幾個configure選項
--target
--disable-shared
--without-headers
--with-newlib
--enable-language-c
--disable-thread
cd $PREFIX/lib/gcc/$IS_TARGET/4.6.1
ln -s libgcc.a libgcc_eh.a
有建議修改 gcc/config/t-linux 這個檔案
增加 -D__gthr_posix_h -Dinhibit_libc 兩個巨集,但我這裡沒這樣做,是因為:
在configure後,編譯使用的命令並不是 make 或者是 make all 而是 make all-gcc 和 make all-target-libgcc,所以很多問題不會出現
-with-newlib,這個選項不會迫使我們必須使用newlib
libgcc.mvars: No such file or directory
不能在 GCC 的原始碼目錄進行configure,必須在另外的目錄進行configure make 等工作
所以這裡在程式碼所在目錄下 mkdir build 並 cd build 再進行 ../configure 等工作
configure: error: C compiler cannot create executables
如果使用 make 或 make all 會出現這樣的問題,因為我們還未編譯出目標指令集的 C 庫
所以只能先使用 make all-gcc make all-target-libgcc
../../../../arm-linux/bin/ld: cannot find -lgcc
../../../../arm-linux/bin/ld: cannot find -lgcc_eh
很多資料都只寫了 make all-gcc 而沒有寫 make all-target-libgcc 這樣只建立了gcc,沒有建立libgcc.a會出現以上第一個錯誤
如果沒手工建立連結檔案 libgcc_eh.a 則會出現第二個錯誤

7、配置核心生成必要的標頭檔案

cd $DIR_SRC
cd linux-2.6.39.2
make ARCH=arm CROSS_COMPILE=$IS_TARGET- menuconfig
make ARCH=arm CROSS_COMPILE=$IS_TARGET-
mkdir -p $PREFIX/include
cd $PREFIX/include
ln -s $DIR_SRC/linux-2.6.39.2/arch/arm/include/asm asm
ln -s $DIR_SRC/linux-2.6.39.2/include/linux linux
ln -s $DIR_SRC/linux-2.6.39.2/include/asm-generic asm-generic
這裡並沒有將核心的標頭檔案複製到交叉工具鏈的安裝目錄
編譯C庫的時候,需要對應的CPU指令集的彙編程式碼所以做了連結處理
編譯核心在執行 make ARCH=arm CROSS_COMPILE=$IS_TARGET- 時如果出錯,是沒有關係的,這裡只要生成了對應的 version.h autoconf.h就可以了

8、編譯C庫

cd $DIR_SRC
cd glibc-2.9
mkdir build
cd build
vi ../configure
vi ../ports/sysdeps/unix/sysv/linux/arm/sigrestorer.S
vi ../sysdeps/unix/syscall-template.S 
vi ../nptl/allocatestack.c 
vi ../elf/dl-tls.c
vi ../sysdeps/ieee754/dbl-64/s_fma.c
vi ../sysdeps/ieee754/dbl-64/s_fmaf.c

具體的修改,我寫在下面(覺得還是要說清楚為什麼修改,所以就沒用sed命令或是做一些patch檔案了,請向下看)
CC=$IS_TARGET-gcc \
$CONFIGURE_BASE \
--host=$IS_TARGET \
-enable-add-ons \
--with-binutils=$PREFIX/bin \
--with-headers=$PREFIX/include \
libc_cv_forced_unwind=yes \
libc_cv_c_cleanup=yes
值得注意的幾個configure選項
--host
--with-headers
lib_cv_forced_unwind
lib_cv_c_cleanup
make
make install 
這裡編譯的時候並有選擇TARGET為EABI,所以在製作交叉工具鏈時會有很多問題需要修改
*** These critical programs are missing or too old: as ld
*** Check the INSTALL file for required versions.
vi ../configure 
查詢  "$AS --version" 將 2.1[3-9] 修改為 2.[1-2][0-9]
查詢  "$LD --version" 將 2.1[3-9] 修改為 2.[1-2][0-9]
Error: previous CFI entry not closed (missing .cfi_endproc)
vi ../ports/sysdeps/unix/sysv/linux/arm/sigrestorer.S
ENTRY(__default_sa_restorer) 下增加
END(__default_sa_restorer)
ENTRY(__default_rt_sa_restorer) 下增加
END(__default_rt_sa_restorer)
syscall-template.S:82: Error: CFI instruction used without previous .cfi_startproc
vi ../sysdeps/unix/syscall-template.S 
這個問題的修改我也不是十分確定,我是這樣來思考的
看到 syscall-template.S 中 有 #include <sysdep.h>
去檢視 ports/sysdeps/unix/sysv/linux/arm/sysdep.h
看到如下程式碼
#ifdef __ASSEMBLER__
#undef  PSEUDO

#define PSEUDO(name, syscall_name, args)                                      \
  .text;                                                                      \
  ENTRY (name);                                                               \
    DO_CALL (syscall_name, args);                                             \
    cmn r0, $4096;

猜測是__ASSEMBLER__巨集未開啟,以至於未能找到PSEUD0函式的宣告,則將

#define PSEUDO(name, syscall_name, args)                                      \
  .text;                                                                      \
  ENTRY (name);                                                               \
    DO_CALL (syscall_name, args);                                             \
    cmn r0, $4096;

這段程式碼 新增至 ../sysdeps/unix/syscall-template.S 中
LS_DTV_UNALLOCATED  undeclared (first use in this function)
vi ../nptl/allocatestack.c
vi ../elf/dl-tls.c 
這個錯誤會出現在編譯以上兩個檔案的時候,這個巨集的定義我grep了整個glibc的所有程式碼,沒找到ARM相關的宣告及定義,按照其他指令集的定義猜測著修改如下
在以上兩個C檔案中增加相應的定義

#define TLS_DTV_UNALLOCATED      ((void *) -1l)

E_TOWARDZERO undeclared (first use in this function)
E_INEXACT undeclared (first use in this function)
以上兩個錯誤會出現在以下兩個檔案的的編譯過程中
vi ../sysdeps/ieee754/dbl-64/s_fma.c
vi ../sysdeps/ieee754/dbl-64/s_fmaf.c
參考 ports/sysdeps/arm/eabi/bits/fenv.h中的定義
在兩個檔案中新增
#define FE_TOWARDZERO 0xc00000
#define FE_INEXACT 16
mawk: scripts/gen-sorted.awk: line 19: regular expression compile failed 
所以要 aptitude install gawk 所以也順帶著 aptitude remove mawk
configure: error: forced unwind support is required 
configure 中增加配置引數 libc_cv_forced_unwind=yes 
error: the compiler must support C cleanup handlin
configure 中增加配置引數libc_cv_c_cleanup=yes 
--enable-add-ons 為 C 庫 增加 thread 支援,目前預設使用的是 nptl 所以這裡沒有去下載 glibc-threads 相關的程式碼
--with-headers 指定核心標頭檔案所在的目錄

9、編譯完整的 gcc 工具鏈

mkdir -p $PREFIX/usr
cd $PREFIX/usr
ln -s ../include include
cd $PREFIX
mkdir -p opt/cross_toolchains
cd opt/cross_toolchains/
ln -s ../../../arm arm
cd $DIR_SRC
cd gcc-4.6.1
cd build
make clean
make distclean
rm * -rf
$CONFIGURE_BASE \
--target=arm-linux \
--enable-languages=c,c++ \
--enable-shared \
--disable-nls \
--enable-c99 \
--enable-long-long \
--disable-multilib \
--enable-__cxa_atexit
幾個值得注意的configure 選項
--target
--enable-shared
make
make install
The directory that should contain system headers does not exist:
這個問題我沒具體的去跟蹤了,從表面上看出來是一些路徑上的問題,並且經過驗證,這個問題是在configure時使用了--with-sysroot選項時產生的
為了嘗試不通過建立連結的方式去解決這個問題
在指明瞭 --includedir --libdir --sysconfdir 等等一系列引數後編譯,依然會出現此問題
所以不再跟蹤,暫且是當做GCC編譯環境上的一個 BUG好了
/opt/cross_toolchains/arm/arm-linux/bin/ld: cannot find /opt/cross_toolchains/arm/lib/libc.so.6 inside /opt/cross_toolchains/arm
這個問題更是有點神經病了,所以這裡也不跟蹤了,也是由於使用了 --with-sysroot選項產生的問題,建立了第二個連結檔案
目的是讓 /opt/cross_toolchains/arm 這個被當做是根目錄的目錄裡面能有一個跟 --prefix 指定的 /opt/cross_toolchains/arm 一樣的目錄結構(說起來真彆扭)
參考資料
https://www.ibm.com/developerworks/cn/linux/l-embcmpl/
http://cross-lfs.org/view/clfs-embedded/arm/cross-tools/introduction.html
http://www.linuxsir.org/bbs/showthread.php?t=267672(這個文章雖然有點老,也有點神,把一些能看懂的說的讓人看不懂,那個圖更是讓人覺得,汗,但原理還是說的很清楚的,這裡強調的--with-sysroot的3次出現的問題,還是值得仔細想想的,這也是我為什麼將 --with-sysroot 選項 做到$CONFIGURE_BASE 這個環境變數中的原因)