<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 如何為嵌入式開(kāi)發(fā)建立交叉編譯環(huán)境

如何為嵌入式開(kāi)發(fā)建立交叉編譯環(huán)境

——
作者: 時(shí)間:2007-04-17 來(lái)源:電子產(chǎn)品世界 收藏

  在進(jìn)行開(kāi)發(fā)之前,首先要建立一個(gè)交叉編譯環(huán)境,這是一套、連接器和libc庫等組成的開(kāi)發(fā)環(huán)境。文章通過(guò)一個(gè)具體的例子說(shuō)明了這些交叉編譯開(kāi)發(fā)工具的制作過(guò)程。
隨著(zhù)消費類(lèi)電子產(chǎn)品的大量開(kāi)發(fā)和應用和Linux操作系統的不斷健壯和強大,系統越來(lái)越多的進(jìn)入人們的生活之中,應用范圍越來(lái)越廣。

  在裁減和定制Linux,運用于你的之前,由于一般嵌入式開(kāi)發(fā)系統存儲大小有限,通常你都要在你的強大的pc機上建立一個(gè)用于目標機的交叉編譯環(huán)境。這是一個(gè)由、連接器和解釋器組成的綜合開(kāi)發(fā)環(huán)境。交叉編譯工具主要由 binutils、gcc 和 glibc 幾個(gè)部分組成。有時(shí)出于減小 libc 庫大小的考慮,你也可以用別的 c 庫來(lái)代替 glibc,例如 uClibc、dietlibc 和 newlib。建立一個(gè)交叉編譯工具鏈是一個(gè)相當復雜的過(guò)程,如果你不想自己經(jīng)歷復雜的編譯過(guò)程,網(wǎng)上有一些編譯好的可用的交叉編譯工具鏈可以下載。

  下面我們將以建立針對arm的交叉編譯開(kāi)發(fā)環(huán)境為例來(lái)解說(shuō)整個(gè)過(guò)程,其他的體系結構與這個(gè)相類(lèi)似,只要作一些對應的改動(dòng)。我的開(kāi)發(fā)環(huán)境是,宿主機 i386-redhat-7.2,目標機 arm。

  這個(gè)過(guò)程如下

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

  2. 建立內核頭文件

  3. 建立二進(jìn)制工具(binutils)

  4. 建立初始(bootstrap gcc)

  5. 建立c庫(glibc)

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

  下載源文件、補丁和建立編譯的目錄

1. 選定軟件版本號

  選擇軟件版本號時(shí),先看看glibc源代碼中的INSTALL文件。那里列舉了該版本的glibc編譯時(shí)所需的binutils 和gcc的版本號。例如在 glibc-2.2.3/INSTALL 文件中推薦 gcc 用 2.95以上,binutils 用 2.10.1 以上版本。

  我選的各個(gè)軟件的版本是:

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,你還要下載一個(gè)叫g(shù)libc-crypt的文件,例如glibc-crypt-2.1.tar.gz。 Linux 內核你可以從www.kernel.org 或它的鏡像下載。

  Binutils、gcc和glibc你可以從FSF的FTP站點(diǎn)ftp://ftp.gun.org/gnu/ 或它的鏡像去下載。在編譯glibc時(shí),要用到 Linux 內核中的 include 目錄的內核頭文件。如果你發(fā)現有變量沒(méi)有定義而導致編譯失敗,你就改變你的內核版本號。例如我開(kāi)始用linux-2.4.25+vrs2,編譯glibc-2.2.3 時(shí)報 BUS_ISA 沒(méi)定義,后來(lái)發(fā)現在 2.4.23 開(kāi)始它的名字被改為 CTL_BUS_ISA。如果你沒(méi)有完全的把握保證你改的內核改完全了,就不要動(dòng)內核,而是把你的 Linux 內核的版本號降低或升高,來(lái)適應 glibc。

  Gcc 的版本號,推薦用 gcc-2.95 以上的。太老的版本編譯可能會(huì )出問(wèn)題。Gcc-2.95.3 是一個(gè)比較穩定的版本,也是內核開(kāi)發(fā)人員推薦用的一個(gè) gcc 版本。

  如果你發(fā)現無(wú)法編譯過(guò)去,有可能是你選用的軟件中有的加入了一些新的特性而其他所選軟件不支持的原因,就相應降低該軟件的版本號。例如我開(kāi)始用 gcc-3.3.2,發(fā)現編譯不過(guò),報 as、ld 等版本太老,我就把 gcc 降為 2.95.3。太新的版本大多沒(méi)經(jīng)過(guò)大量的測試,建議不要選用。

 

