Skip to content

Latest commit

 

History

History
1034 lines (698 loc) · 31.3 KB

构建工具链.md

File metadata and controls

1034 lines (698 loc) · 31.3 KB

构建工具链

image-20201121114740384

说在前:

  • 本节关键就是弄懂上面的构建过程,为什么要分这几个阶段
  • 本节实验采用的都是交叉编译的方式,如果你陷入鸡生蛋蛋生鸡的迷惑,那么说明你动脑了,否则,多看几遍
  • 工具链本质是也是二进制应用,假设我们写一个程序支持A种配置文件,后来应用扩展,配置也要新增,那么这个应用就需要更新来扩展支持配置。说到底源码和配置对程序来说都一样,都是二进制,只是处理方式不同。语言定义了协议规则,编译器根据协议规则实现,协议扩展,编译器也要更新扩展。只是编译器的扩展,仍然是用旧的编译器来编译(编译器)代码生成新的编译器
  • 如果平台架构一致,就没必要重构一些额外的工具。书中所用交叉编译能够更详尽的描述整个鸡生蛋蛋生鸡的过程。交叉编译,你能学到更多
  • 本节最关键的是要弄懂三个工具链工具的依赖关系
    • freestanding不依赖C库的编译器,虽然不完整,但是可以使用,可以用来构建完整的编译器
    • binutils是用来构建编译器的工具,几乎不依赖其他两者
    • glibc中有一部分用到内核,一部分用到gcc编译器,所以还要牵扯到内核头文件
    • 以造车为例,先安排基本材料,然后造工具,然后造车

20190910_215315_93

  • 我们要构建的 vita 系统属于 32 位 OS

工具链

20190910_215434_64

  • 工具链是包括上节中,编译过程,超集。编译用GNU GCC就够了
  • C库的重要性,没有C库就没有其他应用程序了。可以说100%的应用程序都链接C库,C库包含了常用的函数,POSIX标准

20190910_221558_33

  • 交叉编译,无非就是宿主系统和目标系统(开发机)架构不同,例如x86编译arm的程序

20190910_221716_35

  • GNU将编译器和C库分开。但编译器又依赖C库,C库又是由编译器编译产生

20190910_221931_76

20190910_222103_94

20190910_222239_81

20190910_222255_93

20190910_222438_35

图示解释清楚这几者之间的关系

20200204_111434_98

20190910_222539_30

20200204_111510_10

独立(free—standing)环境和宿主(hosted)环境

20200204_111346_32

准备工作

20190910_224015_53

  • 添加vita用户,新建目录,修改权限,切换到vita搞事情

20200204_111601_63

  • 定义环境变量
root@vita:/vita# vi /home/vita/.bashrc

...

#添加内容
unset LANG
export HOST=i686-pc-linux-gnu
export BUILD=$HOST
export TARGET=i686-none-linux-gnu
export CROSS_TOOL=/vita/cross-tool
export CROSS_GCC_TMP=/vita/cross-gcc-tmp
export SYSROOT=/vita/sysroot
PATH=$CROSS_TOOL/bin:$CROSS_GCC_TMP/bin:/sbin/:/usr/sbin:$PATH
CORES=$((`grep processor /proc/cpuinfo |wc -l`))
SPEEDUP=" -j ${CORES}"

20200204_120820_50

20190910_224650_45

  • 故意搞事情

20200204_111710_28

构建二进制工具binutils

参看 scripts/mk-binutils.sh 脚本

#!/bin/bash

set -e

source functions

function binutils(){
	cd /vita/build

	test -d /vita/build/binutils-2.23.1 && /bin/rm -rf binutils-2.23.1
	tar -xf ../source/binutils-2.23.1.tar.bz2

	test -d binutils-build && /bin/rm -rf binutils-build
	mkdir binutils-build && cd binutils-build

	../binutils-2.23.1/configure --prefix=$CROSS_TOOL --target=$TARGET --with-sysroot=$SYSROOT  2>&1 | tee log.configure.binutils

	make ${SPEEDUP}  2>&1 | tee log.make.binutils

	make ${SPEEDUP} install 2>&1 | tee log.makeinstall.binutils

	echogreen "ls $CROSS_TOOL/i686-none-linux-gnu/lib/ldscripts"
	ls $CROSS_TOOL/i686-none-linux-gnu/lib/ldscripts
	echogreen "ls $CROSS_TOOL/i686-none-linux-gnu/bin"
	ls $CROSS_TOOL/i686-none-linux-gnu/bin
	echogreen "ls $CROSS_TOOL/bin"
	ls $CROSS_TOOL/bin
	echogreen "### finish binutils build"
}

