LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 5949|回复: 26

用GCC 4.3-20040810构造SYSROOT工具链

[复制链接]
发表于 2008-4-12 20:49:32 | 显示全部楼层 |阅读模式
本文最后更新于4月15日
-----------
SYSROOT工具链相比普通的LFS/CLFS工具链有很多优势。这点在Youbest的文章里面已经有叙述。

随着GCC 4.3的出现,构造SYSROOT工具链的原有方法已经行不通了。经过本人反复测试,在x86_64 -> x86_64上总结出如下的工具链构造方法。本文主要参考最新的CLFS-SYSROOT BOOK,请对照阅读。

1. 准备工作
请参考根据CLFS-SYSROOT的标准做法,进行分区、添加用户、设置环境等工作。由于本文的宿主是x86_64,因此需要多加几个变量:
export CLFS_TARGET32="i686-pc-linux-gnu"
export BUILD32="-m32"
export BUILD64="-m64"
此外,我的测试环境有些另类。为了拥有一个基本上干净的目标分区,我把cross-tools目录直接建在宿主根目录下,同时在$CLFS目录(目标分区)下创建一个符号连接指向它。这样,所有的交叉工具链(依赖于宿主的)都不会存在于目标分区。
为了安装GCC 4.3我们额外下载3个东东:
GMP 4.2.2 http://ftp.sunet.se/pub/gnu/gmp/gmp-4.2.2.tar.bz2
MPFR 2.3.1 http://www.mpfr.org/mpfr-current/mpfr-2.3.1.tar.bz2
FLEX 2.5.32 http://optusnet.dl.sourceforge.n ... flex-2.5.35.tar.bz2

2. binutils 2.18
本来根据CLFS-SYSROOT,这一步之前需要安装目录结构、设置用户密码等。不过,我们这里忽略它,仅在必要的时候才安装需要的目录。实践证明这样做是完全可行的,因为在工具链创建成功之前我们甚至不想往目标分区放任何东西。只不过有些东西如头文件和库文件等不得不放在那里,否则就构建不出我们的交叉工具链了。

patch -Np1 -i ../binutils-2.18-genscripts_multilib-1.patch
patch -Np1 -i ../binutils-2.18-posix-1.patch

mkdir -v ../binutils-build
cd ../binutils-build

AR=ar AS=as ../binutils-2.18/configure --prefix=$CLFS/cross-tools \
   --host=$CLFS_HOST --target=$CLFS_TARGET --with-sysroot=$CLFS \
   --disable-nls --enable-shared --with-64-bit-bfd
以上没什么好说的,照抄的而已。

make && make install
我懒得一步步make configure-host && make && make install,直接一步make install了事。事实上效果是完全一样的。make configure-host会把所有的目录都创建好并运行相应的configure脚本生成Makefile文件。这对调试Makefile和configure相关问题非常有用。不过,binutils实在也没什么可调试的。但直接make install 也不行,要先make好才能install。

3. GMP & MPFR
两个库的安装方式都很简单:
./configure --prefix=$CLFS/cross-tools --disable-shared
make install
添加--disable-shared是因为我们不需要它们的动态库。只要静态库就足够安装了。

4. FLEX
这个更简单:
./configure --prefix=$CLFS/cross-tools
make install

5. 头文件
首先是Linux头文件,我用Linux-2.6.24.4
install -dv $CLFS/usr/include
make mrproper
make ARCH=x86_64 headers_check
make ARCH=x86_64 INSTALL_HDR_PATH=dest headers_install
cp -rv dest/include/* $CLFS/usr/include

然后是Glibc头文件。顺便说一下,如果你用GCC 4.2.3这一步是可以忽略的,只要在配置参数上加上一个--with-newlib就可以。但是经过反复尝试在GCC 4.3里这样做是不行的。
cp configure{,.orig}
sed -e 's/3.4\*/3.[0-9]\*/g' configure.orig >configure

mkdir -v ../glibc-build
cd ../glibc-build

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

echo "install_root=${CLFS}" > configparms

CC=gcc ../glibc-2.7/configure --prefix=/usr \
    --host=${CLFS_TARGET} --build=${CLFS_HOST} \
    --with-headers=${CLFS}/usr/include --cache-file=config.cache

make install-headers
cp -v bits/stdio_lim.h ${CLFS}/usr/include/bits
touch ${CLFS}/usr/include/gnu/stubs.h
cp -v ../glibc-2.7/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h \
    ${CLFS}/usr/include/bits
以上基本是照抄,然后稍微改动一下得到的。

