自己动手创建交叉工具链
首先,制作交叉工具链的目的是为了给我的手机--MOTO ROKR E2编译程序。然后,顺便学习一下嵌入式软件的开发

先说一下,搞这个需要很大的耐心。
我用的硬件是Sempron3100+, 512MB内存, 编译环境是windowsXP + vmware5.5 + gentoo,
在CUI下,花了大概20个小时才编译完(我从晚上八点一直弄到第二天下午四点

1. 准备源码 :
binuitls-2.17
gcc-4.1.1
glibc-2.5
glibc-ports-2.5
以上都可以在 gnu.org 的 ftp 上下载
默认 glibc 不支持其它处理器 , glibc-ports 是支持其它处理器架构的补丁
另外还有 kernel, 我使用最新的 2.19.1(kernel 用于提供编译头文件 )
2. 准备补丁 :
这个可以在 cross-lfs.org 上面根据它的指南下载 , 我使用了下面的补丁 :
Binutils Branch Update
Binutils Posix Patch
GCC Cross Search Paths Patch
GCC PR20425 Patch
GCC Posix Patch
Glibc Branch Update
Glibc Cross-Compiling Hacks Patch
Glibc Disable linking with libgcc_eh.a
Glibc Localedef Segfault
准备编译环境 , 我直接使用的 debian(sid) 并且所有包都是最新状态 , 另外需要安装 texinfo, gawk( 注意 mawk 编译 glibc header 时会有问题 ), bison, flex
4. 准备环境变量 . 我写了一个 pre.sh, 所有相关内容都放里面
set +h # 关闭 bash 的 hash 功能 ,hash 功能用来记忆系统中所有可执行文件来避免查找 path. 编译时可能会增加新的同名可执行程序在其它目录下
umask 022
export CLFS_HOST="$(echo $MACHTYPE | sed "s/$(echo $MACHTYPE | cut -d- -f2)/cross/")"
export CLFS_TARGET="arm-unknown-linux-gnu"
export CLFS=/home/lizl/arm
export LC_ALL=POSIX # 旧的 libc2.2.4 以下在 LOCALE 为其它时 chroot 回来可能会有异常
export PATH=$CLFS/bin:$PATH
# CFLAGS 和 CXXFLAGS 对编译时可能会有影响
unset CFLAGS
unset CXXFLAGS
5. 准备环境 . 执行 source pre.sh 后执行下面的操作 :
install -dv ${CLFS} # 创建目标目录
install -dv ${CLFS}/include
install -dv ${CLFS}/usr/include
另外最好使用其它用户身份去进行编译的操作 , 因为 root 可能会对系统造成破坏 . 建议创建一个 clfs 用户和组专门操作 ( 我是直接使用的 root):
groupadd clfs # 增加组
useradd -s /bin/bash -g clfs -m -k /dev/null clfs # 创建用户
passwd clfs # 给用户指定口令
chown -Rv clfs ${CLFS} # 修改输出目录的权限
CLFS 建议 clfs 帐号登录时 , 最好不要被系统中其它环境变量影响 , 所以它在 clfs 帐号的 ~/.bash_profile 里面写入下面内容 :
exec env -i HOME=${HOME} TERM=${TERM} PS1='\u:\w\$ ' /bin/bash
因为我是 root, 没有修改 .
su - clfs # 切换到 clfs 用户执行操作
开始创建一些目录 . 这里我没有创建 , 因为我只需要 gcc, binutils 和 glibc 这三个
6. 编译 binutils:
下载 binutils-2.17 并解压 .
下载补丁 :
注意安装 gcc bison flex texinfo
不然编译过程会出错
我编译时报的错是 missing makeinfo
然后安装了 texinfo 还是不行
后面检查 makefile 才发现 bison 等都没有安装
patch -Np1 -i ../patch/binutils-2.17-posix-1.patch
patch -Np1 -i ../patch/binutils-2.17-branch_update-1.patch
binutils 建议编译时在其它目录编译 , 所以我们创建 binutils-build 并在里面执行操作
mkdir -v ../binutils-build
cd ../binutils-build
如果你在 binutils-2.17 执行操作的话 , 那后面的 make configure-host 时可能会报错
我因为报错然后重做了一下干净的解压目录重执行
开始配置
../binutils-2.17/configure --prefix=${CLFS} \
--host=${CLFS_HOST} --target=${CLFS_TARGET} --with-sysroot=${CLFS} \
--disable-nls --enable-shared --disable-multilib
检查看主机上的运行条件是不是符合
make configure-host
编译并安装 :
make
make install
cp -v ../binutils-2.17/include/libiberty.h ${CLFS}/usr/include
7. 安装内核头文件 :
clfs 中是直接复制目录 , 我则是先 make menuconfig 然后修改一此事配置后才复制的
clfs 中操作 :
install -dv ${CLFS}/usr/include
cp -av include/{asm-generic,linux,mtd,scsi,sound} ${CLFS}/usr/include
cp -av include/asm-arm ${CLFS}/usr/include/asm
我的操作 :
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
在 menuconfig 里面 load 一个别人的 2410 的配置然后退出并保存
cp -av include/{asm-generic,linux} ${CLFS}/usr/include
cp -av include/asm-arm ${CLFS}/usr/include/asm
8. 安装 glibc 的头文件 .
先把 3.4 的依赖去掉
cd glibc-2.5
cp configure{,.orig}
sed -e 's/3.4/3.[0-9]/g' configure.orig > configure
然后解压 glibc-ports
tar -jxvf ../glibc-ports-2.5.tar.bz2
mv -v glibc-ports-2.5 ports
注意是解压到当前目录 (glibc-2.5) 下 , 不然执行后面的 configure 时会报 cpu 不支持
然后开始准备编译目录 , 同上 , 我们也在其它目录下进行编译
mkdir -v ../glibc-build
cd ../glibc-build
为打开 NPTL 支持进行如下操作 :
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "libc_cv_arm_tls=yes" >> config.cache
然后把安装路径指定一下 :
echo "install_root=${CLFS}" > configparms
再执行下面的编译 :
CC=gcc ../glibc-2.5/configure --prefix=/usr --host=${CLFS_TARGET} --build=${CLFS_HOST} --with-headers=${CLFS}/usr/include --cache-file=config.cache
make install-headers
由于 awk 语法兼容原因 , 如果安装 mawk 的话上面的步骤会出错 , 安装 gawk 则不会
有一些文件还没有被自动复制过去 , 需要手工复制 :
install -dv ${CLFS}/usr/include/bits
cp -v bits/stdio_lim.h ${CLFS}/usr/include/bits
touch ${CLFS}/usr/include/gnu/stubs.h
cp -v ../glibc-2.5/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h \
${CLFS}/usr/include/bits
9. 安装 gcc 第一次 , 这次是为了编译交叉版本的 glibc 和 gcc, 先打补丁
patch -Np1 -i ../patch/gcc-4.1.1-posix-1.patch
patch -Np1 -i ../patch/gcc-4.1.1-cross_search_paths-1.patch
然后同样创建编译目录并在里面进行编译 :
mkdir -v ../gcc-build
cd ../gcc-build
../gcc-4.1.1/configure --prefix=${CLFS} --host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib --with-sysroot=${CLFS} --disable-nls --disable-shared --enable-languages=c
make all-gcc
make install-gcc
10. 安装 glibc
在前面安装 glibc 的头时已经做了一些事情,如把 port 解压 . 现在做的先是给 glibc 打补丁 :
cd glibc-2.5
patch -Np1 -i ../patch/glibc-2.5-libgcc_eh-2.patch
patch -Np1 -i ../patch/glibc-2.5-localedef_segfault-1.patch
patch -Np1 -i ../patch/glibc-2.5-cross_hacks-2.patch
patch -Np1 -i ../patch/glibc-2.5-branch_update-1.patch
然后创建编译目录并开始编译 :
cd ../glibc-build
rm -rf *
为支持 NPTL 做如下操作 :
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
指明安装目录 :
echo "install_root=${CLFS}" > configparms
开始编译 :
BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc" AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" ../glibc-2.5/configure --prefix=/usr --libexecdir=/usr/lib/glibc --host=${CLFS_TARGET} --build=${CLFS_HOST} --disable-profile --enable-add-ons --with-tls --enable-kernel=2.6.0 --with-__thread --with-binutils=${CLFS}/bin --with-headers=${CLFS}/usr/include --cache-file=config.cache
由于使用的是 2.6.19 的内核 , 内核中使用了新的 netlink 接口 , 把一些宏去掉了
参考 maillist 可知这些定义已经不在内核中使用 , 但是应该还在用户空间使用
CLFS 中对最新内核的支持现在只到 2.6.18.2
所以用 2.6.19 的需要自己修改一下 :
修改目录和文件为 :
glibc-2.5/sysdeps/unix/sysv/linux# grep IFA * -l
check_pf.c
if_index.c
ifaddrs.c
在上面的文件中增加如下内容 :
#include <linux/if_addr.h>
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
然后执行下面操作
make
make install
下面安装 locale, 如果想安装全部 locale 的话可以执行下面的命令 ( 时间比较长 , 可能有半小时 ):
make localedata/install-locales
而如果你不想全装 , 只想装某些 locale 那 clfs 推荐按下面命令执行 :
mkdir -pv ${CLFS}/usr/lib/locale
export I18NPATH=${PWD}/localedata
export GCONV_PATH=${PWD}/iconvdata
export LOCALEDEF="${PWD}/locale/localedef-native --alias-file=../intl/locale.alias"
cd ../glibc-2.5/localedata
${LOCALEDEF} -i locales/de_DE -f charmaps/ISO-8859-1 --prefix=${CLFS} de_DE
${LOCALEDEF} -i locales/de_DE@euro -f charmaps/ISO-8859-15 --prefix=${CLFS} de_DE@euro
${LOCALEDEF} -i locales/en_HK -f charmaps/ISO-8859-1 --prefix=${CLFS} en_HK
${LOCALEDEF} -i locales/en_PH -f charmaps/ISO-8859-1 --prefix=${CLFS} en_PH
${LOCALEDEF} -i locales/en_US -f charmaps/ISO-8859-1 --prefix=${CLFS} en_US
${LOCALEDEF} -i locales/es_MX -f charmaps/ISO-8859-1 --prefix=${CLFS} es_MX
${LOCALEDEF} -i locales/fa_IR -f charmaps/UTF-8 --prefix=${CLFS} fa_IR
${LOCALEDEF} -i locales/fr_FR -f charmaps/ISO-8859-1 --prefix=${CLFS} fr_FR
${LOCALEDEF} -i locales/fr_FR@euro -f charmaps/ISO-8859-15 --prefix=${CLFS} fr_FR@euro
${LOCALEDEF} -i locales/it_IT -f charmaps/ISO-8859-1 --prefix=${CLFS} it_IT
${LOCALEDEF} -i locales/ja_JP -f charmaps/EUC-JP --prefix=${CLFS} ja_JP
unset I18NPATH GCONV_PATH LOCALEDEF
个人认为如果不想全装 , 直接修改一下 localedata/Makefile, 把不需要的 locale 去掉后再执行第一种方法可能更简单 . 这里我执行的是第一种方法 .
11. 配置 glibc 运行信息
如果不配置的话 glibc 也会有默认配置 , 但是在网络环境下可能不正常 . 所以需要配置一下 .
用如下命令创建文件 /etc/nsswitch.conf, 当然直接编辑更快 ( 直接编辑时把后面的 EOF 去掉 ):
cat > ${CLFS}/etc/nsswitch.conf << "EOF"
# Begin /etc/nsswitch.conf
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
ethers: files
rpc: files
# End /etc/nsswitch.conf
EOF
然后用下面命令配置一下时区 :
TZDIR="${CLFS}/usr/share/zoneinfo" ${CLFS}/usr/bin/tzselect
回答一些问题后 , 使用下面命令保存 timezone:
cp -v --remove-destination ${clfs}/usr/share/zoneinfo/[xxx] \
${clfs}/etc/localtime
[xxx] 就是上面的结果 .
我的结果是 :
TZ='Asia/Shanghai'; export TZ
所以命令是 :
cp -v --remove-destination ${clfs}/usr/share/zoneinfo/'Asia/Shanghai' ${clfs}/etc/localtime
12. 配置动态装载器 ( 如果你有库文件放在 /lib 和 /usr/lib 外的其它目录的话 )
动态装载器 (/lib/ld-linux.so.2) 在 /lib 和 /usr/lib 目录下查找程序需要的动态库 .
如果动态库所在目录不上上面两个目录下 , 那需要把它的目录写到 /etc/ld.so.conf 中 .
一般 /usr/local/lib 和 /opt/lib 目录也需要查找 .
如果你有动态库放在这两个目录下的话 , 做如下操作 ( 我没有所以不做 ):
cat > ${CLFS}/etc/ld.so.conf << "EOF"
# Begin /etc/ld.so.conf
/usr/local/lib
/opt/lib
# End /etc/ld.so.conf
EOF
13. 编译 gcc. 前面已经编译过一次 . 前面的编译是为了创建交叉版本的 glibc, 现在则是创建交叉版本的 gcc.
先打补丁
cd gcc-4.1.1
patch -Np1 -i ../patch/gcc-4.1.1-posix-1.patch
patch -Np1 -i ../patch/gcc-4.1.1-PR20425-1.patch
patch -Np1 -i ../patch/gcc-4.1.1-cross_search_paths-1.patch
第一个和每三个前面都已经打过了 , 所以这里只需要再打第二个就可以了
然后创建编译目录 :
mkdir -v ../gcc-build
cd ../gcc-build
../gcc-4.1.1/configure --prefix=${CLFS} \
--host=${CLFS_HOST} --target=${CLFS_TARGET} --disable-multilib \
--with-sysroot=${CLFS} --disable-nls --enable-shared \
--enable-languages=c,c++ --enable-__cxa_atexit \
--enable-c99 --enable-long-long --enable-threads=posix
make
make install
14. 交叉编译工具链已经做好,现在就小试一下牛刀,马上来个Hello World