binutils

20200204_114029_40

  • ../binutils-2.23.1/configure 这种编译方式可以把生成文件单独放到另一个文件夹下,当前PWD是binutils-build
  • 把binutils-build删除就相当于删除了中间文件,对原来的工程目录没有任何改动
vita@vita:/vita/build/binutils-build$ make
vita@vita:/vita/build/binutils-build$ make install

20190910_225941_43

binutils安装的链接脚本和二进制工具

20190910_230109_43

20200204_114917_11

20190910_230652_64

20190910_230923_37

vita@vita:/vita/cross-tool$ ls bin/
i686-none-linux-gnu-addr2line   i686-none-linux-gnu-gcov
i686-none-linux-gnu-ar          i686-none-linux-gnu-gprof
i686-none-linux-gnu-as          i686-none-linux-gnu-ld
i686-none-linux-gnu-c++         i686-none-linux-gnu-ld.bfd
i686-none-linux-gnu-c++filt     i686-none-linux-gnu-nm
i686-none-linux-gnu-cpp         i686-none-linux-gnu-objcopy
i686-none-linux-gnu-elfedit     i686-none-linux-gnu-objdump
i686-none-linux-gnu-g++         i686-none-linux-gnu-ranlib
i686-none-linux-gnu-gcc         i686-none-linux-gnu-readelf
i686-none-linux-gnu-gcc-4.7.2   i686-none-linux-gnu-size
i686-none-linux-gnu-gcc-ar      i686-none-linux-gnu-strings
i686-none-linux-gnu-gcc-nm      i686-none-linux-gnu-strip
i686-none-linux-gnu-gcc-ranlib  pkg-config
vita@vita:/vita/cross-tool$ ls i686-none-linux-gnu/bin/
ar  as  c++  g++  gcc  ld  ld.bfd  nm  objcopy  objdump  ranlib  strip

编译freestanding的交叉编译器

  • 一个理解freestanding和hostd形象例子,其实很简单,就现在啃老现象来说。一个娃,成年后,如果能够自给自足,有份稳定工作,经济独立,他这一辈子能够做到 生存 + 独立
  • 如果连经济都独立不了,只能靠父母 == 啃老,也还是能活的好好地。他就只完成了 生存
  • 说到底其实就是个依赖关系
  • freestanding其实就是独立 + 生存。我不依赖于本地C库,那么我就独立,就这么简单
  • 所谓鸡生蛋蛋生鸡的问题,其实这里并没有解释清楚。无非就是,新工具链由旧工具链生成。。说那么复杂,郁闷

20190911_095406_83

20190911_095900_80


20190911_112228_60

编译过程,例行公事

#!/bin/bash

set -e

source functions

function freestandinggcc(){

	cd /vita/build/

	test -d  gcc-4.7.2 && /bin/rm -rf gcc-4.7.2
	tar -xf ../source/gcc-4.7.2.tar.bz2

	cd gcc-4.7.2/

	tar -xf ../../source/gmp-5.0.5.tar.bz2
	test -d gmp &&  /bin/rm -rf gmp
	/bin/mv -f  gmp-5.0.5 gmp

	tar -xf ../../source/mpfr-3.1.1.tar.bz2  
	test -d mpfr && /bin/rm -rf mpfr
	/bin/mv -f  mpfr-3.1.1 mpfr

	tar -xf ../../source/mpc-1.0.1.tar.gz
	test -d mpc && /bin/rm -rf mpc
	/bin/mv -f  mpc-1.0.1 mpc

	test -d /vita/build/gcc-build && /bin/rm -rf /vita/build/gcc-build
	mkdir /vita/build/gcc-build  && cd /vita/build/gcc-build

	../gcc-4.7.2/configure  --prefix=$CROSS_GCC_TMP \
				--target=$TARGET \
				--with-sysroot=$SYSROOT \
				--with-newlib \
				--enable-languages=c \
				--with-mpfr-include=/vita/build/gcc-4.7.2/mpfr/src \
				--with-mpfr-lib=/vita/build/gcc-build/mpfr/src/.libs \
				--disable-shared --disable-threads \
				--disable-decimal-float --disable-libquadmath \
				--disable-libmudflap --disable-libgomp \
				--disable-nls --disable-libssp 2>&1 | tee log.configure.gcc

	make ${SPEEDUP} 2>&1 | tee log.make.gcc

	make ${SPEEDUP} install 2>&1 | tee log.makeinstall.gcc

	cd /vita/cross-gcc-tmp
	ln -sfv libgcc.a lib/gcc/i686-none-linux-gnu/4.7.2/libgcc_eh.a

	echogreen "ls /vita/cross-gcc-tmp"
	/vita/cross-gcc-tmp

	echogreen "### finish freestanding gcc build"
}

