如何建立Linux下的ARM交叉編譯環境

來源:互聯網
上載者:User

最簡單的方法就是下載一個buildtoolchain.tar.gz安裝就行了,有時候就是想自己親身體驗一下安裝定製過程,Linux的樂趣也在這點。從網上搜集了些資料,以備日後查閱。    
如何為嵌入式開發建立交叉編譯環境

 

  
 
< language=java type=text/java script>      
 
 

 
梁元恩 , 軟體工程師

2005 年 9 月

        在進行嵌入式開發之前,首先要建立一個交叉編譯環境,這是一套編譯器、連接器和libc庫等組成的開發環境。文章通過一個具體的例子說明了這些嵌入式交叉編譯開發工具的製作過程。

隨著消費類電子產品的大量開發和應用和Linux作業系統的不斷健壯和強大,嵌入式系統越來越多的進入人們的生活之中,應用範圍越來越廣。

在裁減和定製Linux,運用於你的嵌入式系統之前,由於一般嵌入式開發系統儲存大小有限,通常你都要在你的強大的pc機上建立一個用於目標機的交叉編譯環境。這是一個由編譯器、連接器和解譯器組成的綜合開發環境。交叉編譯工具主要由 binutils、gcc 和 glibc 幾個部分組成。有時出於減小 libc 庫大小的考慮,你也可以用別的 c 庫來代替 glibc,例如 uClibc、dietlibc 和 newlib。建立一個交叉編譯工具鏈是一個相當複雜的過程,如果你不想自己經曆複雜的編譯過程,網上有一些編譯好的可用的交叉編譯工具鏈可以下載。

下面我們將以建立針對arm的交叉編譯開發環境為例來解說整個過程,其他的體繫結構與這個相類似,只要作一些對應的改動。我的開發環境是,宿主機 i386-redhat-7.2,目標機 arm。

這個過程如下

1. 下載源檔案、補丁和建立編譯的目錄

2. 建立核心標頭檔

3. 建立二進位工具(binutils)

4. 建立初始編譯器(bootstrap gcc)

5. 建立c庫(glibc)

6. 建立全套編譯器(full gcc)

下載源檔案、補丁和建立編譯的目錄

1. 選定軟體版本號碼

選擇軟體版本號碼時,先看看glibc原始碼中的INSTALL檔案。那裡列舉了該版本的glibc編譯時間所需的binutils 和gcc的版本號碼。例如在 glibc-2.2.3/INSTALL 檔案中推薦 gcc 用 2.95以上,binutils 用 2.10.1 以上版本。

我選的各個軟體的版本是:

linux-2.4.21+rmk2
binutils-2.10.1
gcc-2.95.3
glibc-2.2.3
glibc-linuxthreads-2.2.3

如果你選的glibc的版本號碼低於2.2,你還要下載一個叫glibc-crypt的檔案,例如glibc-crypt-2.1.tar.gz。 Linux 核心你可以從www.kernel.org 或它的鏡像下載。

Binutils、gcc和glibc你可以從FSF的FTP網站ftp://ftp.gun.org/gnu/ 或它的鏡像去下載。在編譯glibc時,要用到 Linux 核心中的 include 目錄的核心標頭檔。如果你發現有變數沒有定義而導致編譯失敗,你就改變你的核心版本號碼。例如我開始用linux-2.4.25+vrs2,編譯glibc-2.2.3 時報 BUS_ISA 沒定義,後來發現在 2.4.23 開始它的名字被改為 CTL_BUS_ISA。如果你沒有完全的把握保證你改的核心改完全了,就不要動核心,而是把你的 Linux 核心的版本號碼降低或升高,來適應 glibc。

Gcc 的版本號碼,推薦用 gcc-2.95 以上的。太老的版本編譯可能會出問題。Gcc-2.95.3 是一個比較穩定的版本,也是核心開發人員推薦用的一個 gcc 版本。

如果你發現無法編譯過去,有可能是你選用的軟體中有的加入了一些新的特性而其他所選軟體不支援的原因,就相應降低該軟體的版本號碼。例如我開始用 gcc-3.3.2,發現編譯不過,報 as、ld 等版本太老,我就把 gcc 降為 2.95.3。太新的版本大多沒經過大量的測試,建議不要選用。

 
 

2. 建立工作目錄

