嵌入式Linux系统移植-使用crosstool创建自己的交叉编译器

时间:2021-05-22 16:28:41

 

l     前言

在嵌入式系统移植的过程中,必不可少的一样东西是交叉编译器,只有使用交叉编译器才可以把原先在宿主机(相信大多数人所使用的宿主机会是Linuxx86系统的)上所编写的程序交叉编译成开发板(如ARM系统或PPC系统)所识别的二进制形式。对于一些成熟的移植过程来说,互联网上存在已经制作好的交叉编译器,只要下载过来解压缩配置后就可以使用了。但在使用这些交叉编译器的过程中可能存在着一些问题,由于自己机子上的某些环境不一样,会导致使用这些交叉编译器编译出来的内核,bootloader存在这样或那样的问题。为了去除交叉编译器对今后的编译工作带来的错误影响,最好创建属于自己的交叉编译器。

l     配置

手动创建交叉编译器相当复杂,对于一般的嵌入式程序开发员来说,这部分知识并不是必须的。幸好我们有Dan Kegel所写的创建交叉编译器的脚本工具crosstool。从crosstool官方网站上下载crosstool的最新版本(0.43之后就再没更新过),解压缩后得到crosstool-0.43目录,查看crosstool-0.43文件夹,可以看到目录下有很多demo-*.sh脚本和*.dat配置文件。首先需要找到你要交叉编译的平台CPU所对应的demo-*.sh脚本,比如说我要交叉编译的平台是三星的S3C2440,它的CPUARM9T,则选用demo-arm9tdmi.sh

如下是对该文件的说明,标红色部分表示可根据需要进行修改,这里我们保持文件默认:

#!/bin/sh
# This script has one line for each known working toolchain
# for this architecture. Uncomment the one you want.
# Generated by generate-demo.pl from buildlogs/all.dats.txt

set -ex
TARBALLS_DIR=$HOME/downloads

RESULT_TOP=/opt/crosstool
export TARBALLS_DIR RESULT_TOP
GCC_LANGUAGES=”c,c++”
export GCC_LANGUAGES

# Really, you should do the mkdir before running this,
# and chown /opt/crosstool to yourself so you don’t need to run as root.
mkdir -p $RESULT_TOP

#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.2.5.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.3.2.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.3.2-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.2.5.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.3.2.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.3.2-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.2.5.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.2.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.2-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.5.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.5-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.6.dat` sh all.sh –notest
eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.6-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.2.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.2-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.5.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.5-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.6.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.6-tls.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.1.0-glibc-2.3.2.dat` sh all.sh –notest
#eval `cat arm9tdmi.dat gcc-4.1.0-glibc-2.3.2-tls.dat` sh all.sh –notest

echo Done.

TARBALLS_DIR是指创建crosstool过程中所需要的glibc, binutils, gcc等程序的tar.bz2文件所要存放的位置,这里我把他们放在我的下载目录。Crosstool会自动的从网上下载所需的程序,但由于crosstool在下载的过程中选择的服务器会是国外的官方服务器,会比较慢,最好在build过程之前从网上把这些所需要的文件下载过来放到TARBALLS_DIR中,具体所需要的文件会在下面做介绍。

RESULT_TOP指的是编译好后所生成的交叉编译器存放的目录,一定要改到有写权限的目录,不然无法编译。

eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.6-tls.dat` sh all.sh –notest

表示使用cross-tools顶层目录下的arm9tdmi.dat(根据CPU类型选择)和gcc-3.4.5-glibc-2.3.6-tls.dat(根据想要使用的gcc版本和glibc版本进行选择)来进行交叉编译器的创建。在crosstool官方网站的buildlog页面上可以看到各种CPUGCC+Glibc版本那些已经编译成功,那些部分成功,那些彻底失败。

如果需要更改,在修改好demo-*.sh脚本后,打开所选定的arm9tdmi.dat gcc-3.4.5-glibc-2.3.6-tls.dat文件

首先,打开arm9tdmi.dat