6. GCC 4.3-20080410 c语言静态库
在目前的阶段,GCC无法产生动态库,这是因为动态库需要启动代码,而启动代码由Libc提供,现阶段Libc还尚不存在。因此现在要编译GCC,只能选择生成静态库。
之前的版本这里有一个补丁,根据1987a网友的提示这步是不需要的,可以省略。
(可以省略)cp libgcc/Makefile.in{,.orig}
(可以省略)sed -e '/libgcc\.a libgcov\.a\s*$/s/$/ libgcc_eh.a/' libgcc/Makefile.in.orig > libgcc/Makefile.in

mkdir ../gcc-build
cd ../gcc-build

AR=ar CC_FOR_TARGET="$CLFS_TARGET-gcc" ../gcc-4.3-20080410/configure --prefix=$CLFS/cross-tools --host=$CLFS_HOST --target=$CLFS_TARGET --with-sysroot=$CLFS --disable-nls --enable-long-long --enable-languages=c --with-gmp=$CLFS/cross-tools --with-mpfr=$CLFS/cross-tools --disable-shared --disable-threads

这里要注意的是--with-gmp 和--with-mpfr参数是为了让GCC构建系统能够找到之前编译的GMP和MPFR这两个包。其余参数都可以从CLFS-SYSROOT BOOK找到。同时,AR=ar这个环境变量如果不设置,构建系统会试图寻找并不存在的x86_64-cross-linux-gnu-ar。而CC_FOR_TARGET的设置后面会提到。

构造部分非常特别,是我实验多次才找到的。

make all-gcc && make install-gcc

首先说一句,和我在别处的风格不一样,这里如果只有make install-gcc那是跑不了的。因为make install-gcc不默认执行make all-gcc。其次,这一步看上去和之前的版本一模一样,但有本质的区别。因为从GCC 4.3开始,make all-gcc就真的只会生成gcc及相关的可执行文件,至于相关的库它一点都不管了。所以我们还需要额外的步骤来生成相关的库文件。

不过有一个问题,就是随后生成库文件的步骤中,构建系统应当采用新创建的$CLFS_TARGET-gcc而不是宿主的gcc来编译。所以我们需要在配置的时候设置好CC_FOR_TARGET变量。之前曾采取过

(不建议使用)ln -sv ${CLFS_TARGET}-gcc $CLFS/cross-tools/bin/cc

的方式来绕过这个问题,不过如果你用了正确的参数,就不再需要这个步骤。

现在我们来构建GCC库文件

make all-target-libgcc && make install-target-libgcc

之前的版本我们需要一个补丁,但这个补丁其实已经包含在Glibc包中(1987a的提醒),所以这些步骤都不需要了
(不需要)cp $CLFS_TARGET/libgcc/libgcc_eh.a $CLFS/cross-tools/lib/gcc/$CLFS_TARGET/4.3.1
(不需要)cp $CLFS_TARGET/32/libgcc/libgcc_eh.a $CLFS/cross-tools/lib/gcc/$CLFS_TARGET/4.3.1/32
(不需要)${CLFS_TARGET}-ranlib $CLFS/cross-tools/lib/gcc/$CLFS_TARGET/4.3.1/libgcc_eh.a
(不需要)${CLFS_TARGET}-ranlib $CLFS/cross-tools/lib/gcc/$CLFS_TARGET/4.3.1/32/libgcc_eh.a

7. Glibc 32bit
现在我们需要构造一个32位的Glibc。先打两个补丁
patch -Np1 -i ../glibc-2.7-libgcc_eh-1.patch
patch -Np1 -i ../glibc-2.7-localedef_segfault-1.patch

GCC 4.3系列把某些头文件放在了另一个目录,致使Glibc找不到。为此我们需要一个补丁:
cp configure{,.orig}
sed -e "/ccheaders=/s/\`\(\$CC.*include\)\`/\"& -isystem \`\1-fixed\`\"/" configure.orig > configure

随后是标准步骤:
mkdir -v ../glibc-build
cd ../glibc-build

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

echo "install_root=${CLFS}" > configparms
echo "CFLAGS += -march=i686" >> configparms

BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc ${BUILD32}" \
    AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \
    ../glibc-2.7/configure --prefix=/usr \
    --libexecdir=/usr/lib/glibc --host=${CLFS_TARGET32} --build=${CLFS_HOST} \
    --disable-profile --enable-add-ons --with-tls --enable-kernel=2.6.0 \
    --with-__thread --with-binutils=/cross-tools/bin \
    --with-headers=${CLFS}/usr/include --cache-file=config.cache