首先,我們建立幾個用來工作的目錄:

在你的使用者目錄,我用的是使用者liang,因此使用者目錄為 /home/liang,先建立一個項目目錄embedded。

$pwd 
/home/liang
$mkdir embedded
 

再在這個項目目錄 embedded 下建立三個目錄 build-tools、kernel 和 tools。

build-tools-用來存放你下載的 binutils、gcc 和 glibc 的原始碼和用來編譯這些原始碼的目錄。

kernel-用來存放你的核心原始碼和核心補丁。

tools-用來存放編譯好的交叉編譯工具和庫檔案。

$cd embedded
$mkdir  build-tools kernel tools
 

執行完後目錄結構如下:

$ls embedded
build-tools kernel tools
 

3. 輸出和環境變數

我們輸出如下的環境變數方便我們編譯。

$export PRJROOT=/home/liang/embedded
$export TARGET=arm-linux
$export PREFIX=$PRJROOT/tools
$export TARGET_PREFIX=$PREFIX/$TARGET
$export PATH=$PREFIX/bin:$PATH
 

如果你不慣用環境變數的,你可以直接用絕對或相對路徑。我如果不用環境變數,一般都用絕對路徑,相對路徑有時會失敗。環境變數也可以定義在.bashrc檔案中,這樣當你logout或換了控制台時,就不用老是export這些變數了。

體繫結構和你的TAEGET變數的對應如下表

 

你可以在通過glibc下的config.sub指令碼來知道,你的TARGET變數是否被支援,例如:

$./config.sub  arm-linux
arm-unknown-linux-gnu
 

在我的環境中,config.sub 在 glibc-2.2.3/scripts 目錄下。

網上還有一些 HOWTO 可以參考,ARM 體繫結構的《The GNU Toolchain for ARM Target HOWTO》,PowerPC 體繫結構的《Linux for PowerPC Embedded Systems HOWTO》等。對TARGET的選取可能有協助。

4. 建立編譯目錄

為了把源碼和編譯時間產生的檔案分開,一般的編譯工作不在的源碼目錄中,要另建一個目錄來專門用於編譯。用以下的命令來建立編譯你下載的binutils、gcc和glibc的原始碼的目錄。

$cd $PRJROOT/build-tools
$mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patch
 

build-binutils-編譯binutils的目錄
build-boot-gcc-編譯gcc 啟動部分的目錄
build-glibc-編譯glibc的目錄
build-gcc-編譯gcc 全部的目錄
gcc-patch-放gcc的補丁的目錄

gcc-2.95.3 的補丁有 gcc-2.95.3-2.patch、gcc-2.95.3-no-fixinc.patch 和gcc-2.95.3-returntype-fix.patch,可以從 http://www.linuxfromscratch.org/ 下載到這些補丁。

再將你下載的 binutils-2.10.1、gcc-2.95.3、glibc-2.2.3 和 glibc-linuxthreads-2.2.3 的原始碼放入 build-tools 目錄中

看一下你的 build-tools 目錄,有以下內容:

$ls
binutils-2.10.1.tar.bz2     build-gcc   gcc-patch
build-binutls            build-glibc          glibc-2.2.3.tar.gz
build-boot-gcc           gcc-2.95.3.tar.gz glibc-linuxthreads-2.2.3.tar.gz
 

 
 

建立核心標頭檔

把你從 www.kernel.org 下載的核心原始碼放入 $PRJROOT /kernel 目錄

進入你的 kernel 目錄:

$cd $PRJROOT /kernel
 

解開核心原始碼

$tar -xzvf linux-2.4.21.tar.gz
 

$tar -xjvf linux-2.4.21.tar.bz2
 

小於 2.4.19 的核心版本解開會產生一個 linux 目錄,沒帶版本號碼,就將其改名。

$mv linux linux-2.4.x
 

給 Linux 核心打上你的補丁

$cd linux-2.4.21
$patch -p1 < ../patch-2.4.21-rmk2
 

編譯核心產生標頭檔

$make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

你也可以用 config 和 xconfig 來代替 menuconfig,但這樣用可能會沒有設定某些設定檔選項和沒有產生下面編譯所需的標頭檔。推薦大家用 make menuconfig,這也是核心開發人員用的最多的配置方法。配置完退出並儲存,檢查一下的核心目錄中的 include/linux/version.h 和 include/linux/autoconf.h 檔案是不是產生了,這是編譯 glibc 是要用到的,version.h 和 autoconf.h 檔案的存在,也說明了你產生了正確的標頭檔。

