分类:
2008-03-07 15:00:48
在为目标板开发及定制软件的过程中, 最好将项目要用到的代码, 文档, 及生成的目标文件按一定的组织放在统一的, 结构化的目录中. 这里采用《构建嵌入式Linux系统》中推荐的项目目录安排:
目录 | 内容 |
bootldr |
目标板的引导加载程序 |
build-tools |
建立跨平台开发工具链所需要用到的包和目录 |
debug | 调试工具及相关包 |
doc |
项目相关的文档 |
images |
使用在目标板上的引导加载程序和内核的二进制映像, 以及根文件系统 |
kernel | 将在目标板上进行评估的各个内核版本 |
rootfs |
目标板的内核在运行时看到的根文件系统 |
sysapps |
目标板需要用到的系统应用程序 |
tmp |
进行实验时或临时文件会用到此目录 |
tools |
放置跨平台开发工具链以及C链接库 |
上表列出的是一个完备的目录结构, 使用于一个实际的项目. 本文关注的是建立跨平台工具链, 它使用下面的目录:
build-tools, tools, kernel
其中, 在build-tools建立下列目录:
$ mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patch
#!/bin/bash export PRJROOT=/home/zp/project/EmbeddedLinux export TARGET=arm-linux export PREFIX=${PRJROOT}/tools export TARGET_PREFIX=${PREFIX}/${TARGET} export PATH=${PREFIX}/bin:${PATH} cd PRJROOT |
注意运行脚本的方式: 一般是有两种方法source file.sh或./file.sh. 如果直接调用脚本名,
当前shell会生成一个子shell去执行脚本, 子shell在脚本运行完后退出. 不会对当前shell产生影响.
也就是说当前设置的环境变量只对子shell起作用. 所以不用这种方法运行. 而使用source.
source命令使得脚本在当前shell的上下文中被执行. |
本工具链的各组件的版本为: gcc : 2.95.3 binutils : 2.10.1 glibc : 2.2.3 + libc-linuxthreads-2.2.3 kernel : 2.4.21 + patch-2.4.21-rmk2 |
kernel目录,
下载内核源码,以及
patch-2.4.21-rmk2是针对ARM的补丁, 关于它的介绍可以参考
这里使用的2.4.21版的内核, 如果使用2.4.18版之前(含2.4.18)的内核, 解压之后建立的目录名为linux, 不带版本号.
如果使用多个版本的内核, 最好把它linux目录改名,添加版本号. 否则如果解压另一版本(低于2.4.19)的内核, 会覆盖linux目录.
2.4.19版之后的目录名会加上版本号.
解压内核, 并打补丁:
$ cd linux-2.4.21
$ patch -p1 < ../patch-2.4.21-rmk2
在内核源码数根目录配置内核:
$ make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
ARCH=arm指定目标系统的体系结构,这里是针对ARM,如果你不指定 ARCH=arm,那么会针对你的本地系统(X86)配置内核.
由于你没有建立交叉编译器, 你无法编译内核. 在这里只是对内核进行基本的配置: 在这里只需选定 目标系统的处理器类型. |
推荐用menuconfig进行配置, 关于配置内核的工具, 参考本blog这篇文章的前半部分.
配置结束, 退出menuconfig时, 它提示你运行 make dep, 其实不需要运行它. 因为此处只是简单的配置, 不编译内核. |
配置完退出并保存, 检查一下的内核目录中的 include/linux/version.h 和 include/linux/autoconf.h 文件是不是生成了, 这是编译 glibc 是要用到的, version.h 和 autoconf.h 文件的存在,也说明了你生成了正确的头文件.
设置内核头文件
此后编译完整的gcc过程中需要用到内核头文件. 编译过程中系统默认在sys-linux目录中搜索头文件.
我们可以在配置gcc编译时增加 --with-headers选项来设定包含头文件目录, 但这会使得头文件被拷贝到sys-linux目录中.
比较好的方法是创建符号连接以避免拷贝冗余文件:
1, 将内核源码术的asm-arm目录和linux目录拷贝到$TARGET_PREFIX/include目录:
$ cd $PRJROOT/kernel/linux-2.4.21
$ cp -dR include/asm-arm $TARGET_PREFIX/include/asm
$ cp -dR include/linux $TARGET_PREFIX/include/linux
2, 在内核源码数建立下列符号连接:
$ cd include
$ ln -s asm-arm asm
$ cd asm
$ ln -s arch-epxa arch
$ ln -s proc-armv proc
3, 在$TARGET_PREFIX/目录中建立下面的符号连接:
$ cd $TARGET_PREFIX
$ ln -s include sys-linux
$ cd
$TARGET_PREFIX/include/asm
$ ln -s arch-epxa arch
$ ln -s proc-armv proc
(二)设置binutils
此步骤不需要设置内核头文件!
进入build-tools目录, 下载
(1)进入build-binutils目录配置和编译binutils
$../binutils-2.10.1/configure --target=$TARGET --prefix=$PREFIX
--target 选项是指出我们生成的是 arm-linux 的工具,--prefix 是指出我们可执行文件安装的位置。
注意: 配置binutils需要用到flex, 若没有安装flex, 配置过程中会提示:
../../binutils-2.10.1/binutils/configure: line 1945: flex: command not found
checking for flex... lex
checking for yywrap in -ll... no
checking lex output file root... ../../binutils-2.10.1/binutils/configure: line 2033: lex: command not found
configure: error: cannot find output from lex; giving up
需要安装flex, 在Debian/Ubuntu中,直接运行:
$ sudo apt-get install flex
下面是从源代码安装的方法:
------------------------------------------------------------------------------
先安装lex,到GNU网站:下载的源码安装。
在编译flex的过程中,make又提示错误:
make: yacc: Command not found
make: *** [parse.c] Error 127
需要yacc,于是下载Berkeley的源码。
so,安装binutils时,若需要flex, yacc,执行下列步骤
1,获得yacc, flex源码
2,安装yacc: ./configure --> make --> make install
3,安装flex: ./confugre --> make --> make install
完成后,再继续安装binutils:
1,./configure --target=..., --prefix=...
2,make
3,make install
------------------------------------------------------------------------------
(2) 前面的配置产生Makefile之后, 只需运行:
$ make
$ make install
OK, 前面已经安装好了binutils, 下面我们看看安装了哪些程序:
$ ls $PREFIX/bin
arm-linux-addr2line
arm-linux-c++filt
arm-linux-nm
arm-linux-ranlib arm-linux-strings
arm-linux-ar
arm-linux-gasp arm-linux-objcopy
arm-linux-readelf arm-linux-strip
arm-linux-as
arm-linux-ld
arm-linux-objdump arm-linux-size
(三)设置初始编译器(boot-gcc)
此步骤不需要设置内核头文件!
进入build-tools目录, 下载
并到网站下载这三个补丁:
解压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-1.patch
$patch -p1< ../gcc-patch/gcc-2.95.3-returntype_fix-1.patch
echo timestamp > gcc/cstamp-h.in
如果你用的是Ubuntu默认的gcc(既安装build-essential中的gcc, 该gcc的版本目前是4.0.2). 在编译时候会提示"invalid lvalue in increment"错误. 最好使用gcc-3.3. Ubuntu中安装gcc-3.3: $ sudo apt-get install gcc-3.3 只有调用不同版本的gcc, 只需: $ export CC=gcc-3.3 |
实际上, 应该这样修改t-linux: 在TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC语句之前添加"T_CFLAGS = -Dinhibit_libc -D__gthr_posix_h" 成为: T_CFLAGS = -Dinhibit_libc -D__gthr_posix_h TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC |
../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
可能是去掉posix thread支持吧.如果用的比较老版本gcc (比如gcc-2.95.3) 在配置过程中会提示这样的错误: Config.guess failed to determine the host type. You need to specify one. 这是由于config.guess, config.sub版本太老. config.guess是用来检测host类型的, 运行它就能得知host类型. 解决方法: 到ftp://ftp.gnu.org/pub/pub/gnu/config/下载新版的config.guess和config.sub: *checkout*/config/config/config.guess |
注意:为什么不用 all-in-one 的 gcc-$VGCC.tar.gz 呢?
all-in-one 的 gcc 包里面有 chill, fortran, java 等语言的编译器,虽然在下面 configure 时指定 -enable-languages=c,但编译时还是把所有的都编译一便,这不是我们需要的,而且它也总会有错误。因此我们只编译 C 语言的编译器。后面第二次编译的时候也是这个问题,我们只编译 C 和 C++ 的编译器。 |
解压glibc, 并打补丁
$ 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
配置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
$ make
$ make install_root=$TARGET_PREFIX prefix="" install
install_root 指定了安装链接库组件的目录, 将glibc安装到与我们项目相关的目录, 而非/usr目录.由于嵌入式系统存储功能的限制, 使用glibc生成的可执行文件比较大, 可以使用uClibc. 文末介绍了使用uClibc. |
$ ../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++
$ make install
如果你想将所有的应用程序静态连接, 那么你可以关闭动态库支持. 但如果以后要用动态库时, 又得重新编译uClibc了(glibc也是如此). 最好选上对动态库的支持. 你可以在gcc选项中加上-static来使用静态库. |