2. 建立工作目錄

  首先,我們建立幾個(gè)用來(lái)工作的目錄:

  在你的用戶(hù)目錄,我用的是用戶(hù)liang,因此用戶(hù)目錄為 /home/liang,先建立一個(gè)項目目錄embedded。

 

$pwd    
/home/liang
$mkdir embedded
 


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

  build-tools-用來(lái)存放你下載的 binutils、gcc 和 glibc 的源代碼和用來(lái)編譯這些源代碼的目錄。

  kernel-用來(lái)存放你的內核源代碼和內核補丁。

  tools-用來(lái)存放編譯好的交叉編譯工具和庫文件。

 

$cd embedded
$mkdir  build-tools kernel tools
 


執行完后目錄結構如下:

 

$ls embedded
build-tools kernel tools
 


3. 輸出和環(huán)境變量

  我們輸出如下的環(huán)境變量方便我們編譯。

 

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


  如果你不慣用環(huán)境變量的,你可以直接用絕對或相對路徑。我如果不用環(huán)境變量,一般都用絕對路徑,相對路徑有時(shí)會(huì )失敗。環(huán)境變量也可以定義在.bashrc文件中,這樣當你logout或換了控制臺時(shí),就不用老是export這些變量了。

  體系結構和你的TAEGET變量的對應如下表


  你可以在通過(guò)glibc下的config.sub腳本來(lái)知道,你的TARGET變量是否被支持,例如:

 

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


  在我的環(huán)境中,config.sub 在 glibc-2.2.3/scripts 目錄下。

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

4. 建立編譯目錄

  為了把源碼和編譯時(shí)生成的文件分開(kāi),一般的編譯工作不在的源碼目錄中,要另建一個(gè)目錄來(lái)專(zhuān)門(mén)用于編譯。用以下的命令來(lái)建立編譯你下載的binutils、gcc和glibc的源代碼的目錄。 {{分頁(yè)}}

 

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


build-binutils-編譯binutils的目錄
build-boot-gcc-編譯gcc 啟動(dòng)部分的目錄
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 目錄

  進(jìn)入你的 kernel 目錄:

 

$cd $PRJROOT /kernel
 


  解開(kāi)內核源代碼

 

$tar -xzvf linux-2.4.21.tar.gz
 


 

$tar -xjvf linux-2.4.21.tar.bz2
 


小于 2.4.19 的內核版本解開(kāi)會(huì )生成一個(gè) linux 目錄,沒(méi)帶版本號,就將其改名。

 

$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 來(lái)代替 menuconfig,但這樣用可能會(huì )沒(méi)有設置某些配置文件選項和沒(méi)有生成下面編譯所需的頭文件。推薦大家用 make menuconfig,這也是內核開(kāi)發(fā)人員用的最多的配置方法。配置完退出并保存,檢查一下的內核目錄中的 include/linux/version.h 和 include/linux/autoconf.h 文件是不是生成了,這是編譯 glibc 是要用到的,version.h 和 autoconf.h 文件的存在,也說(shuō)明了你生成了正確的頭文件。

還要建立幾個(gè)正確的鏈接

 

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


接下來(lái)為你的交叉編譯環(huán)境建立你的內核頭文件的鏈接

 

$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 內核頭文件拷貝過(guò)來(lái)用

 

$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   
 

 

建立二進(jìn)制工具(binutils)

binutils是一些二進(jìn)制工具的集合,其中包含了我們常用到的as和ld。

首先,我們解壓我們下載的binutils源文件。

 

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


然后進(jìn)入build-binutils目錄配置和編譯binutils。

 

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


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

會(huì )出現很多 check,最后產(chǎn)生 Makefile 文件。

有了 Makefile 后,我們來(lái)編譯并安裝 binutils,命令很簡(jiǎn)單。

 

$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
 