freestandinggcc

20200204_133425_37

cd /vita/cross-gcc-tmp
ln -sv libgcc.a lib/gcc/i686-none-linux-gnu/4.7.2/libgcc_eh.a

20200204_133526_72

安装内核头文件linux-3.7.4

20190911_114434_12

20190911_115217_71

内核头文件编译过程中会报错。没有找到.config文件

20190911_115506_52

make menuconfig一个,但是又报错,缺少ncurse库,apt安装一下依赖

20190911_115608_66

root@vita:/vita/cross-gcc-tmp# apt-get install libncurses5-dev -y

还可以生成默认配置文件

make defconfig

书上有个巨大的错误,作者也勘误了。

20190911_125025_59

20190911_125226_51

#!/bin/bash

set -e

source functions

function kernelheaders(){
	cd /vita/build
	test -d linux-3.7.4 && /bin/rm -rf linux-3.7.4
	tar -xf ../source/linux-3.7.4.tar.xz

	cd /vita/build/linux-3.7.4
	make mrproper 2>&1 | tee log.mrproper

	make ARCH=i386 headers_check 2>&1  | tee log.make.headers_check

	make defconfig

	make ARCH=i386 INSTALL_HDR_PATH=$SYSROOT/usr/  headers_install ${SPEEDUP} 2>&1 | tee log.make.headers

	echogreen "ls $SYSROOT/usr/include"
	ls $SYSROOT/usr/include
	echogreen "### finish kernel head build"

}

kernelheaders

20200204_134523_18

20190911_125348_85

  • 内核头文件定义了,用户态库函数调用系统调用的入口。
  • 用户态程序如何跟内核打交道,通道就是系统调用,但是直接搞系统调用太麻烦,毕竟系统调用不超过512个,也就两三百个,所以一般都会封装,一层一层封装起来。一个库函数可能分装N多个系统调用。

开启多线程编译

make -j ${NUM_OF_CPU_CORE}

20190911_120638_49

make指定参数可以开启多线程编译,一般指定CPU核心数目-1

20190911_120752_18

编译目标系统的C库

20190911_125748_27

  • windows下有个概念叫运行时库,其实就是这个意思,要跑起来就必须要这个库
  • 有没有不依赖库的程序,有,但是,啥事也干不了

安装Glibc适配的awk版本

sudo apt-get install gawk -y

PS:如果你开启上网代理的话,谨慎使用sudo哦~~

20190911_140911_73

glibc编译

20190911_141146_50

  • 例行公事,然而。。。

20190911_153614_30

 ../glibc-2.15/configure --prefix=/usr --host=$TARGET    --enable-kernel=3.7.4 --enable-add-ons      --with-headers=$SYSROOT/headers_include/include   libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes    libc_cv_ctors_headers=yes

这个错误很尴尬,应该是libc_cv_ctors_header 而不是 libc_cv_ctors_headers。失之毫厘谬以千里。在configure的时候不会处理未知的参数,也不会报错咋地,这很尴尬。所以要多检查几遍

#!/bin/bash

set -e

source functions

function glibc(){

        cd /vita/build

        test -d glibc-2.15 && /bin/rm -rf glibc-2.15
        tar -xf ../source/glibc-2.15.tar.xz

        cd glibc-2.15
        patch -p1 < ../../source/glibc-2.15-cpuid.patch 2>&1 | tee log.glibc.patch.cpuid
        patch -p1 < ../../source/glibc-2.15-s_frexp.patch 2>&1 | tee log.glibc.patch.frexp


        mkdir -p /vita/build/glibc_build
        cd /vita/build/glibc_build
        echogreen $TARGET
        echogreen $SYSROOT
        ../glibc-2.15/configure --prefix=/usr --host=$TARGET \
                                --enable-kernel=3.7.4 --enable-add-ons \
                                --with-headers=$SYSROOT/usr/include \
                                libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes \
                                libc_cv_ctors_header=yes 2>&1 | tee log.configure.glibc

        make ${SPEEDUP}  2>&1 | tee log.make.glibc

        make ${SPEEDUP} install_root=$SYSROOT install 2>&1 | tee log.makeinstall.glibc
        echo "ls $SYSROOT/lib"
        ls $SYSROOT/lib
        echogreen "### finished glibc build"
}