make && make install
工具链的组件基本上都不可以直接make install。

8. Glibc 64bit
标准操作是要删除源代码,然后重新打补丁,重新构建。但是因为补丁是一样的,我们就没有必要删除重来了。只需要在glibc-build下
rm -rf *
然后即可开始标准步骤:
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache

echo "install_root=${CLFS}" > configparms
echo "slibdir=/lib64" >> configparms

BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc ${BUILD64}" \
    AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \
    ../glibc-2.7/configure --prefix=/usr --libdir=/usr/lib64 \
    --libexecdir=/usr/lib64/glibc --host=${CLFS_TARGET} --build=${CLFS_HOST} \
    --disable-profile --enable-add-ons --with-tls --enable-kernel=2.6.0 \
    --with-__thread --with-binutils=${CLFS}/cross-tools/bin \
    --with-headers=${CLFS}/usr/include --cache-file=config.cache

make && make install

9. 终极Gcc
在GCC 4.3-20080410 中的libstdc++部分有一个bug必须修复,请参见附件。

patch -Np1 -i ../gcc-4.3-20080410-libstdc++-v3.patch.txt

mkdir -v ../gcc-build
cd ../gcc-build

AR=ar CXX_FOR_TARGET="$CLFS_TARGET-g++" CC_FOR_TARGET="$CLFS_TARGET-gcc" ../gcc-4.3-20080410/configure --prefix=${CLFS}/cross-tools \
    --host=${CLFS_HOST} --target=${CLFS_TARGET} \
    --with-sysroot=${CLFS} --disable-nls --enable-shared \
    --enable-languages=c,c++ --enable-__cxa_atexit \
    --enable-c99 --enable-long-long --enable-threads=posix \
    --with-gmp=$CLFS/cross-tools --with-mpfr=$CLFS/cross-tools
这里我们再次使用了CC_FOR_TARGET和CXX_FOR_TARGET来防止库构建过程引用错误的编译器。构造过程可谓是一波三折,共需三个阶段

a. 编译并安装编译器
make all-gcc && make install-gcc
在这个阶段,为什么我们还不能大大方方地make呢?原因还是因为在构建GCC库的时候,GCC 4.3需要引用刚编译的C++编译器。这个编译器在make install-gcc的时候才能安装上。

之前我使用过这条命令
(不建议使用)ln -sv $CLFS_TARGET-g++ $CLFS/cross-tools/bin/c++
来防止错误的编译器引用。现在已经不需要了。

b.编译并安装libgcc
make all-target-libgcc && make install-target-libgcc
在后面某个阶段我们需要新安装的而不是老的libgcc(因为之前的libgcc是静态库,而这次编译用的是动态链接)。如果绕过make all-gcc直接运行这个,那么因为target-libgcc使用之前静态链接的gcc编译,随后步骤会发生一些错误。

c.最终步骤
make  && make install
完成安装。

不出意外的话,经过千辛万苦,我们的SYSROOT工具链应该就完成了!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2008-4-12 21:11:55 | 显示全部楼层
向白鼠致敬。
建议lz修改一下标题,你这个应该是CLFS-SYSROOT x86_64 Multilib Builds.
回复 支持 反对

使用道具 举报

发表于 2008-4-12 21:31:46 | 显示全部楼层
lz新建 CLFS-SYSROOT 又一新分支,建议完善后提交官方,建议+精。
下面给出后续工作的一点建议,交叉编译perl时应安装32bit版本。64bit版本交叉编译时需要先在x86_64 native 环境下配置,然后修改配置才可以交叉编译成功。64bit版本建议使用boot/chroot后的 native 编译版本。当然你的host环境是x86_64,会简单很多,但没有一般性。
回复 支持 反对

使用道具 举报

发表于 2008-4-12 22:11:22 | 显示全部楼层
lz已经做了这么多,顺便帮个小忙好吗?

我用 CLFS-SYSROOT 的方法制作了pure64 的 x86_64 toolchain,结合CLFS-1.0安装软件包的顺序完成了现在正使用的系统。
(等些时间看看能不能也总结个 CLFS-SYSROOT x86_64 pure64 Builds 精华帖出来)

但出现了E2fsprogs-1.40.6和grub-0.97(x86 32bit静态编译)不兼容的问题:grub-0.97不认识E2fsprogs-1.40.6做的ext3,linux-kernel放在其他地方,系统可以正常启动。我现在使用的是E2fsprogs-1.40.2。
http://www.linuxsir.cn/bbs/thread324509.html

