全手工制作arm-linux交叉编译工具链《二》

来源:互联网 发布:linux echo用法 编辑:程序博客网 时间:2024/04/27 00:36

全手工制作arm-linux交叉编译工具链《二》

全手工制作arm-linux交叉编译工具链

Gcc 4.2.1 + Glibc 2.6.1 + Linux 2.6.22.6)《二》

作者:Garfield Trump

《四》具体实现:

http://cross-lfs.org/view/clfs-sysroot/arm/index.html

 

在此部分的制作过程主要参考以上网站完成,但其中制作过程有错,在本文中Garfield Trump予以了纠正。读者可以事后参看一下。我会在以下篇幅中指出与该网站的不同之处,并说明错在什么地方。

建议先看本文,此网站的目录结构比较混乱,而且按该网站所述建立工作目录,一定会出错,是在第二阶段 Gcc 制作中出错,原因是找不到头文件。

 

 

 

4.1 下载所需源码包

http://ftp.gnu.org/gnu/binutils/binutils-2.18.tar.bz2

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/binutils-2.18-posix-1.patch

http://ftp.gnu.org/gnu/gcc/gcc-4.2.1/gcc-4.2.1.tar.bz2

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/gcc-4.2.1-posix-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/gcc-4.2.1-cross_search_paths-1.patch

http://ftp.gnu.org/gnu/glibc/glibc-2.6.1.tar.bz2

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-sysdep_cancel-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-localedef_segfault-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-libgcc_eh-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-hppa_nptl-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-cross_hacks-1.patch

http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch

 

4.2 设置环境变量

export TAR=/tar //设置源文件压缩包的存放目录路径

export TOP=/usr/local/arm //设置目标工具链目录的顶成目录

export CLFS=${TOP}/clfs //设置编译过程工作目录

export SYSROOT=${TOP}/4.2.1 //设置目标工具链的工作目录

export TARGET_PREFIX=${TOP}/4.2.1 //设置目标工具链的安装目录


注意:这里的SYSROOT 和 TARGET_PREFIX 设成相同。跟http://cross-lfs.org/view/clfs-sysroot/arm/index.html 上所讲的有所不同,也是该网站出错最严重的地方,因为不但制作过程需要 Linux 内核头文件 跟 glibc 的头文件,而且以后使用这个制作出来的目标交叉编译工具链来编译程序的时候也会用到这些头文件,特别是Linux内核的头文件。所以Garfield Trump 把SYSROOT 和 TARGET_PREFIX设成相同,以便把头文件直接安装到目标交叉编译工具链的工作目录中。


LINUX_VERSION=2.6.22.6 //设置 Linux 的版本号

BINUTILS_VERSION=2.18 //设置 binutils 的版本号

GLIBC_VERSION=2.6.1 //设置 glibc 的版本号

GCC_VERSION=4.2.1 //设置 目标工具链的版本号


unset CFLAGS //禁用两个环境变量,因为可能导致编译过程出错

unset CXXFLAGS //默认情况下这两个环境变量为空,但随不同的Linux 平台的不同,或者用户自己之前的使用过程中设置了这两个变量设置目标工具链的目标体系,Gcc编译器会根据这个变量来确定目标交叉编译工具链是为那个目标体系的cpu编译程序的。

export CLFS_TARGET="arm-linux" //设置目标交叉编译工具链的编译器(arm-linux-gcc)的路径,因为在完成第一阶段arm-linux-gcc的编译后,我们将会把它安装到这里,并且使用它来编译出第二阶段 arm-linux-gcc 制作所依赖的动态链接库 glibc。

export PATH=${TARGET_PREFIX}/bin:/bin:/usr/bin:$PATH

 
 
4.3建立相应工作目录安装Linux 内核头文件
 

rm -rf ${TOP} //清除可能干扰制作过程的目录

install -dv ${SYSROOT}/usr/include //建立Linux头文件安装目录

install -dv ${TOP}/source //建立源码解压目录

cd ${TOP}/source //进入源码解压目录

cp ${TAR}/linux-${LINUX_VERSION}.tar.gz ./ //拷贝源码包到解压目录