KERNELCONFIG=`pwd`/arm.config
TARGET=arm-9tdmi-linux-gnu
GCC_EXTRA_CONFIG=”–with-cpu=arm9tdmi –enable-cxx-flags=-mcpu=arm9tdmi”
TARGET_CFLAGS=”-O”

TARGET表示最后生成的交叉编译工具链的名称,根据自己喜欢修改。

其次打开gcc-3.4.5-glibc-2.3.6-tls.dat

BINUTILS_DIR=binutils-2.15
GCC_DIR=gcc-3.4.5
GLIBC_DIR=glibc-2.3.6
LINUX_DIR=linux-2.6.23.8
LINUX_SANITIZED_HEADER_DIR=linux-libc-headers-2.6.12.0
GLIBCTHREADS_FILENAME=glibc-linuxthreads-2.3.6

将这里的LINUX_DIR改成你真正想要移植的Linux版本,然后这里的binutils-2.15, gcc-3.4.5, glibc-2.3.6, linux-2.6.23.8, linux-libc-headers-2.6.12.0, glibc-linuxthreads-2.3.6就是你所要下载后放到之前提到的TARBALLS_DIR里的文件(必须是tar.bz2文件)

l     步骤

root登陆Ubuntu系统,创建目录/opt/crosstool/(demo-*.sh脚本里面的变量RESULT_TOP不同而不同)并修改其owner。这是是因为此crosstool不能以root安装,而须以username安装,安装过程会读写此目录,故需要修改属主。

以用户username登陆,创建TARBALLS_DIR指定的目录,在这是系统默认的下载路径/home/username/downloads,本身已存在,不需要自己创建,但如果TARBALLS_DIR被修改过了,则要创建这个修改后的目录,这个目录将来用于自动从网上下载gcc, binutiltyglibc等。如果自己已经下载了这些软件包,也放在这个目录下,这样就不用程序自动从网上下载了。

http://kegel.com/crosstool/下载crosstool-0.43.tar.gz到目录/opt/crosstool,,执行如下命令

cd /opt/crosstool

tar xzvf crosstool-0.43.tar.gz

进入crosstool-0.43目录执行shdemo-arm9tdmi.sh开始创建交叉编译工具,大概要经历12个小时

l     问题与解决方案

置好crosstool后,运行脚本有可能得到如下错误

问题1:

. ……………….
……………….
applying patch /opt/crosstool-0.43/patches/glibc-2.3.6/arm-ctl_bus_isa.patch
getandpatch.sh: 1: patch: not found
patch /opt/crosstool-0.43/patches/glibc-2.3.6/arm-ctl_bus_isa.patch failed

解决办法:通过sudo apt-get install patch 安装patch解决这一问题

问题2:

…………………………

…………………………

/home/rookiesean/workspace/crosstool-0.43/crosstool.sh: 110: bison: not found

crosstool: You don’t have bison installed

解决办法:通过sudo apt-get install bison 安装bison解决这一问题

问题3:

…………………………
…………………………
/home/rookiesean/workspace/crosstool-0.43/crosstool.sh: 111: flex: not found
crosstool: You don’t have flex installed

解决办法:通过sudo apt-get install flex 安装flex解决这一问题

问题4:

…………………………
…………………………

configure: error:

*** These critical programs are missing or too old: as ld

*** Check the INSTALL file for required versions.

出现这种情况是因为Ubuntu默认所安装的binutils版本为binutils-2.20binutils太新的时候,crosstool只好将它当成太老的版本,报告说too old; as ld. 于是我们需要重新编译安装一个老版本的binutils 2.19或者2.18都可以被crosstool所识别,这里拿binutils-2.18举例。但还有一个问题,Ubuntu10.04默认安装的gcc版本是gcc-4.4.3,跟binutils-2.20一样,太高版本的gcc对语法要求更为严格,这样会导致binutils-2.18无法轻松的编译通过,于是我们需要编译安装一个老版本的gcc4.1的版本可以编译成功binutils-2.18。在Ubuntu10.04可以通过