glibc

20190911_165732_68

这个glibc编译需要花蛮长时间,骚等。。。

Glibc主要安装文件

20190911_165819_66

20190911_165831_40

构建完整的交叉编译器

因为依赖关系,先构建残缺的GCC编译器,然后构建C库,然后在已经构建的C库基础上重新构建GCC编译器

20190911_171045_80

#!/bin/bash

set -e

source functions

function fullgcc(){

	cd /vita/build/

	test -d  gcc-4.7.2 && /bin/rm -rf gcc-4.7.2
	tar -xf ../source/gcc-4.7.2.tar.bz2

	cd gcc-4.7.2/

	tar -xf ../../source/gmp-5.0.5.tar.bz2
	test -d gmp &&  /bin/rm -rf gmp
	/bin/mv -f  gmp-5.0.5 gmp

	tar -xf ../../source/mpfr-3.1.1.tar.bz2  
	test -d mpfr && /bin/rm -rf mpfr
	/bin/mv -f  mpfr-3.1.1 mpfr

	tar -xf ../../source/mpc-1.0.1.tar.gz
	test -d mpc && /bin/rm -rf mpc
	/bin/mv -f  mpc-1.0.1 mpc

	cd /vita/build/

        test -d fullgcc-build && /bin/rm -rf fullgcc-build
	mkdir fullgcc-build && cd fullgcc-build

        ../gcc-4.7.2/configure \
                --prefix=$CROSS_TOOL --target=$TARGET \
                --with-sysroot=$SYSROOT \
                --with-mpfr-include=/vita/build/gcc-4.7.2/mpfr/src \
                --with-mpfr-lib=/vita/build/fullgcc-build/mpfr/src/.libs \
                --enable-languages=c,c++ --enable-threads=posix 2>&1 | tee log.fullcompiler

        make ${SPEEDUP} 2>&1 | tee log.make.fullcompiler

        make ${SPEEDUP} install 2>&1 | tee log.makeinstall.fullcompiler

	echogreen "### finish full gcc build"
}


fullgcc

20190911_172134_92

完整编译器的组成部分

20200204_141750_29

20200204_141825_43

定义工具链相关的环境变量

20190911_172232_85

  • 工具链中定义了很多变量,通过变量来获取相应的依赖路径
  • 我们从无到有编译的交叉编译器,默认是不会使用的,但是如果修改了环境变量,那么编译的时候就能生效
vita@vita:/vita/scripts$ cat crosscompiler
export HOST=i686-pc-linux-gnu
export BUILD=$HOST
export TARGET=i686-none-linux-gnu
export CROSS_TOOL=/vita/cross-tool
export CROSS_GCC_TMP=/vita/cross-gcc-tmp
export SYSROOT=/vita/sysroot
export CC="$TARGET-gcc"
export CXX="$TARGET-g++"
export AR="$TARGET-ar"
export AS="$TARGET-as"
export RANLIB="$TARGET-ranlib"
export LD="$TARGET-ld"
export STRIP="$TARGET-strip"
export DESTDIR=$SYSROOT

20200204_203951_20

  • pkg-config其实就是搜查大使,编译器找不到的东西就问pkg-config找,有就继续编译,没有就歇菜

对于一个比较大第三方库,其头文件和库文件的数量是比较多的。如果我们一个个手动地写,那将是相当麻烦的。所以,pkg-config就应运而生了。pkg-config能够把这些头文件和库文件的位置指出来,给编译器使用。如果你的系统装有gtk,可以尝试一下下面的命令$pkg-config --cflags gtk+-2.0。可以看到其输出是gtk的头文件的路径。

我们平常都是这样用pkg-config的。

$gcc main.c `pkg-config --cflags --libs gtk+-2.0` -o main

上面的编译命令中,pkg-config --cflags --libs gtk+-2.0的作用就如前面所说的,把gtk的头文件路径和库文件列出来,让编译去获取。--cflags和--libs分别指定头文件和库文件。

#!/bin/bash

set -e

source functions

cat > /vita/cross-tool/bin/pkg-config << EOF
#!/bin/bash
HOST_PKG_CFG=/usr/bin/pkg-config

