Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1210422
  • 博文数量: 322
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 3276
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-17 09:21
文章分类

全部博文(322)

文章存档

2010年(155)

2009年(167)

我的朋友

分类: 嵌入式

2010-01-20 22:14:54

交叉编译环境介绍

交叉编译是嵌入式开发过程中的一项重要技术,它的主要特征是某机器中执行的程序代码不是在本机编译生成,而是由另一台机器编译生成,一般把前者称为目标机,后者称为主机。采用交叉编译的主要原因在于,多数嵌入式目标系统不能提供足够的资源供编译过程使用,因而只好将编译工程转移到高性能的主机中进行。

linux下的交叉编译环境重要包括以下几个部分:

针对目标系统的编译器gcc

针对目标系统的二进制工具binutils

目标系统的标准c库glibc

目标系统的linux内核头文件

交叉编译环境的建立步骤

下载源代码

下载包括binutils、gcc、glibc及linux内核的源代码(需要注意的是,glibc和内核源代码的版本必须与目标机上实际使用的版本保持一致),并设定shell变量PREFIX指定可执行程序的安装路径。

编译binutils

首先运行configure文件,并使用--prefix=$PREFIX参数指定安装路径,使用--target=arm-linux参数指定目标机类型,然后执行make install。

配置linux内核头文件

首先执行make mrproper进行清理工作,然后执行make config ARCH=arm(或make menuconfig/xconfig ARCH=arm)进行配置(注意,一定要在命令行中使用ARCH=arm指定cpu架构,因为缺省架构为主机的cpu架构),这一步需要根据目标机的实际情况进行详细的配置,笔者进行的实验中目标机为HP的ipaq-hp3630 PDA,因而设置system type为SA11X0,SA11X0 Implementations中选择Compaq iPAQ H3600/H3700。

配置完成之后,需要将内核头文件拷贝到安装目录: cp -dR include/asm-arm $PREFIX/arm-linux/include/asm cp -dR include/linux $PREFIX/arm-linux/include/linux

第一次编译gcc

首先运行configure文件,使用--prefix=$PREFIX参数指定安装路径,使用--target=arm-linux参数指定目标机类型,并使用--disable-threads、--disable-shared、--enable-languages=c参数,然后执行make install。这一步将生成一个最简的gcc。由于编译整个gcc是需要目标机的glibc库的,它现在还不存在,因此需要首先生成一个最简的gcc,它只需要具备编译目标机glibc库的能力即可。

交叉编译glibc

这一步骤生成的代码是针对目标机cpu的,因此它属于一个交叉编译过程。该过程要用到linux内核头文件,默认路径为$PREFIX/arm-linux/sys-linux,因而需要在$PREFIX/arm-linux中建立一个名为sys-linux的软连接,使其内核头文件所在的include目录;或者,也可以在接下来要执行的configure命令中使用--with-headers参数指定linux内核头文件的实际路径。

configure的运行参数设置如下(因为是交叉编译,所以要将编译器变量CC设为arm-linux-gcc):

CC=arm-linux-gcc ./configure --prefix=$PREFIX/arm-linux --host=arm-linux --enable-add-ons

最后,按以上配置执行configure和make install,glibc的交叉编译过程就算完成了,这里需要指出的是,glibc的安装路径设置为$PREFIXARCH=arm/arm-linux,如果此处设置不当,第二次编译gcc时可能找不到glibc的头文件和库。

第二次编译gcc

运行configure,参数设置为--prefix=$PREFIX --target=arm-linux --enable-languages=c,c++。

运行make install。

到此为止整个交叉编译环境就完全生成了。

几点注意事项

第一点、在第一次编译gcc的时候可能会出现找不到stdio.h的错误,解决办法是修改gcc/config/arm/t-linux文件,在TARGET_LIBGCC2_CFLAGS变量的设定中增加-Dinhibit_libc和-D__gthr_posix_h。

第二点、对与2.3.2版本的glibc库,编译linuxthread/sysdeps/pthread/sigaction.c时可能出错,需要通过补丁glibc-2.3.2-arm.patch解决:执行patch -p1 < glibc-2.3.2-arm.patch

第三点、第二次编译gcc时可能会出现libc.so的错误,这是需要利用文本编辑器手动修改libc.so。

 

 ## 本文以在i386平台建立arm工具链为例说明。

    交叉编译工具的建立过程比较繁琐,主要参考资料为《构建嵌入式Linux系统》一书第四章内容。以下主要罗列一些需要注意的问题。