gzip -d ./linux-${LINUX_VERSION}.tar.gz //解压Linux 内核源码包

tar -xf linux-${LINUX_VERSION}.tar //解包 Linux 内核源码包

rm -rf linux-${LINUX_VERSION}.tar //解包完后删除 Linux 内核源码包

cd linux-${LINUX_VERSION} //进入Linux 内核源码目录

make s3c2410_defconfig ARCH=arm //设置 Linux 内核源码匹配的cpu 体系

//注意:下面一步是Garfield Trump 给予纠正的一步,在官方网站http://cross-lfs.org/view/clfs-sysroot/arm/index.html下是没有这一步的,会导致后面的编译出错。

make include/linux/version.h //生成Linux 版本头文件。

//复制制作目标交叉编译工具链所要的Linux头文件
cp -a include/{asm-generic,linux,mtd,scsi,sound} ${SYSROOT}/usr/include
cp -a include/asm-arm ${SYSROOT}/usr/include/asm

 

4.4建立binutils

mkdir -p ${TARGET_PREFIX} //建立目标交叉编译工具链安装目录

cd ${TOP}/source //进入源码解压目录

tar -jxf ${TAR}/binutils-${BINUTILS_VERSION}.tar.bz2 //解压binutils 源码包到此目录

cd binutils-${BINUTILS_VERSION} //进入 binutils 的源码目录

patch -Np1 -i ${TAR}/binutils-${BINUTILS_VERSION}-posix-1.patch //给binutils打补丁

mkdir -p ${TOP}/source/BUILD/binutils-${BINUTILS_VERSION} //建立 binutils 的编译目录

cd ${TOP}/source/BUILD/binutils-${BINUTILS_VERSION} //进入 binutils 的编译目录

//设立汇编器的环境变量

AR=ar
AS=as
//对 binutils 进行配置

${TOP}/source/binutils-${BINUTILS_VERSION}/configure --prefix=${TARGET_PREFIX} --target=${CLFS_TARGET} --with-sysroot=${SYSROOT} --disable-nls --enable-shared --disable-multilib
               
make configure-host //编译 binutils

make
make install //安装 binutils

//复制后续编译所要的 binutils 的头文件

cp -v ${TOP}/source/binutils-${BINUTILS_VERSION}/include/libiberty.h ${SYSROOT}/usr/include

 

4.5安装Glibc 的头文件

 

 

 

 

cd ${TOP}/source //进入源码解压目录

tar -jxf ${TAR}/glibc-${GLIBC_VERSION}.tar.bz2 //解压 Glibc 的源码包到此目录


//改变源码目录名,为了标识这份源码是为安装头文件而解压、配置、补丁的。http://cross-lfs.org/view/clfs-sysroot/arm/index.html 上说的是要我们在编译安装完成每一个阶段后,把用过的源码包删除,下次用到时再次解压,以免这次的补丁、配置影响下一次的编译。Garfield Trump 则采用改变目录名的方式来实现,目的在于保留这些编译、设置过的源码,以后可以直接用这些编译过的内容直接安装,不需要再次编译。因为编译是很耗时的事情。

mv glibc-${GLIBC_VERSION} glibc-${GLIBC_VERSION}-headers-build

cd glibc-${GLIBC_VERSION}-headers-build //进入glibc头文件安装源码目录


//下面两行是为了消除在配置glibc时 gcc 对glibc的依赖。因为这里只是为了安装头文件,并不是要配置、编译、安装 Glibc。

cp configure{,.orig}
sed -e 's/3.4/3.[0-9]/g' configure.orig > configure

//解压glibc 的cpu体系支持源码包到glibc 头文件安装源码目录,因为glibc 默认是没有ARM cpu支持的,GNU组织专门加入了此源码包来解决此问题。

tar -jxf ${TAR}/glibc-ports-${GLIBC_VERSION}.tar.bz2

//改变cpu 体系支持源码目录为 ports ,因为glibc对所有加入的而外支持包的默认搜索目录为 ports。

mv glibc-ports-${GLIBC_VERSION} ports

//建立glibc头文件配置、安装的工作目录

mkdir -p ${TOP}/source/BUILD/glibc-${GLIBC_VERSION}-headers-build