還要建立幾個正確的連結

$cd include
$ln -s asm-arm asm
$cd asm
$ln -s arch-epxa arch
$ln -s proc-armv proc
 

接下來為你的交叉編譯環境建立你的核心標頭檔的連結

$mkdir -p $TARGET_PREFIX/include
$ln -s $PRJROOT/kernel/linux-2.4.21/include/linux  $TARGET_PREFIX/include/linux
$in -s $PRJROOT/kernel/linux-2.4.21/include/asm-arm  $TARGET_PREFIX/include/asm
 

也可以把 Linux 核心標頭檔拷貝過來用

$mkdir -p $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/linux  $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/asm-arm  $TARGET_PREFIX/include  
 

 
 

建立二進位工具(binutils)

binutils是一些二進位工具的集合,其中包含了我們常用到的as和ld。

首先,我們解壓我們下載的binutils源檔案。

$cd $PRJROOT/build-tools
$tar -xvjf binutils-2.10.1.tar.bz2
 

然後進入build-binutils目錄配置和編譯binutils。

$cd build-binutils
$../binutils-2.10.1/configure --target=$TARGET --prefix=$PREFIX
 

--target 選項是指出我們產生的是 arm-linux 的工具,--prefix 是指出我們可執行檔安裝的位置。

會出現很多 check,最後產生 Makefile 檔案。

有了 Makefile 後,我們來編譯並安裝 binutils,命令很簡單。

$make
$make install
 

看一下我們 $PREFIX/bin 下的產生的檔案

$ls $PREFIX/bin
arm-linux-addr2line arm-linux-gasp arm-linux-objdump  arm-linux-strings
arm-linux-ar   arm-linux-ld  arm-linux-ranlib  arm-linux-strip
arm-linux-as   arm-linux-nm  arm-linux-readelf 
arm-linux-c++filt  arm-linux-objcopy arm-linux-size
 

我們來解釋一下上面產生的可執行檔都是用來幹什麼的

add2line - 將你要找的地址轉成檔案和行號,它要使用 debug 資訊。

Ar-產生、修改和解開一個封存檔案

As-gnu 的彙編器

C++filt-C++ 和 java 中有一種重載函數,所用的重載函數最後會被編譯轉化成彙編的標號,c++filt 就是實現這種反向的轉化,根據標號得到函數名。

Gasp-gnu 彙編器先行編譯器。

Ld-gnu 的連接器

Nm-列出目標檔案的符號和對應的地址

Objcopy-將某種格式的目標檔案轉化成另外格式的目標檔案

Objdump-顯示目標檔案的資訊

Ranlib-為一個封存檔案產生一個索引,並將這個索引存入封存檔案中

Readelf-顯示 elf 格式的目標檔案的資訊

Size-顯示目標檔案各個節的大小和目標檔案的大小

Strings-列印出目標檔案中可以列印的字串,有個預設的長度,為4

Strip-剝掉目標檔案的所有的符號資訊

 
 

建立初始編譯器(bootstrap gcc)

首先進入 build-tools 目錄,將下載 gcc 原始碼解壓

$cd $PRJROOT/build-tools
$tar -xvzf  gcc-2.95.3.tar.gz
 

然後進入 gcc-2.95.3 目錄給 gcc 打上補丁

$cd gcc-2.95.3
$patch -p1< ../gcc-patch/gcc-2.95.3.-2.patch
$patch -p1< ../gcc-patch/gcc-2.95.3.-no-fixinc.patch
$patch -p1< ../gcc-patch/gcc-2.95.3-returntype-fix.patch
echo timestamp > gcc/cstamp-h.in
 

在我們編譯並安裝 gcc 前,我們先要改一個檔案 $PRJROOT/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

你如果沒定義 -Dinhibit,編譯時間將會報如下的錯誤

http://www.cnblogs.com/gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
http://www.cnblogs.com/gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
 

如果沒有定義 -D__gthr_posix_h,編譯時間會報如下的錯誤

