在Ubuntu10.04中建立ARM交叉編譯環境
在Linux中建立整個ARM交叉編譯環境的整體過程爲:
1、 下載源文件
2、 在Linux中建立編譯目錄並設置環境變量
3、 建立內核頭文件
4、 建立二進制工具(binutils)
5、 建立初始編譯器(bootstrap gcc)
6、 建立glibc庫
7、 建立全套編譯器(full gcc)
8、 驗證編譯器
一、下載源文件
GNU的所有源碼文件都可以到這個地址下載:http://ftp.gnu.org/gnu/
Linux Kernel源代碼可以去這裏下載:http://www.kernel.org
mpc可以去這裏下載:http://www.multiprecision.org
我所下載的源碼包如下:
binutils-2.21.1.tar.bz2
gcc-4.6.1.tar.gz
glibc-2.14.tar.gz
glibc-linuxthreads-2.5.tar.bz2
glibc-ports-2.13.tar.gz
gmp-5.0.2.tar.bz2
linux-2.6.32.45.tar.gz
mpc-0.9.tar.gz
mpfr-2.4.2.tar.gz
注:mpfr不建議使用3.0.0版本。mpfr-3.0.0有Bug,會導致gcc編譯不過。
二、在Linux中建立編譯目錄並設置環境變量
選定自己的工作目錄,如我選擇/home/embedded作爲自己的工作目錄。然後再embedded中建立build-tools、kernel、tools三個文件夾。實例:
root@ubuntu:/home/huchao# cd /home/
root@ubuntu:/home# mkdir embedded
root@ubuntu:/home# cd embedded/
root@ubuntu:/home/embedded# mkdir build-tools kernel tools
root@ubuntu:/home/embedded# cd build-tools/
root@ubuntu:/home/embedded/build-tools# mkdir build-binutils build-boot-gcc build-glibc build-gcc
各文件夾的作用如下:
/home/embedded:交叉編譯環境的主目錄
/home/embedded/build-tools:存放binutils、gcc、glibc等GNU源碼和用來編譯這些源代碼的目錄
/home/embedded/kernel:用來存放Linux內核源代碼
/home/embedded/tools:用來存放編譯好的交叉編譯工具和庫文件
/home/embedded/build-tools/build-binutils:編譯binutils的目錄
/home/embedded/build-tools/build-boot-gcc:編譯gcc啓動部分的目錄
/home/embedded/build-tools/build-glibc:編譯glibc的目錄
/home/embedded/build-tools/build-gcc:編譯整個gcc的目錄
建立好編譯目錄之後便是設置環境變量(建議直接在~/.bashrc中修改,注意修改之後要重新運行Terminal)。如下:
export PRJROOT=/home/embedded
export TARGET=arm-linux
export PREFIX=$PRJROOT/tools
export TARGET_PREFIX=$PREFIX/$TARGET
export PATH=$PREFIX/bin:$PATH
各個環境變量的意義如下:
PRJROOT:整個交叉編譯環境的根目錄
TARGET:目標文件對應的architecture,arm-linux表示編譯出來的target只能在arm architecture中運行
PREFIX:目標文件夾的路徑前綴
TARGET_PREFIX:目標文件夾的路徑前綴路徑
PATH:可執行文件路徑,這裏主要指定編譯工具等
三、建立內核頭文件
將Linux內核源碼解壓至$PRJROOT/kernel目錄,然後建立幾個文件的符號鏈接,最後生成version.h文件。實例:
首先解壓Linux內核源文件
root@ubuntu:/home/embedded/kernel# cp /mnt/hgfs/VMwareShare_Ubuntux64/linux-2.6.32.45.tar.gz .
root@ubuntu:/home/embedded/kernel# tar -xvf linux-2.6.32.45.tar.gz
root@ubuntu:/home/embedded/kernel# mkdir /home/embedded/tools/arm-linux
root@ubuntu:/home/embedded/kernel# mkdir /home/embedded/tools/arm-linux/include
root@ubuntu:/home/embedded/kernel# ln -s /home/embedded/kernel/linux-2.6.32.45/include/linux /home/embedded/tools/arm-linux/include/linux
root@ubuntu:/home/embedded/kernel# ln -s /home/embedded/kernel/linux-2.6.32.45/include/asm-generic /home/embedded/tools/arm-linux/include/asm-generic
root@ubuntu:/home/embedded/kernel# ln -s /home/embedded/kernel/linux-2.6.32.45/arch/arm/include/asm /home/embedded/tools/arm-linux/include/asm
下面檢查上面創建的符號鏈接是否正確。實例:
root@ubuntu:/home/embedded/kernel# cd /home/embedded/tools/arm-linux/include/
root@ubuntu:/home/embedded/tools/arm-linux/include# ll
總用量 8
drwxr-xr-x 2 root root 4096 2011-09-29 05:12 ./
drwxr-xr-x 3 root root 4096 2011-09-29 05:07 ../
lrwxrwxrwx 1 root root 58 2011-09-29 05:12 asm -> /home/embedded/kernel/linux-2.6.32.45/arch/arm/include/asm/
lrwxrwxrwx 1 root root 57 2011-09-29 05:10 asm-generic -> /home/embedded/kernel/linux-2.6.32.45/include/asm-generic/
lrwxrwxrwx 1 root root 51 2011-09-29 05:09 linux -> /home/embedded/kernel/linux-2.6.32.45/include/linux/
看到如上結果表示符號鏈接創建正確。
最後生成version.h文件。實例:
root@ubuntu:/home/embedded/kernel/linux-2.6.32.45# cd /home/embedded/kernel/linux-2.6.32.45/
root@ubuntu:/home/embedded/kernel/linux-2.6.32.45# make include/linux/version.h
CHK include/linux/version.h
UPD include/linux/version.h
下面查看version.h文件是否建立成功。實例:
root@ubuntu:/home/embedded/kernel/linux-2.6.32.45# cd /home/embedded/kernel/linux-2.6.32.45/include/linux/
root@ubuntu:/home/embedded/kernel/linux-2.6.32.45/include/linux# ll | grep version.h
-rw-r--r-- 1 root root 97 2011-09-29 05:14 version.h
看到如上結果表示version.h文件建立成功。
四、建立二進制工具(binutils)
Binutils是一些二進制工具集合,其中包含了常用的一些命令。首先將binutils-2.21.1.tar.bz2解壓至build-tools,然後進入build-binutils目錄,配置並編譯binutils,最後使用make install進行安裝。實例:
root@ubuntu:/home/embedded/build-tools# cd /home/embedded/build-tools/
root@ubuntu:/home/embedded/build-tools# cp /mnt/hgfs/VMwareShare_Ubuntux64/binutils-2.21.1.tar.bz2 .
root@ubuntu:/home/embedded/build-tools# tar -xjf binutils-2.21.1.tar.bz2
root@ubuntu:/home/embedded/build-tools# cd build-binutils/
root@ubuntu:/home/embedded/build-tools/build-binutils# ../binutils-2.21.1/configure --target=$TARGET --prefix=$PREFIX
root@ubuntu:/home/embedded/build-tools/build-binutils# make
root@ubuntu:/home/embedded/build-tools/build-binutils# make install
完成後,去$PREFIX中檢查一下生成的工具。實例:
root@ubuntu:/home/embedded/build-tools/build-binutils# cd /home/embedded/tools/bin
root@ubuntu:/home/embedded/tools/bin# ll
總用量 49988
drwxr-xr-x 2 root root 4096 2011-09-29 05:30 ./
drwxr-xr-x 6 root root 4096 2011-09-29 05:30 ../
-rwxr-xr-x 1 root root 3009029 2011-09-29 05:30 arm-linux-addr2line*
-rwxr-xr-x 2 root root 3161667 2011-09-29 05:30 arm-linux-ar*
-rwxr-xr-x 2 root root 4789065 2011-09-29 05:30 arm-linux-as*
-rwxr-xr-x 1 root root 2981965 2011-09-29 05:30 arm-linux-c++filt*
-rwxr-xr-x 1 root root 77829 2011-09-29 05:30 arm-linux-elfedit*
-rwxr-xr-x 1 root root 3456392 2011-09-29 05:30 arm-linux-gprof*
-rwxr-xr-x 4 root root 4502054 2011-09-29 05:30 arm-linux-ld*
-rwxr-xr-x 4 root root 4502054 2011-09-29 05:30 arm-linux-ld.bfd*
-rwxr-xr-x 2 root root 3048986 2011-09-29 05:30 arm-linux-nm*
-rwxr-xr-x 2 root root 3710926 2011-09-29 05:30 arm-linux-objcopy*
-rwxr-xr-x 2 root root 4176150 2011-09-29 05:30 arm-linux-objdump*
-rwxr-xr-x 2 root root 3161666 2011-09-29 05:30 arm-linux-ranlib*
-rwxr-xr-x 1 root root 807601 2011-09-29 05:30 arm-linux-readelf*
-rwxr-xr-x 1 root root 3036038 2011-09-29 05:30 arm-linux-size*
-rwxr-xr-x 1 root root 3010718 2011-09-29 05:30 arm-linux-strings*
-rwxr-xr-x 2 root root 3710917 2011-09-29 05:30 arm-linux-strip*
這些生成的文件的作用分別爲:
arm-linux-addr2line:將你要找的地址轉成文件和行號,它要使用 debug 信息
arm-linux-ar:產生、修改和解開一個存檔文件
arm-linux-as:GNU的彙編器
arm-linux-c++filt:C++ 和 java 中有一種重載函數,所用的重載函數最後會被編譯轉化成彙編的標,c++filt 就是實現這種反向的轉化,根據標號得到函數名
arm-linux-elfedit:用途暫時未知
arm-linux-gprof:GNU彙編器預編譯器
arm-linux-ld:GNU的連接器
arm-linux-ld.bfd:用途暫時未知
arm-linux-nm:列出目標文件的符號和對應的地址
arm-linux-objcopy:將某種格式的目標文件轉化成另外格式的目標文件
arm-linux-objdump:顯示目標文件的信息
arm-linux-ranlib:爲一個存檔文件產生一個索引,並將這個索引存入存檔文件中
arm-linux-readelf:顯示 elf 格式的目標文件的信息
arm-linux-size:顯示目標文件各個節的大小和目標文件的大小
arm-linux-strings:打印出目標文件中可以打印的字符串,有個默認的長度,爲4
arm-linux-strip:剝掉目標文件的所有的符號信息
五、建立初始編譯器(bootstrap gcc)
Gcc是最主要的編譯器。首先將gcc-4.6.1.tar.gz解壓至build-tools,然後將gmp-5.0.2.tar.bz2、mpfr-2.4.2.tar.gz、mpc-0.9.tar.gz分別解壓至gcc源碼所在目錄,並將目錄重命名爲gmp、mpfr、mpc,然後進入build-boot-gcc目錄,進行編譯配置,然後make all-gcc並安裝,最後make all-target-gcc並安裝。實例:
root@ubuntu:/home/embedded/build-tools# cd /home/embedded/build-tools/
root@ubuntu:/home/embedded/build-tools# cp /mnt/hgfs/VMwareShare_Ubuntux64/gcc-4.6.1.tar.gz .
root@ubuntu:/home/embedded/build-tools# tar -xvf gcc-4.6.1.tar.gz
root@ubuntu:/home/embedded/build-tools# cd gcc-4.6.1/
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# cp /mnt/hgfs/VMwareShare_Ubuntux64/mpfr-2.4.2.tar.gz .
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# cp /mnt/hgfs/VMwareShare_Ubuntux64/gmp-5.0.2.tar.bz2 .
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# cp /mnt/hgfs/VMwareShare_Ubuntux64/mpc-0.9.tar.gz .
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# tar -xvf mpfr-2.4.2.tar.gz
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# mv mpfr-2.4.2/ mpfr
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# tar -xjf gmp-5.0.2.tar.bz2
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# mv gmp-5.0.2/ gmp
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# tar -xvf mpc-0.9.tar.gz
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# mv mpc-0.9 mpc
這裏需要修改一下編譯配置文件:/home/embedded/build-tools/gcc-4.6.1/gcc/config/arm/t-linux
將“TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer –fPIC”改爲“TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h”。
然後便可以切換到目錄build-boot-gcc進行編譯了,實例:
root@ubuntu:/home/embedded/build-tools/gcc-4.6.1# cd /home/embedded/build-tools/build-boot-gcc/
root@ubuntu:/home/embedded/build-tools/build-boot-gcc# ../gcc-4.6.1/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-threads --with-newlib --disable-shared --disable-libmudflap --disable-libssp
root@ubuntu:/home/embedded/build-tools/build-boot-gcc# make all-gcc
root@ubuntu:/home/embedded/build-tools/build-boot-gcc# make install-gcc
root@ubuntu:/home/embedded/build-tools/build-boot-gcc# make all-target-libgcc
root@ubuntu:/home/embedded/build-tools/build-boot-gcc# make install-target-libgcc
完成之後,$PREFIX/bin下又多了幾個文件:
-rwxr-xr-x 1 root root 864105 2011-09-29 06:32 arm-linux-cpp*
-rwxr-xr-x 2 root root 854850 2011-09-29 06:32 arm-linux-gcc*
-rwxr-xr-x 2 root root 854850 2011-09-29 06:32 arm-linux-gcc-4.6.1*
-rwxr-xr-x 1 root root 126539 2011-09-29 06:32 arm-linux-gcov*
這些生成的文件的作用分別爲:
arm-linux-cpp:GNU的C的預編譯器
arm-linux-gcc:GNU的C語言編譯器
arm-linux-gcc-4.6.1:GNU的C語言編譯器,其實和arm-linux-gcc是一樣的
arm-linux-gcov:gcc 的輔助測試工具,用來分析和優化程序
六、建立glic庫
Glibc是交叉編譯環境的運行庫。首先將glibc-2.14.tar.gz解壓至build-tools,然後將glibc-linuxthreads-2.5.tar.bz2解壓至glibc源碼所在目錄,將glibc-ports-2.13.tar.gz解壓至glibc源碼所在目錄,並重命名爲ports。進入build-glibc文件夾,建立用於配置glibc的config.cache文件,然後配置並編譯glibc,安裝glibc,最後修改libc.so。實例:
root@ubuntu:/home/embedded/build-tools# cd /home/embedded/build-tools/
root@ubuntu:/home/embedded/build-tools# cp /mnt/hgfs/VMwareShare_Ubuntux64/glibc-2.14.tar.gz .
root@ubuntu:/home/embedded/build-tools# tar -xvf glibc-2.14.tar.gz
root@ubuntu:/home/embedded/build-tools# cd glibc-2.14/
root@ubuntu:/home/embedded/build-tools/glibc-2.14# cp /mnt/hgfs/VMwareShare_Ubuntux64/glibc-linuxthreads-2.5.tar.bz2 .
root@ubuntu:/home/embedded/build-tools/glibc-2.14# tar -xjf glibc-linuxthreads-2.5.tar.bz2
root@ubuntu:/home/embedded/build-tools/glibc-2.14# cp /mnt/hgfs/VMwareShare_Ubuntux64/glibc-ports-2.13.tar.gz .
root@ubuntu:/home/embedded/build-tools/glibc-2.14# tar -xvf glibc-ports-2.13.tar.gz
root@ubuntu:/home/embedded/build-tools/glibc-2.14# mv glibc-ports-2.13/ ports
root@ubuntu:/home/embedded/build-tools/glibc-2.14# cd ../build-glibc/
建立用於配置glibc的config.cache文件,文件內容爲:
libc_cv_forced_unwind=yes
libc_cv_c_cleanup=yes
libc_cv_arm_tls=yes
建立完成之後,便可以開始配置並編譯glibc了,實例:
root@ubuntu:/home/embedded/build-tools/build-glibc# BUILD_CC="gcc" CC=$TARGET-gcc ../glibc-2.14/configure --host=$TARGET --target=$TARGET --prefix=/usr --enable-add-ons --disable-profile --cache-file=config.cache --with-binutils=$PREFIX/bin/ --with-headers=$TARGET_PREFIX/include/
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
../ports/sysdeps/unix/sysv/linux/arm/sigrestorer.S:30: Error: previous CFI entry not closed (missing .cfi_endproc)
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/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)
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
../sysdeps/unix/syscall-template.S:82: Error: CFI instruction used without previous .cfi_startproc
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/sysdeps/unix/syscall-template.S
找到如下行:
#define T_PSEUDO(SYMBOL, NAME, N) PSEUDO (SYMBOL, NAME, N)
在其上添加:
#define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name); \
DO_CALL (syscall_name, args); \
cmn r0, $4096;
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
allocatestack.c:247:33: 錯誤:‘TLS_DTV_UNALLOCATED’未聲明(在此函數內第一次使用)
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/nptl/allocatestack.c
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/elf/dl-tls.c
分別在文件中的include後面添加:
#define TLS_DTV_UNALLOCATED ((void *) -1l)
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
/home/embedded/tools/lib/gcc/arm-linux/4.6.1/../../../../arm-linux/bin/ld: cannot find -lgcc_eh
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# ln -s /home/embedded/tools/lib/gcc/arm-linux/4.6.1/libgcc.a /home/embedded/tools/lib/gcc/arm-linux/4.6.1/libgcc_eh.a
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
../sysdeps/ieee754/dbl-64/s_fma.c:152:15: 錯誤:‘FE_TOWARDZERO’未聲明(在此函數內第一次使用)
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/sysdeps/ieee754/dbl-64/s_fma.c
在文件中的include後面添加:
#define FE_TOWARDZERO 0xc00000
#define FE_INEXACT 16
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
編譯出錯:
../sysdeps/ieee754/dbl-64/s_fmaf.c:39:15: 錯誤:‘FE_TOWARDZERO’未聲明(在此函數內第一次使用)
解決方法:
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../glibc-2.14/sysdeps/ieee754/dbl-64/s_fmaf.c
在文件中的include後面添加:
#define FE_TOWARDZERO 0xc00000
#define FE_INEXACT 16
繼續make編譯
root@ubuntu:/home/embedded/build-tools/build-glibc# make
root@ubuntu:/home/embedded/build-tools/build-glibc# make install_root=$TARGET_PREFIX prefix="" install
最後,修改libc.so便完成此步驟
root@ubuntu:/home/embedded/build-tools/build-glibc# vi ../../tools/arm-linux/lib/libc.so
找到如下行:
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) )
將其改爲:
GROUP ( libc.so.6 libc_nonshared.a )
七、建立全套編譯器(full gcc)
首先進入build-gcc目錄,然後配置並編譯full gcc,最後安裝就完成了。實例:
root@ubuntu:/home/embedded/build-tools/build-glibc# cd /home/embedded/build-tools/build-gcc/
root@ubuntu:/home/embedded/build-tools/build-gcc# ../gcc-4.6.1/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --disable-libgomp
root@ubuntu:/home/embedded/build-tools/build-gcc# make
root@ubuntu:/home/embedded/build-tools/build-gcc# make install
完成之後,$PREFIX/bin下又多了幾個文件:
-rwxr-xr-x 2 root root 869603 2011-09-29 19:25 arm-linux-c++*
-rwxr-xr-x 2 root root 869603 2011-09-29 19:25 arm-linux-g++*
這些生成的文件的作用分別爲:
arm-linux-g++:GNU的c++編譯器
arm-linux-c++:等同於arm-linux-g++
八、驗證編譯器
使用vim寫下如下代碼,並保存爲main.c文件:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
然後執行編譯命令。實例:
root@ubuntu:/home/embedded/tmp# arm-linux-gcc -static main.c –o helloworld
編譯完成後驗證最終編譯出的文件。實例:
root@ubuntu:/home/embedded/tmp# file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1, statically linked, for GNU/Linux 2.0.0, not stripped
有如上輸出表示編譯ARM版本程序成功。