//进入glibc头文件配置、安装的工作目录

cd ${TOP}/source/BUILD/glibc-${GLIBC_VERSION}-headers-build

//以下三步是为了把glibc头文件配置成支持 NPTL(linux 的新线程标准)而设立的必须条件,并把这些条件写入缓存文件(可以从下面的配置选项 --cache-file=config.cache看出)

echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "libc_cv_arm_tls=yes" >> config.cache
CC=gcc //指定配置使用的编译器


//配置glibc

${TOP}/source/glibc-${GLIBC_VERSION}-headers-build/configure --prefix=/usr --host=${CLFS_TARGET} --with-headers=${SYSROOT}/usr/include --cache-file=config.cache

make install-headers install_root=${SYSROOT} //安装 glibc头文件

cp -v bits/stdio_lim.h ${SYSROOT}/usr/include/bits //复制编译后续编译所要的头文件

//建立必要的地头文件,内容为空,因为这个头文件在第一阶段Gcc 编译安装时要被 check 到,但这是后面编译安装目标机的glibc时才被生成安装的。

touch ${SYSROOT}/usr/include/gnu/stubs.h


//拷贝建立支持NPTL编译器所必须的头文件

cp --reply=yes ${TOP}/source/glibc-${GLIBC_VERSION}-headers-build/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h ${SYSROOT}/usr/include/bits

 

4.6 编译安装第一阶段 arm-linux-gcc

cd ${TOP}/source //进入源码解压目录

tar -jxf ${TAR}/gcc-${GCC_VERSION}.tar.bz2 //解压gcc源码


//改变源码目录,为了标识这是第一阶段用的gcc源码,目的前面说过了。

mv gcc-${GCC_VERSION} gcc-${GCC_VERSION}-stage1

cd gcc-${GCC_VERSION}-stage1 //进入第一阶段源码目录


//打上支持posix 标准的补丁,新的线程标准NPTL是符合posix标准的。

patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-posix-1.patch

//打上交叉编译gcc搜索头文件路径的补丁

patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-cross_search_paths-1.patch

cd ${TOP}/source //进入源码解压目录

mkdir -p BUILD/gcc-${GCC_VERSION}-stage1 //建立编译第一阶段gcc的工作目录

cd BUILD/gcc-${GCC_VERSION}-stage1 //进入编译第一阶段gcc 的工作目录


//配置第一阶段gcc。

${TOP}/source/gcc-${GCC_VERSION}-stage1/configure --prefix=${TARGET_PREFIX} --host=i686-pc-linux-gnu --target=${CLFS_TARGET} --disable-multilib --with-sysroot=${SYSROOT} --disable-nls --disable-shared --enable-languages=c
注意配置选项--enable-languages=c 和--disable-shared!!!因为这一阶段的gcc 制作时,还没有生成其给目标机编译程序时所依赖的动态库,所以要—disable-shared,因此第一阶段的gcc是个静态的arm-linux-gcc。之所以只用了--enable-languages=c,而后面生成第二阶段的arm-linux-gcc却用了--enable-languages=c,c++,是因为我们这一阶段的arm-linux-gcc是为了生成制作第二阶段arm-linux-gcc所依赖的glibc动态函数库而制作,编译glibc只需要arm-linux-gcc,并不需要arm-linux-g++。加上c++也是没错的。



make all-gcc //编译第一阶段gcc

make install-gcc //安装第一阶段gcc

 

4.7 编译安装交叉编译工具链(第二阶段arm-linux-gcc)所依赖的glibc

 

cd ${TOP}/source //进入源码解压目录

tar -jxf ${TAR}/glibc-${GLIBC_VERSION}.tar.bz2 //解压glibc源码

cd glibc-${GLIBC_VERSION} //进入源码目录


//解压glibc 的cpu体系支持源码包到glibc 头文件安装源码目录,因为glibc 默认是没有ARM cpu支持的,GNU组织专门加入了此源码包来解决此问题。

tar -jxf ${TAR}/glibc-ports-${GLIBC_VERSION}.tar.bz2

//改变cpu 体系支持源码目录为 ports ,因为glibc对所有加入的而外支持包的默认搜索目录为 ports。

