前几天自己亲手尝试了制作嵌入式linux开发的toolchain的过程,当然也参考了网上的一些资料,因为我自己也属于新手行列,只是刚好公司有开发板等环境,于是就尝试了这个所谓的嵌入式系统开发的第一步。
在进行嵌入式开发之前,首先要建立一个交叉编译环境,这是一套编译器、连接器和libc库等组成的开发环境。由于一般嵌入式开发系统存储大小有限,通常你都要在你的强大的pc机上建立一个用于目标机的交叉编译环境。这是一个由编译器、连接器和解释器组成的综合开发环境。交叉编译工具主要由 binutils、gcc 和 glibc 几个部分组成。有时出于减小 libc 库大小的考虑,你也可以用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。下面我们将以建立针对arm的交叉编译开发环境为例来解说整个过程,其他的体系结构与这个相类似,只要作一些对应的改动。我的开发环境是,宿主机 Ubuntu 7.04,目标机 arm。
在开始之前想先声明一下,之所以会选择用ubuntu,有两点原因,一是我自己刚好有一个ubuntu的虚拟机是作为自己工作以外学习之用的;二是我知道初始情况下的ubuntu预装的应用软件比较少,这样出错的机会也比较大,于是呢学习到的东西也会比较多了。这点在后面的步骤中体现的比较多。由于前几天在论坛http://forum.ubuntu.org.cn/上看到有人回帖抱怨说ubuntu不好用,很多东西都没有预装的,所以随便搞个软件都得折腾半天。其实我觉得这个事情得两面看,首先确实,对于刚开始使用linux,或者使用了比较长时间但比较停留在表面上的应用,或者使用linux只是为了图个新鲜而想要求linux向windows看齐的用户来说,确实不方便;但是ubuntu的这种方式也有很好的一面,象我这次特意选的是什么其他软件都没装过的一个ubuntu系统来搭建这个交叉编译环境,首先是为了给新手们一个真正可以全面参考了动手搭建的说明,其次由于系统中缺少了一些必要的软件,比如flex,bison等,编译过程中肯定会出现一些在其他系统中不会见到的错误,这样可以让我们了解更多东西。同时个人觉得ubuntu最方便的就是它提供了很方便的安装源,比方说在没安装bison的情况下输入bison,系统就会提示没有安装,并且提示了该如何安装,于是我们只要直接复制安装命令就OK了,多方便多人性化啊,呵呵。
另外我还想事先提供一种解决问题的方法,如果碰到奇怪的问题,也google不到,那可能是有什么必要的软件没装,其实可以查看Makefile文件,里面有很多依赖关系,可以测试以下是否有必要的没有装,有的话装好就OK了。
网上有很多文章都说明了,搭建开发环境的过程大致如下:
下载源文件、补丁和建立编译的目录
1. 选定软件版本号
选择软件版本号时,先看看glibc源代码中的INSTALL文件。那里列举了该版本的glibc编译时所需的binutils 和gcc的版本号。例如在 glibc-2.2.3/INSTALL 文件中推荐 gcc 用 2.95以上,binutils 用 2.10.1 以上版本。
我选的各个软件的版本是:
2. 建立工作目录
首先,我们建立几个用来工作的目录:(可根据自己喜好任意选择建立的目录)
我用的是/workdir/,先建立一个项目目录embedded。
$pwd /workdir $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=/workdir/embedded $export TARGET=arm-linux $export PREFIX=$PRJROOT/tools $export TARGET_PREFIX=$PREFIX/$TARGET $export PATH=$PREFIX/bin:$PATH |
如果你不惯用环境变量的,你可以直接用绝对或相对路径。我如果不用环境变量,一般都用绝对路径,相对路径有时会失败。环境变量也可以定义在.bashrc文件中,这样当你logout或换了控制台时,就不用老是export这些变量了。
你可以在通过glibc(also in ~/gcc-2.95.3/)下的config.sub脚本来知道,你的TARGET变量是否被支持,例如:
$./config.sub arm-linux arm-unknown-linux-gnu |
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/ 下载到这些补丁,当然也可以直接google。
再将你下载的 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 |
接下来把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/asm $cp –r include/asm-generic/ ${TARGET_PREFIX}/include |