if [ ! $SYSROOT ];then
	echo "Please make sure you are in cross-comile environment!"
	exit 1
fi

$HOST_PKG_CFG --exists $*
if [ $? -ne 0 ];then
	exit 1
fi

if $HOST_PKG_CFG $* | sed -e "s/-I/-I\/vita\/sysroot/g; \
	s/-L/-L\/vita\/sysroot/g"
then
	exit 0
else
	exit 1
fi
EOF

chmod a+x /vita/cross-tool/bin/pkg-config
ls -alh  /vita/cross-tool/bin/pkg-config
find $SYSROOT -name "*.la" -exec rm -f '{}' \;
echogreen "### finish pkg-config generate"

20190911_183746_46

20200204_204638_87

  • 因为配置了PATH环境变量,默认修改后的 pkg-config 优先执行

20190911_185354_89

  • 只有系统安装了的库才会被检索到,而且是根据环境变量$PKG_CONFIG_LIBDIR来的
  • 其实这个命令指示帮你找到链接库的未知,然后以gcc可以识别的命令呈现

20190911_185610_33

libtool

20190911_185701_90

20190911_185931_25

libtool 是一个通用库支持脚本(/usr/bin/libtool),将使用动态库的复杂性隐藏在统一、可移植的接口中。

可以在不同平台上创建并调用动态库,我们可以认为libtool是gcc的一个抽象,也就是说,它包装了gcc或者其他的任何编译器,用户无需知道细节, 只要告诉libtool说我需要要编译哪些库即可,并且,它只与libtool文件打交道,例如lo、la为后缀的文件。

libtool生成一个抽象的后缀名为la高层库libxx.la(其实是个文本文件),并将该库对其它库的依赖关系,都写在该la的文 件中。该文件中的dependency_libs记录该库依赖的所有库(其中有些是以.la文件的形式加入的);libdir则指出了库的安装位 置;library_names记录了共享库的名字;old_library记录了静态库的名字。

  • libtool 用来辅助链接,但是并不包括工具链内,但是工具链有需要用到它,结果他是hosted环境下的,如果用libtool进行链接,就会找错库的位置。难道没有环境变量可以用来修改libtool??书上说的可以直接修改la文件,或者直接删掉对应的辅助链接文件*.la 。之后真正链接就会根据环境变量去找。简单粗暴
find $SYSROOT -name "*.la" -exec rm -f '{}' \;

启动代码

20190911_190659_75

20190911_191235_10

  • 其实这块就是反汇编的知识,学逆向的基本都知道
  • 程序执行之前,堆栈环境,函数本质入口探讨

20190911_191557_15

20190911_191616_50

Glibc程序入口处理代码

20190911_191646_99

20190911_191811_78

20190911_192112_60

20190911_193255_23

修改启动代码小实验

root@vita:/vita/source/demo/chap2# cat foo.c
#include <stdio.h>

void myinit(int argc, char **argv, char **envp) {
	printf("%s\n", __FUNCTION__);
}

__attribute__((section(".init_array"))) typeof(myinit) *__myinit = myinit;

void test()
{
	printf("%s\n",__FUNCTION__);
}

root@vita:/vita/source/demo/chap2# cat bar.c
#include <stdio.h>

void main()
{
	printf("Enter main.\n");
	test();
}
root@vita:/vita/source/demo/chap2# vim foo.c
root@vita:/vita/source/demo/chap2# vim bar.c
root@vita:/vita/source/demo/chap2# gcc bar.c -o bar -L./ -lfoo
root@vita:/vita/source/demo/chap2# LD_LIBRARY_PATH=./ ./bar
myinit
Enter main.
test

20190911_200543_77

20190911_200440_92

书上这里是在搞笑么??

一键搞事情脚本

针对本书第二章的所有软件安装,可以通过脚本触发各个 shell 函数 onekey 执行

1.放到/vita目录下,chmod a+x 赋予执行权限 2.提前准备好source,github仓库目录下有,包括所有软件包

#!/bin/bash

set -e

./mk-binutils.sh && ./mk-freestandinggcc.sh && ./mk-kernelhead.sh && ./mk-glibc.sh && ./mk-fullgcc.sh && ./gen-pkgconfig.sh

装逼截图

20190911_202443_34

20190911_202458_76

20190911_210006_61

20190911_210139_52

所有编译脚本

#!/bin/bash

set -e