使用我建立系统的方法这个问题在我的机器上每次都可以重现,所以怀疑是不是自己什么地方做的有问题,暂时也没有报告bug给E2fsprogs-1.40.6和grub-0.97。

lz 你的CLFS-SYSROOT x86_64 Multilib Builds刚好可以帮我验证一下。

PS:grub-0.97(x86 32bit静态编译) 是使用 CLFS-SYSROOT x86 方式建立的,与pure64 x86_64共享同一套源程序。
PS:我痛恨Multilib方式的系统。
回复 支持 反对

使用道具 举报

发表于 2008-4-12 22:57:57 | 显示全部楼层
Post by 地球发动机;1837546
首先说一句,和我在别处的风格不一样,这里如果只有make install-gcc那是跑不了的。因为make install-gcc不默认执行make all-gcc。其次,这一步看上去和之前的版本一模一样,但有本质的区别。因为从GCC 4.3开始,make all-gcc就真的只会生成gcc及相关的可执行文件,至于相关的库它一点都不管了。所以我们还需要额外的步骤来生成相关的库文件。不过在此之前,有一个看似很奇怪的步骤必须先执行

ln -sv ${CLFS_TARGET}-gcc $CLFS/cross-tools/bin/cc

这一步之所以需要是因为随后生成库文件的步骤中,构建系统采用cc -m32来执行编译。无论理论上还是实际上,这个编译器应该是之前make all-gcc生成的那个才对。如果你没有这个步骤,那么这个cc将引用宿主的编译器,一般来说会发生很多莫名其妙的错误。


在这个阶段,为什么我们还不能大大方方地make呢?原因还是因为在构建GCC库的时候,GCC 4.3使用了c++来引用g++编译器。这个编译器在make install-gcc的时候才能安装上。

ln -sv $CLFS_TARGET-g++ $CLFS/cross-tools/bin/c++


lz cc c++这两个软连接不妥,有失CLFS方法一般性,你的host系统是x86_64-unknown-linux-gnu,你的toolchain也是for x86_64-unknown-linux-gnu的,当然你用交叉编译的方式"交叉编译"后,这些工具可以在host上直接使用,但如果你的host系统不是x86_64-unknown-linux-gnu呢,比如i486/i586/i686?
你这么做相当于为host升级了 native gcc,但这种方式是有问题的,你偷了不该偷的懒。我们知道,升级gcc应该使用bootstrap方式,以确保gcc安装正确。你应该把升级gcc独立出来才不失CLFS方法一般性。
回复 支持 反对

使用道具 举报

发表于 2008-4-12 23:24:04 | 显示全部楼层
发动机大哥的好贴,不顶不行。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-4-13 16:26:05 | 显示全部楼层
Post by 1987a;1837599
lz cc c++这两个软连接不妥,有失CLFS方法一般性,你的host系统是x86_64-unknown-linux-gnu,你的toolchain也是for x86_64-unknown-linux-gnu的,当然你用交叉编译的方式"交叉编译"后,这些工具可以在host上直接使用,但如果你的host系统不是x86_64-unknown-linux-gnu呢,比如i486/i586/i686?
你这么做相当于为host升级了 native gcc,但这种方式是有问题的,你偷了不该偷的懒。我们知道,升级gcc应该使用bootstrap方式,以确保gcc安装正确。你应该把升级gcc独立出来才不失CLFS方法一般性。


我没有试图去改变宿主系统。因为我的链接是建立在$CLFS/cross-tools/bin下的,宿主系统一般不会把这个加到路径里面去,只有CLFS用户才会把它加入。同时,如果你有留意我的做法,最后我是把这些软链接删除了的。

我这个也绝对不是native gcc,而是cross gcc,在宿主机上,这个gcc一般是用不了的,因为它的sysroot路径指向/mnt/clfs。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-4-13 20:20:29 | 显示全部楼层
Post by 1987a;1837599
lz cc c++这两个软连接不妥,有失CLFS方法一般性,你的host系统是x86_64-unknown-linux-gnu,你的toolchain也是for x86_64-unknown-linux-gnu的,当然你用交叉编译的方式"交叉编译"后,这些工具可以在host上直接使用,但如果你的host系统不是x86_64-unknown-linux-gnu呢,比如i486/i586/i686?
你这么做相当于为host升级了 native gcc,但这种方式是有问题的,你偷了不该偷的懒。我们知道,升级gcc应该使用bootstrap方式,以确保gcc安装正确。你应该把升级gcc独立出来才不失CLFS方法一般性。