mv glibc-ports-${GLIBC_VERSION} ports
 
//以下四步均为给glibc打补丁,至于是什么补丁,自己到http://cross-lfs.org/view/clfs-sysroot/arm/index.html看!!

patch -Np1 -i ${TAR}/glibc-2.6.1-libgcc_eh-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-localedef_segfault-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-cross_hacks-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch

mkdir -p ${TOP}/source/BUILD/glibc-${GLIBC_VERSION} //建立配置、编译、安装glibc的工作目录

cd ${TOP}/source/BUILD/glibc-${GLIBC_VERSION} //进入配置、编译、安装glibc的工作目录


//以下三步是为了把glibc头文件配置成支持 NPTL(linux 的新线程标准)而设立的必须条件,并把这些条件写入缓存文件(可以从下面的配置选项 --cache-file=config.cache看出)

echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "libc_cv_arm_tls=yes" >> config.cache

//指定配置使用的编译器为gcc,即本机的gcc

BUILD_CC="gcc"
     
//指定编译glibc时使用第一阶段的交叉gcc,即上面生成的arm-linux-gcc

CC="${CLFS_TARGET}-gcc"
 
//指定汇编glibc时使用的汇编器为arm-linux-ar,即在制作binutils 时生成的交叉汇编器

AR="${CLFS_TARGET}-ar"

//这里我也不清楚,从环境变量命名看应该是编译时所用到的库吧!!!

RANLIB="${CLFS_TARGET}-ranlib"

//配置交叉编译工具链所依赖的动态库glibc

${TOP}/source/glibc-${GLIBC_VERSION}/configure --prefix=/usr --libexecdir=/usr/lib/glibc --host=${CLFS_TARGET} --build=i686-pc-linux-gnu --disable-profile --enable-add-ons --with-tls --enable-kernel=2.6.0 --with-__thread --with-binutils=${TARGET_PREFIX}/bin --with-headers=${SYSROOT}/usr/include --cache-file=config.cache
make //编译交叉编译工具链所依赖的动态库glibc

make install install_root=${SYSROOT} //安装交叉编译工具链所依赖的动态库


//以下的步骤是配置交叉编译工具链在使用动态库时所用的时区,语言。这里不多说了,照做就是了!!!

make localedata/install-locales
mkdir -pv ${SYSROOT}/usr/lib/locale
export I18NPATH=${PWD}/localedata
export GCONV_PATH=${PWD}/iconvdata
export LOCALEDEF="${PWD}/locale/localedef-native --alias-file=../intl/locale.alias"
cd ${TOP}/source/glibc-${GLIBC_VERSION}/localedata
${LOCALEDEF} -i locales/de_DE -f charmaps/ISO-8859-1 --prefix=${SYSROOT} de_DE
${LOCALEDEF} -i locales/de_DE@euro -f charmaps/ISO-8859-15 --prefix=${SYSROOT} de_DE@euro
${LOCALEDEF} -i locales/en_HK -f charmaps/ISO-8859-1 --prefix=${SYSROOT} en_HK
${LOCALEDEF} -i locales/en_PH -f charmaps/ISO-8859-1 --prefix=${SYSROOT} en_PH
${LOCALEDEF} -i locales/en_US -f charmaps/ISO-8859-1 --prefix=${SYSROOT} en_US
${LOCALEDEF} -i locales/es_MX -f charmaps/ISO-8859-1 --prefix=${SYSROOT} es_MX
${LOCALEDEF} -i locales/fa_IR -f charmaps/UTF-8 --prefix=${SYSROOT} fa_IR
${LOCALEDEF} -i locales/fr_FR -f charmaps/ISO-8859-1 --prefix=${SYSROOT} fr_FR
${LOCALEDEF} -i locales/fr_FR@euro -f charmaps/ISO-8859-15 --prefix=${SYSROOT} fr_FR@euro
${LOCALEDEF} -i locales/it_IT -f charmaps/ISO-8859-1 --prefix=${SYSROOT} it_IT
${LOCALEDEF} -i locales/ja_JP -f charmaps/EUC-JP --prefix=${SYSROOT} ja_JP
unset I18NPATH GCONV_PATH LOCALEDEF
/************************ 下面是配置动态库的使用环境文件 照做!!!******************/
cat > ${SYSROOT}/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="${SYSROOT}/usr/share/zoneinfo"
${SYSROOT}/usr/bin/tzselect
cp -v --reply=yes --remove-destination ${SYSROOT}/usr/share/zoneinfo/America/New_York ${SYSROOT}/etc/localtime