unset LANG
export HOST=i686-pc-linux-gnu
export BUILD=$HOST
export TARGET=i686-none-linux-gnu
export CROSS_TOOL=/vita/cross-tool
export CROSS_GCC_TMP=/vita/cross-gcc-tmp
export SYSROOT=/vita/sysroot
PATH=$CROSS_TOOL/bin:$CROSS_GCC_TMP/bin:/sbin/:/usr/sbin:$PATH

CORES=`grep processor /proc/cpuinfo |wc -l`
SPEEDUP=" -j ${CORES}"


function basicenv()
{
	unset LANG
	export HOST=i686-pc-linux-gnu
	export BUILD=$HOST
	export TARGET=i686-none-linux-gnu
	export CROSS_TOOL=/vita/cross-tool
	export CROSS_GCC_TMP=/vita/cross-gcc-tmp
	export SYSROOT=/vita/sysroot
	PATH=$CROSS_TOOL/bin:$CROSS_GCC_TMP/bin:/sbin/:/usr/sbin:$PATH


	grep 'unset LANG' ~/.bashrc || echo 'unset LANG' >> ~/.bashrc
	grep 'export HOST=i686-pc-linux-gnu' ~/.bashrc || echo 'export HOST=i686-pc-linux-gnu' >> ~/.bashrc
	grep 'export BUILD=$HOST' ~/.bashrc || echo 'export BUILD=$HOST' >> ~/.bashrc
	grep 'export TARGET=i686-none-linux-gnu' ~/.bashrc || echo 'export TARGET=i686-none-linux-gnu' >> ~/.bashrc
	grep 'export CROSS_TOOL=/vita/cross-tool' ~/.bashrc || echo 'export CROSS_TOOL=/vita/cross-tool' >> ~/.bashrc
	grep 'export CROSS_GCC_TMP=/vita/cross-gcc-tmp' ~/.bashrc || echo 'export CROSS_GCC_TMP=/vita/cross-gcc-tmp' >> ~/.bashrc
	grep 'export SYSROOT=/vita/sysroot' ~/.bashrc || echo 'export SYSROOT=/vita/sysroot' >> ~/.bashrc
	grep 'PATH=$CROSS_TOOL/bin:$CROSS_GCC_TMP/bin:/sbin/:/usr/sbin:$PATH' ~/.bashrc || echo 'PATH=$CROSS_TOOL/bin:$CROSS_GCC_TMP/bin:/sbin/:/usr/sbin:$PATH' >> ~/.bashrc

	echo  -e "\e[32m\e[1m ========== finish basic environment build =================================  \e[0m"
}

function checkout(){
	if [ ${PIPESTATUS[0]} -ne 0 ];then
		echo  -e "\e[31m\e[1m ===========================================  \e[0m"
		echo  -e "\e[31m\e[1m  Error!please checkout it. [$1]  \e[0m"
		echo  -e "\e[31m\e[1m ===========================================  \e[0m"
		exit 1
	fi
}

function aptinstall(){
	apt-get update
	apt-get install  xorg-dev xserver-xephyr lrzsz \
			 libgtk-3-dev 	openssh-server \
			 libncurses5-dev build-essential \
			 texinfo autoconf gawk tree g++ \
			 m4 gcc-multilib htop libtool  xsltproc -y
	checkout apt-get
	echo  -e "\e[32m\e[1m ========== finish apt install  =================================  \e[0m"
}

function binutils(){
	cd /vita/build

	test -d /vita/build/binutils-2.23.1 && /bin/rm -rf binutils-2.23.1
	tar -xf ../source/binutils-2.23.1.tar.bz2
	checkout log.xf.binutils

	test -d binutils-build && /bin/rm -rf binutils-build
	mkdir binutils-build && cd binutils-build


	../binutils-2.23.1/configure --prefix=$CROSS_TOOL --target=$TARGET --with-sysroot=$SYSROOT  2>&1 | tee log.configure.binutils
	checkout log.configure.binutils

	make ${SPEEDUP}  2>&1 | tee log.make.binutils
	checkout log.make.binutils

	make ${SPEEDUP} install 2>&1 | tee log.makeinstall.binutils
	checkout log.makeinstall.binutils

	echo  -e "\e[32m\e[1m ========== finish binutils build =================================  \e[0m"
}