In file included from gthr-default.h:1,
                 from http://www.cnblogs.com/gcc-2.95.3/gcc/gthr.h:98,
                 from http://www.cnblogs.com/gcc-2.95.3/gcc/libgcc2.c:3034:
http://www.cnblogs.com/gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
 

還有一種與-Dinhibit同等效果的方法,那就是在你配置configure時多加一個參數-with-newlib,這個選項不會迫使我們必須使用newlib。我們編譯了bootstrap-gcc後,仍然可以選擇任何c庫。

接著就是配置boostrap gcc, 後面要用bootstrap gcc 來編譯 glibc 庫。

$cd ..; cd build-boot-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX \
>--without-headers  --enable-languages=c --disable-threads
 

這條命令中的 -target、--prefix 和配置 binutils 的含義是相同的,--without-headers 就是指不需要標頭檔,因為是交叉編譯工具,不需要本機上的標頭檔。-enable-languages=c是指我們的 boot-gcc 只支援 c 語言。--disable-threads 是去掉 thread 功能,這個功能需要 glibc 的支援。

接著我們編譯並安裝 boot-gcc

$make all-gcc
$make install-gcc
 

我們來看看 $PREFIX/bin 裡面多了哪些東西

$ls $PREFIX/bin
 

你會發現多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 幾個檔案。

Gcc-gnu 的 C 語言編譯器

Unprotoize-將 ANSI C 的源碼轉化為 K&R C 的形式,去掉函數原型中的參數類型。

Cpp-gnu的 C 的先行編譯器

Gcov-gcc 的輔助測試載入器,可以用它來分析和優程式。

使用 gcc3.2 以及 gcc3.2 以上版本時,配置 boot-gcc 不能使用 --without-headers 選項,而需要使用 glibc 的標頭檔。

 
 

建立 c 庫(glibc)

首先解壓 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 原始碼

$cd $PRJROOT/build-tools
$tar -xvzf glibc-2.2.3.tar.gz
$tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3
 

然後進入 build-glibc 目錄配置 glibc

$cd build-glibc
$CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix="/usr"
--enable-add-ons --with-headers=$TARGET_PREFIX/include
 

CC=arm-linux-gcc 是把 CC 變數設成你剛編譯完的boostrap gcc,用它來編譯你的glibc。--enable-add-ons是告訴glibc用 linuxthreads 包,在上面我們已經將它放入了 glibc 源碼目錄中,這個選項等價於 -enable-add-ons=linuxthreads。--with-headers 告訴 glibc 我們的linux 核心標頭檔的目錄位置。

配置完後就可以編譯和安裝 glibc

$make
$make install_root=$TARGET_PREFIX prefix="" install
 

然後你還要修改 libc.so 檔案


GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)

改為
GROUP ( libc.so.6 libc_nonshared.a)

這樣串連程式 ld 就會在 libc.so 所在的目錄尋找它需要的庫,因為你的機子的/lib目錄可能已經裝了一個相同名字的庫,一個為編譯可以在你的宿主機上啟動並執行程式的庫,而不是用於交叉編譯的。

 
 

建立全套編譯器(full gcc)

在建立boot-gcc 的時候,我們只支援了C。到這裡,我們就要建立全套編譯器,來支援C和C++。

$cd $PRJROOT/build-tools/build-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++
 

--enable-languages=c,c++ 告訴 full gcc 支援 c 和 c++ 語言。

然後編譯和安裝你的 full gcc

$make all
$make install
 

我們再來看看 $PREFIX/bin 裡面多了哪些東西

$ls $PREFIX/bin
 

你會發現多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 幾個檔案。

G++-gnu的 c++ 編譯器。

Protoize-與Unprotoize相反,將K&R C的源碼轉化為ANSI C的形式,函數原型中加入參數類型。

C++-gnu 的 c++ 編譯器。

到這裡你的交叉編譯工具就算做完了,簡單驗證一下你的交叉編譯工具。

用它來編譯一個很簡單的程式 helloworld.c

#i nclude

int main(void)
{
 printf("hello world\n");
 return 0;
}

$arm-linux-gcc helloworld.c -o helloworld
$file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1,
dynamically linked (uses shared libs), not stripped
 

上面的輸出說明你編譯了一個能在 arm 體繫結構下啟動並執行 helloworld,證明你的編譯工具做成功了。
 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/wonsoft/archive/2008/11/06/3242030.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.