cat > ${SYSROOT}/etc/ld.so.conf << "EOF"
# Begin /etc/ld.so.conf

/usr/local/lib
/opt/lib

# End /etc/ld.so.conf
EOF

 

4.8 第二阶段的gcc 制作。

即制作依赖上一阶段生成的glibc arm-linux-gcc等一系列交叉编译工具,统称交叉编译工具链。这里已经是交叉编译工具链生成的最后一步了,恭喜你!!!

cd ${TOP}/source //进入源码解压目录

tar -jxf ${TAR}/gcc-${GCC_VERSION}.tar.bz2 //解压gcc源代码


//改名源码目录,为了标识这是编译第二阶段的gcc 所用的源码

mv gcc-${GCC_VERSION} gcc-${GCC_VERSION}-stage2

cd gcc-${GCC_VERSION}-stage2 //进入源码目录


//打上支持posix 标准的补丁,新的线程标准NPTL是符合posix标准的。

patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-posix-1.patch

//打上交叉编译gcc搜索头文件路径的补丁

patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-cross_search_paths-1.patch

cd ${TOP}/source //进入源码解压目录

mkdir -p BUILD/gcc-${GCC_VERSION}-stage2 //建立第二阶段gcc的编译工作目录

cd BUILD/gcc-${GCC_VERSION}-stage2 //进入第二阶段gcc的编译工作目录


//配置第二阶段交叉编译工具链

${TOP}/source/gcc-${GCC_VERSION}-stage2/configure --prefix=${TARGET_PREFIX} --host=i686-pc-linux-gnu --target=${CLFS_TARGET} --disable-multilib --with-sysroot=${SYSROOT} --disable-nls --enable-shared --enable-languages=c,c++ --enable-__cxa_atexit --enable-c99 --enable-long-long --enable-threads=posix

make all-gcc //编译第二阶段交叉编译工具链

make install-gcc install_root=${TARGET_PREFIX} //安装交叉编译工具链

 

《五》疑难解答:

5.1 第一阶段gcc 跟第二阶段 gcc ,一个是静态一个是动态,那么是在哪里指定了第二阶段gcc是跟动态函数库关联,而且是关联到哪个动态库,怎样关联到我们制作出来的动态库呢?

 

答:

1、比较两次的配置参数

Gcc stage1

configure --prefix=${TARGET_PREFIX} --host=i686-pc-linux-gnu --target=${CLFS_TARGET} --disable-multilib --with-sysroot=${SYSROOT} --disable-nls --disable-shared --enable-languages=c

 

Gcc stage2

configure --prefix=${TARGET_PREFIX} --host=i686-pc-linux-gnu --target=${CLFS_TARGET} --disable-multilib --with-sysroot=${SYSROOT} --disable-nls --enable-shared --enable-languages=c,c++ --enable-__cxa_atexit --enable-c99 --enable-long-long --enable-threads=posix

 

2、因为指定了--with-sysroot=${SYSROOT} 那么编译时就会以该目录为系统根目录作为动态共享函数库目录、头文件存放目录的顶层搜索目录。如果--enable-shared 就会在该目录下搜索lib目录、usr/lib目录下的动态共享函数库文件,并在该目录下搜索include 目录、/usr/include目录中的头文件。这样只要我们把我们制作的glibc指定安装到${SYSROOT},制作出来的交叉编译器就会关联到我们的glibc,并且在以后使用这个交叉编译器编译程序时,编译器就会到${SYSROOT}下关联我们制做的动态函数库,查找用户程序所使用的Linux内核头文件。但如果使用--disable-shared参数,就不会去搜索一切${SYSROOT}下的动态函数库文件夹,来关联动态函数库文件了。

原创粉丝点击