function gcc(){

	cd /vita/build/

	test -d  gcc-4.7.2 && /bin/rm -rf gcc-4.7.2
	tar -xf ../source/gcc-4.7.2.tar.bz2
	checkout log.xf.gcc

	cd gcc-4.7.2/
	tar -xf ../../source/gmp-5.0.5.tar.bz2
	checkout log.xf.gmp
	test -d gmp &&  /bin/rm -rf gmp
	/bin/mv -f  gmp-5.0.5 gmp

	tar -xf ../../source/mpfr-3.1.1.tar.bz2  
	checkout log.xf.mpfr
	test -d mpfr && /bin/rm -rf mpfr
	/bin/mv -f  mpfr-3.1.1 mpfr

	tar -xf ../../source/mpc-1.0.1.tar.gz
	checkout log.xf.mpc
	test -d mpc && /bin/rm -rf mpc
	/bin/mv -f  mpc-1.0.1 mpc

	test -d /vita/build/gcc-build && /bin/rm -rf /vita/build/gcc-build
	mkdir /vita/build/gcc-build  && cd /vita/build/gcc-build

	../gcc-4.7.2/configure  --prefix=$CROSS_GCC_TMP \
				--target=$TARGET \
				--with-sysroot=$SYSROOT \
				--with-newlib \
				--enable-languages=c \
				--with-mpfr-include=/vita/build/gcc-4.7.2/mpfr/src \
				--with-mpfr-lib=/vita/build/gcc-build/mpfr/src/.libs \
				--disable-shared --disable-threads \
				--disable-decimal-float --disable-libquadmath \
				--disable-libmudflap --disable-libgomp \
				--disable-nls --disable-libssp 2>&1 | tee log.configure.gcc
	checkout log.configure.gcc

	make ${SPEEDUP} 2>&1 | tee log.make.gcc
	checkout log.make.gcc

	make ${SPEEDUP} install 2>&1 | tee log.makeinstall.gcc
	checkout log.makeinstall.gcc


	cd /vita/cross-gcc-tmp
	ln -sfv libgcc.a lib/gcc/i686-none-linux-gnu/4.7.2/libgcc_eh.a  2>&1 | tee log.ln.libgcc
	checkout log.ln.libgcc

	echo  -e "\e[32m\e[1m =========== finish gcc build =====================================  \e[0m"
}

function kernelheaders(){

	cd /vita/build
	test -d linux-3.7.4 && /bin/rm -rf linux-3.7.4
	tar -xf ../source/linux-3.7.4.tar.xz
	checkout log.xf.linux

	cd /vita/build/linux-3.7.4
	make mrproper 2>&1 | tee log.mrproper
	checkout log.mrproper

	make ARCH=i386 headers_check 2>&1  | tee log.make.headers_check
	checkout log.make.headers_check

	make defconfig

	make ARCH=i386 INSTALL_HDR_PATH=$SYSROOT/usr/  headers_install ${SPEEDUP} 2>&1 | tee log.make.headers


	echo  -e "\e[32m\e[1m ========== finish kernel headers build ===========================  \e[0m"

}

function glibc(){

	cd /vita/build

	test -d glibc-2.15 && /bin/rm -rf glibc-2.15
	tar -xf ../source/glibc-2.15.tar.xz
	checkout log.xf.glibc

	cd glibc-2.15
	patch -p1 < ../../source/glibc-2.15-cpuid.patch 2>&1 | tee log.glibc.patch.cpuid
	checkout log.glibc.patch.cpuid
	patch -p1 < ../../source/glibc-2.15-s_frexp.patch 2>&1 | tee log.glibc.patch.frexp
	checkout log.glibc.patch.frexp


	mkdir -p /vita/build/glibc_build
	cd /vita/build/glibc_build
	echo $TARGET
	echo $SYSROOT
	../glibc-2.15/configure --prefix=/usr --host=$TARGET \
				--enable-kernel=3.7.4 --enable-add-ons \
				--with-headers=$SYSROOT/usr/include \
				libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes \
				libc_cv_ctors_header=yes 2>&1 | tee log.configure.glibc
	checkout log.configure.glibc

	make ${SPEEDUP}  2>&1 | tee log.make.glibc
	checkout log.make.glibc

	make ${SPEEDUP} install_root=$SYSROOT install 2>&1 | tee log.makeinstall.glibc
	checkout log.makeinstall.glibc
	echo  -e "\e[32m\e[1m ========== finish glibc build =====================================  \e[0m"
}