我們來(lái)解釋一下上面生成的可執行文件都是用來(lái)干什么的

add2line - 將你要找的地址轉成文件和行號,它要使用 debug 信息。

Ar-產(chǎn)生、修改和解開(kāi)一個(gè)存檔文件

As-gnu 的匯編器

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

Gasp-gnu 匯編器預編譯器。

Ld-gnu 的連接器

Nm-列出目標文件的符號和對應的地址

Objcopy-將某種格式的目標文件轉化成另外格式的目標文件

Objdump-顯示目標文件的信息

Ranlib-為一個(gè)存檔文件產(chǎn)生一個(gè)索引,并將這個(gè)索引存入存檔文件中

Readelf-顯示 elf 格式的目標文件的信息

Size-顯示目標文件各個(gè)節的大小和目標文件的大小

Strings-打印出目標文件中可以打印的字符串,有個(gè)默認的長(cháng)度,為4

Strip-剝掉目標文件的所有的符號信息

 


建立初始編譯器(bootstrap gcc)

首先進(jìn)入 build-tools 目錄,將下載 gcc 源代碼解壓

 

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


然后進(jìn)入 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 {{分頁(yè)}}
 


在我們編譯并安裝 gcc 前,我們先要改一個(gè)文件 $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

你如果沒(méi)定義 -Dinhibit,編譯時(shí)將會(huì )報如下的錯誤

 

../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
../../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
 


如果沒(méi)有定義 -D__gthr_posix_h,編譯時(shí)會(huì )報如下的錯誤

 

In file included from gthr-default.h:1,
                 from ../../gcc-2.95.3/gcc/gthr.h:98,
                 from ../../gcc-2.95.3/gcc/libgcc2.c:3034:
../../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時(shí)多加一個(gè)參數-with-newlib,這個(gè)選項不會(huì )迫使我們必須使用newlib。我們編譯了bootstrap-gcc后,仍然可以選擇任何c庫。

接著(zhù)就是配置boostrap gcc, 后面要用bootstrap gcc 來(lái)編譯 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 語(yǔ)言。--disable-threads 是去掉 thread 功能,這個(gè)功能需要 glibc 的支持。

接著(zhù)我們編譯并安裝 boot-gcc

 

$make all-gcc
$make install-gcc
 


我們來(lái)看看 $PREFIX/bin 里面多了哪些東西

 

$ls $PREFIX/bin
 


你會(huì )發(fā)現多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 幾個(gè)文件。

Gcc-gnu 的 C 語(yǔ)言編譯器

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

Cpp-gnu的 C 的預編譯器

Gcov-gcc 的輔助測試工具,可以用它來(lái)分析和優(yōu)程序。

使用 gcc3.2 以及 gcc3.2 以上版本時(shí),配置 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
 


然后進(jìn)入 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,用它來(lái)編譯你的glibc。--enable-add-ons是告訴glibc用 linuxthreads 包,在上面我們已經(jīng)將它放入了 glibc 源碼目錄中,這個(gè)選項等價(jià)于 -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 就會(huì )在 libc.so 所在的目錄查找它需要的庫,因為你的機子的/lib目錄可能已經(jīng)裝了一個(gè)相同名字的庫,一個(gè)為編譯可以在你的宿主機上運行的程序的庫,而不是用于交叉編譯的。

 


建立全套編譯器(full gcc)

在建立boot-gcc 的時(shí)候,我們只支持了C。到這里,我們就要建立全套編譯器,來(lái)支持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++ 語(yǔ)言。

然后編譯和安裝你的 full gcc

 

$make all
$make install
 


我們再來(lái)看看 $PREFIX/bin 里面多了哪些東西

 

$ls $PREFIX/bin
 


你會(huì )發(fā)現多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 幾個(gè)文件。

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

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

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

到這里你的交叉編譯工具就算做完了,簡(jiǎn)單驗證一下你的交叉編譯工具。

用它來(lái)編譯一個(gè)很簡(jiǎn)單的程序 helloworld.c

 

#include <stdio.h>
int main(void)
{
    printf("hello worldn");
    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
 


  上面的輸出說(shuō)明你編譯了一個(gè)能在 arm 體系結構下運行的 helloworld,證明你的編譯工具做成功了。

 

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>