1. 工具链主要包括binutils, gcc, glibc三个组件,由于各个组件的开发和发布彼此独立,所以并非用各组件的任意版本都能顺利完成建立工作。经过屡次尝试,我最终使用了如下版本:

    binutils:         2.16.1
    gcc:               3.4.6
    glibc:             2.3.6   
    linux-kernel:  2.6.16
    主机原生gcc:   3.3.5

2. 四个阶段:

    (1)编译binutils
    (2)生成引导编译器(即生成arm-linux-gcc)
    (3)编译glibc
    (4)生成完整编译器(arm-linux-gcc,arm-linux-g++)

3. 使用3.x系列gcc编译2.x系列glibc时,会产生一个compile internal error,所以必须在上述第(2)阶段修改一个文件.../gcc-3.x.x/gcc/flow.c,点这里下载patch文件。

4. 生成引导编译器阶段,在configure时,除了书中提到的参数,还应该加上--disable-threads和   --disable-shared,因为该功能需要glibc支持,而此时glibc尚未生成。我使用的完整命令如下:

    .../gcc-3.x.x/configure --target=arm-linu --prefix=/opt/tools        --without-headers  --with-newlib --disable-threads --disable-shared --enable-languages=c

5. 编译glibc时有两个错误非常常见:

    (1)error: `BUS_ISA' undeclared
   
    原因:linux-kernel 2.4.23以上版本使用CTL_BUS_ISA替代BUS_ISA
    修正:将glibc-2.x.x/sysdeps/unix/sysv/linux/arm/ioperm.c中的BUS_ISA替换为CTL_BUS_ISA,大概有两处。

    (2)ld: cannot find -lgcc_eh
   
    修正:修改glibc-2.x.x/Makeconfig
    将gnulib := -lgcc $(libgcc_eh)
       static-gnulib := -lgcc -lgcc_eh $(libunwind)
    替换为
       gnulib := -lgccs
       tatic-gnulib := -lgcc

    经过如上步骤,即可顺利完成建立工作。如果遇到其他错误,google之,很可能你的问题别人也遇到过并已经解决,注意要搜索所有网页,不要仅搜索简体中文。
(e129)

 

linux-arm交叉编译工具链的构建过程

嵌入式linux-arm交叉编译工具链的构建

很高兴再次来到这里,开始写自己的文档,由于自己经验欠缺和水平有限,希望读不懂的朋友多多包涵,或者发送邮件联系!!在师兄的帮助下,我构建了自己的基于linux-arm交叉编译工具链,并用一个简单的应用程序进行了测试,初始证明比较好用。现在网上的交叉编译工具链的建立过程,都是以一个比较老的版本作为例子来进行讲解,一步一步给出编译过程。http://blog.csdn.net/bekars/archive/2006/02.aspx,已经不能适应新版本的编译器的需要,和新版的安装过程有较大的区别。为了使广大的初学者少走弯路,并且练习一下自己的动手能力,我撰写了自己的文档,希望能给您带来一点点帮助!在这里我是借鉴别人写的脚本,用脚本实现的自己的安装过程:第一步:首先下载如下源文件binutils-2.16.  tar.gz,gcc-3.4.4.tar.bz2, t-linux.diff, glibc-2.3.5.tar.gz, glibc-linuxthreads-2.3.5.tar.gz,  ioperm.c.diff,  linux-2.6.11.12tar.gz  并且把所有的源文件放入/home/zmj/usr/arm/src文件夹中,其中zmj是用户名。并把如下脚本,写入一个文件,例如文件名为buildchain.sh,并把该文件放入usr目录下。第二步: 运行buildchain.sh脚本即可。其中第七步是不需要的,将来自己编译内核的时候还要重新配置,故可以删去。
 
#!/bin/bash
 # Setup 
PREFIX=/home/zmj/usr/arm
TARGET=arm-unknown-linux-gnu
SYSROOT=${PREFIX}/sysrootexport
ARCH=armexport
CROSS_COMPILE=${TARGET}-
export PATH=$PATH:${PREFIX}/binmkdir -p ${PREFIX}/src 
 
## Get the sources
#
#cd ${PREFIX}/src
#tar xvfz binutils-2.16.tar.gz
#mkdir -p BUILD/binutils-2.16#cd BUILD/binutils-2.16
# ../../binutils-2.16/configure --prefix=${PREFIX} --target=${TARGET} --with-sysroot=${SYSROOT} 2>&1 | tee configure.out#make 2>&1 | tee make.out
#make install 2>&1 | tee -a make.out
#
# Linux Kernel Headers 
#
#cd ${PREFIX}/src
#tar xvfz linux-2.6.11.12.tar.gz
#ln -s linux-2.6.11.12 linux
#cd linux
#make ARCH=arm CROSS_COMPILE=${CROSS_COMPILE} menuconfig
#make include/linux/version.h
#mkdir -p ${SYSROOT}/usr/include
#cp -a ${PREFIX}/src/linux/include/linux ${SYSROOT}/usr/include/linux
#cp -a ${PREFIX}/src/linux/include/asm-arm ${SYSROOT}/usr/include/asm
#cp -a ${PREFIX}/src/linux/include/asm-generic ${SYSROOT}/usr/include/asm-generic
##
## Glibc headers
#
#cd ${PREFIX}/src
##tar xvfz glibc-2.3.5.tar.gz
##patch -d glibc-2.3.5 -p1
#cd glibc-2.3.5
##tar xvfj ../glibc-linuxthreads-2.3.5.tar.gz
#cd ..
#mkdir BUILD/glibc-2.3.5-headers
#cd BUILD/glibc-2.3.5-headers
#../../glibc-2.3.5/configure --prefix=/usr --host=${TARGET} --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include 2>&1 | tee configure.out
#make cross-compiling=yes install_root=${SYSROOT} install-headers 2>&1 | tee make.out
#touch ${SYSROOT}/usr/include/gnu/stubs.h
#touch ${SYSROOT}/usr/include/bits/stdio_lim.h
#
# Step 4: stage 1 gcc
#
#cd ${PREFIX}/src
#bunzip2 -c gcc-3.4.4.tar.bz2 | tar xvf -
#patch -d gcc-3.4.4 -p1 < flow.c.diff
#patch -d gcc-3.4.4 -p1 < t-linux.diff
#mkdir -p BUILD/gcc-3.4.4-stage1
#cd BUILD/gcc-3.4.4-stage1
#../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c --with-sysroot=${SYSROOT} 2>&1 | tee configure.out
#make 2>&1 | tee make.out
#make install 2>&1 | tee -a make.out
#
# Step 5: glibc 
#
#cd ${PREFIX}/src
#mkdir BUILD/glibc-2.3.5
#cd BUILD/glibc-2.3.5
#BUILD_CC=gcc CC=${CROSS_COMPILE}gcc AR=${CROSS_COMPILE}ar RANLIB=${CROSS_COMPILE}ranlib AS=${CROSS_COMPILE}as LD=${CROSS_COMPILE}ld ../../glibc-2.3.5/configure --prefix=/usr --build=i686-pc-linux-gnu  --host=arm-unknown-linux-gnu --target=arm-unknown-linux-gnu --without-__thread --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include 2>&1 | tee configure.out
#
#make 2>&1 | tee make.out
#make install_root=${SYSROOT} install 
#
# Step 6: stage 2 gcc 
#
#cd ${PREFIX}/src
#mkdir BUILD/gcc-3.4.4
#cd BUILD/gcc-3.4.4
#../../gcc-3.4.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --with-sysroot=${SYSROOT} 2>&1 | tee configure.out
#make 2>&1 | tee make.out#make install 2>&1 | tee -a make.out
#cd ../.. 
#
# Step 7: Linux kernel 
#
cd ${PREFIX}/src/linux
make zImage
make modules
make INSTALL_MOD_PATH=${SYSROOT} modules_install 
注意 :文中的大部分#号是自己当初为了分步编译差错方便而屏蔽掉的部分。自己编译的时候可以去掉。顺便说一下我是在suse环境下建立这个交叉编译环境的,内核是2.6以上的版本,其中—build=i686-pc-linux-gnu
几个简单的命令: set nu 显示文本行号。 15s/^/#/g可以在文本的1~5行添加一个#号,也即屏蔽掉这几行。15s/^#//g去掉文本1~5行文本开头的#号。
 
 第三步  测试程序Helloworld.c 
#includestdio.h
int main( )
{ printf(“Hello ,world!n”);
 return 0;}
可以在脚本中/etc/bash.bashrc中写入环境变量,也可以直接写如下:
export PATH=/home/zmj/usr/arm/arm/bin:$PATH 其中bin中存放的是自己交叉编译器的路径。

cd ..helloworld.c的目录。# arm-unknown-linux-gnu-gcc helloworld.c完毕!

 

如有转载敬请说明谢谢!

阅读(1197) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~