function fullcompiler(){
	cd /vita/build/gcc-build
	/bin/rm -rf /vita/build/gcc-build/*
	../gcc-4.7.2/configure \
		--prefix=$CROSS_TOOL --target=$TARGET \
		--with-sysroot=$SYSROOT \
		--with-mpfr-include=/vita/build/gcc-4.7.2/mpfr/src \
		--with-mpfr-lib=/vita/build/gcc-build/mpfr/src/.libs \
		--enable-languages=c,c++ --enable-threads=posix 2>&1 | tee log.fullcompiler
	checkout log.fullcompiler

	make ${SPEEDUP} 2>&1 | tee log.make.fullcompiler
	checkout log.make.fullcompiler

	make ${SPEEDUP} install 2>&1 | tee log.makeinstall.fullcompiler
	checkout log.makeinstall.fullcompiler

	echo  -e "\e[32m\e[1m ========== finish fullcompiler build =============================  \e[0m"
}

function defineenv(){

	export CC="$TARGET-gcc"
	export CXX="$TARGET-g++"
	export AR="$TARGET-ar"
	export AS="$TARGET-as"
	export RANLIB="$TARGET-ranlib"
	export LD="$TARGET-ld"
	export STRIP="$TARGET-strip"

	export DESTDIR=$SYSROOT
	unset PKG_CONFIG_PATH
	export PKG_CONFIG_LIBDIR=$SYSROOT/usr/lib/pkgconfig:SYSROOT/usr/share/pkgconfig

	grep 'export CC="$TARGET-gcc"' ~/.bashrc || echo 'export CC="$TARGET-gcc"' >> ~/.bashrc
	grep 'export CXX="$TARGET-g++"' ~/.bashrc || echo 'export CXX="$TARGET-g++"' >> ~/.bashrc
	grep 'export AR="$TARGET-ar"' ~/.bashrc || echo 'export AR="$TARGET-ar"' >> ~/.bashrc
	grep 'export AS="$TARGET-as"' ~/.bashrc || echo 'export AS="$TARGET-as"' >> ~/.bashrc
	grep 'export RANLIB="$TARGET-ranlib"' ~/.bashrc || echo 'export RANLIB="$TARGET-ranlib"' >> ~/.bashrc
	grep 'export LD="$TARGET-ld"' ~/.bashrc || echo 'export LD="$TARGET-ld"' >> ~/.bashrc
	grep 'export STRIP="$TARGET-strip"' ~/.bashrc || echo 'export STRIP="$TARGET-strip"' >> ~/.bashrc
	grep 'export DESTDIR=$SYSROOT' ~/.bashrc || echo 'export DESTDIR=$SYSROOT' >> ~/.bashrc
	grep 'unset PKG_CONFIG_PATH' ~/.bashrc || echo 'unset PKG_CONFIG_PATH' >> ~/.bashrc
	grep 'export PKG_CONFIG_LIBDIR=$SYSROOT/usr/lib/pkgconfig:SYSROOT/usr/share/pkgconfig' ~/.bashrc || echo 'export PKG_CONFIG_LIBDIR=$SYSROOT/usr/lib/pkgconfig:SYSROOT/usr/share/pkgconfig' >> ~/.bashrc

	echo  -e "\e[32m\e[1m ========== finish define environment  =============================  \e[0m"
}

function pkgconfig(){

	FILE=/vita/cross-tool/bin/pkg-config
	/bin/cat << EOF > ${FILE}
#!/bin/bash
HOST_PKG_CFG=/usr/bin/pkg-config

if [ ! \$SYSROOT ];then
	echo "Please make sure you are in cross-comile environment!"
	exit 1
fi

\$HOST_PKG_CFG --exists \$*
if [ \$? -ne 0 ];then
	exit 1
fi

if \$HOST_PKG_CFG \$* | sed -e "s/-I/-I\/vita\/sysroot/g; \\
	s/-L/-L\/vita\/sysroot/g"
then
	exit 0
else
	exit 1
fi
EOF
	chmod a+x ${FILE}

	echo  -e "\e[32m\e[1m ========== finish pkg-config =============================  \e[0m"
}

function main()
{
	basicenv
	aptinstall
	binutils
	gcc
	kernelheaders
	glibc
	fullcompiler
	defineenv
	pkgconfig
}

main

参考

小总结

  1. 我算知道configure尿性。错误选项参数不会报错。
  2. 如果有网络代理的话,sudo会有一定影响(不会传递普通用户的环境变量,需要修改/etc/sudoers),有时候不用sudo反而靠谱