解决方案:

执行sudo apt-get install gcc-4.1安装gcc-4.1,安装完成后,执行如下命令:

cd  /usr/bin

sudo rm gcc

sudo ln -sf gcc-4.1 gcc

gcc -v

得到如下显示:

Using built-in specs.

Target: i486-linux-gnu

Configured with: ../src/configure -v –enable-languages=c,c++ –prefix=/usr –enable-shared –with-system-zlib –libexecdir=/usr/lib –without-included-gettext –enable-threads=posix –enable-nls –with-gxx-include-dir=/usr/include/c++/4.1.3 –program-suffix=-4.1 –enable-__cxa_atexit –enable-clocale=gnu –enable-libstdcxx-debug –with-tune=generic –enable-checking=release i486-linux-gnu

Thread model: posix

gcc version 4.1.3 20080704 (prerelease) (Ubuntu 4.1.2-27ubuntu1)

表明原先指向gcc-4.4的的符号链接已经被重新指向新安装的gcc-4.1,系统中默认的gcc版本为4.1

 

下载binutils-2.18,将其解压缩后,进入binutils顶层目录,运行

./configure -prefix=/home/rookiesean/temp/binutils -disable-nls
make all
make install

其中–prefix=/home/rookiesean/temp/binutils表示生成可执行文件的存放位置,可自定义。

编译成功后在/home/rookiesean/temp/binutils/bin/中就生成了ld as程序的可执行文件,/usr/bin目录下面将系统默认的ldas替换成2.18版本的:

#进入/usr/bin目录

cd /usr/bin/

#备份as ld为后面恢复使用

sudo cp as as.bak

sudo cp ld ld.bak

#删除原来版本的as ld

sudo rm as ld

#替换2.18版本
ln -sf /opt/crosstool/binutils/bin/ld  ld
ln -sf /opt/crosstool /binutils/bin/as as
ld -v; as -v

得到如下显示:

GNU ld (GNU Binutils) 2.18
GNU assembler version 2.18 (i686-pc-linux-gnu) using BFD version (GNU Binutils) 2.18

表示系统默认的binutils版本已经变换为2.18版本。

接下来,就可以运行demo-*.sh建立属于自己的交叉编译器了。

问题5:

version.c:40: error: syntax error before string constant

make[2]: *** [/opt/crosstool/crosstool-0.43/build/arm-softfloat-linux-gnu/gcc-3.4.5-glibc-2.3.6/build-glibc/csu/version.o] Error 1

make[2]: Leaving directory `/opt/crosstool/crosstool-0.43/build/arm-softfloat-linux-gnu/gcc-3.4.5-glibc-2.3.6/glibc-2.3.6/csu'

make[1]: *** [csu/subdir_lib] Error 2

make[1]: Leaving directory `/opt/crosstool/crosstool-0.43/build/arm-softfloat-linux-gnu/gcc-3.4.5-glibc-2.3.6/glibc-2.3.6'

make: *** [lib] Error 2

解决办法:老版本的glibc/bin/shdash的时候会出现这个问题,一种解决方法是把/bin/sh重定向为bash,在创建完交叉编译器后可以将/bin/sh重新改回dash,运行如下面命令修改/bin/sh:

cd /bin
sudo mv /bin/sh sh.old
sudo ln -sf bash /bin/sh
sh –version

得到如下显示:

GNU bash, version 4.1.5(1)-release (i486-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
 重新运行demo-*.sh建立属于自己的交叉编译器了。

l       恢复修改的系统设置

1.     恢复gcc4.4

Sudo rm /usr/bin/gcc

Sudo ln –s /usr/bin/gcc-4.4 /usr/bin/gcc

2.     恢复sh

Cd /bin

Sudo rm sh

Sudo mv sh.old sh

3.     恢复as ld

Cd /usr/bin

Sudo rm ld

Sudo mv ld.bak ld

Sudo rm as

Sudo mv as.bak as

http://blog.csdn.net/mr_raptor

http://blog.csdn.net/fudan_abc