在顶楼我已经做了更新,采用环境变量来解决这个问题。但我仍然要澄清另一点,就是你不能靠更新host为native gcc来解决这个编译器问题。libgcc是要在目标机器上运行的代码,这意味着它必须由交叉gcc编译出来。更新host cc为native gcc并不能解决这个问题。唯一方案只能是由本次编译产生的gcc来编译libgcc。
回复 支持 反对

使用道具 举报

发表于 2008-4-13 21:21:38 | 显示全部楼层
首先,lz 已经修改cc这个部分,表扬一下。但c++还留着,还是不妥。

按个人理解:
gcc已经是非常成熟的软件包,在host系统各相关软件版本满足该版本gcc配置编译要求的情况下,制作toolchain过程中,配置编译该版本gcc时,应当仅给出--build --host --target参数以及相应binutils工具变量就可以顺利完成编译才是正常的,不应当依赖其它不相关变量设置或连接(如lz 给出的cc/c++软连接);
否则,就是什么地方出了问题,可能是该版本gcc的bug,可能是编译者hacking引起的,可能是host系统并不真正满足要求……

Post by 地球发动机;1837793
我没有试图去改变宿主系统。因为我的链接是建立在$CLFS/cross-tools/bin下、的,宿主系统一般不会把这个加到路径里面去,只有CLFS用户才会把它加入。同时,如果你有留意我的做法,最后我是把这些软链接删除了的。

我这个也绝对不是native gcc,而是cross gcc,在宿主机上,这个gcc一般是用不了的,因为它的sysroot路径指向/mnt/clfs。


lz这么讲正说明自己相关概念不清晰,有点逻辑混乱。没别的意思,只是讨论讨论,有不对的地方,尽管使板砖。

没错,你的gcc是cross gcc,是toolchain中使用的cross gcc。
我只是说"你这么做相当于为host升级了 native gcc"。
可能是我没讲清楚,lz正文中cc c++两个软连接给我的直接印象是toolchain中gcc的编译依赖host系统的gcc-4.3,而lz的host系统使用的是低版本的gcc。
我认为对host系统的基本要求应当加入gcc-4.3,相应的GMP MPFR也加入基本要求,这样制作toolchain的过程应当只需要正常的2次编译gcc而不是lz的3次,同时也不需要cc c++两个软连接。这个现在只是猜测,需要实际验证。

Post by 地球发动机;1837793
我没有试图去改变宿主系统。

没必要这么偏执,必要时,还是需要的,过河是目的,之后拆桥都成,host系统随你处置。
如你把GMP MPFR安装在host系统/usr下,不是更简单么,制作toolchain时不再需要--with-gmp --with-mpfr参数。

Post by 地球发动机;1837793
因为我的链接是建立在$CLFS/cross-tools/bin下、的,宿主系统一般不会把这个加到路径里面去,只有CLFS用户才会把它加入。同时,如果你有留意我的做法,最后我是把这些软链接删除了的。

按个人标准,这是hacking,可能会带来不可预测的后果,应优先使用通用方法,除非这种行为能带来可以接受的优势,或不得不这样做。

Post by 地球发动机;1837793
我这个也绝对不是native gcc,而是cross gcc,在宿主机上,这个gcc一般是用不了的,因为它的sysroot路径指向/mnt/clfs。

我不否认你这个是cross gcc。但根据你的正文,你有定义这么两个变量CLFS_HOST=x86_64-cross-linux-gnu CLFS_TARGET=x86_64-unknown-linux-gnu,所以你的cross gcc事实上是一个变相的native gcc,只是它的sysroot路径指向/mnt/clfs。不出意外的话,你host系统和toolchain使用的是同版本glibc-2.7。用你的toolchain交叉编译一份for x86_64的程序,只要host系统有同版本必须的lib,可以在host系统上运行的几率接近1。
另,你连接为cc的第一次编译的gcc-4.3,是一个静态的裸编译器。在你用它完成第一遍gcc-4.3后半部分时,等同于native gcc-4.3。
请注意到此为止,我从没说过你的gcc是native gcc。
回复 支持 反对

使用道具 举报

发表于 2008-4-13 21:27:51 | 显示全部楼层
Post by 地球发动机;1837840
在顶楼我已经做了更新,采用环境变量来解决这个问题。但我仍然要澄清另一点,就是你不能靠更新host为native gcc来解决这个编译器问题。libgcc是要在目标机器上运行的代码,这意味着它必须由交叉gcc编译出来。更新host cc为native gcc并不能解决这个问题。唯一方案只能是由本次编译产生的gcc来编译libgcc。


好吧,我来验证一下。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表