zoukankan      html  css  js  c++  java
  • Linux 交叉编译工具链

    本文连接:http://blog.chinaunix.net/uid-2630593-id-2138544.html

    搞了一个“中基学生电脑”(详细的见这里http://www.ouravr.com/bbs /bbs_content.jsp?bbs_sn=1420850&bbs_page_no=1&search_mode=4& search_text=dack&bbs_id=9999),当作arm开发板用。但本人对linux不熟,arm更是没有搞过,所以从头开始 学,先编译一套工具链才能进行下一步。
    了解到有crosstools可以方便的编译工具链,甚至还有编译好的下载,但是鉴于本人初学,什么都不懂,决定还是自己一步一步编译,权当熟 悉linux,熟悉一下编译流程了。花了一个多星期终于搞好了,其实第一次编译成功用了不到一个星期,为了写这篇文章和搞清楚其中的一些不明所以的地方, 又重新编译了两次,现在基本搞清楚了,发上来与大家共享。其实还有一些不明所以的地方,以后再说吧,实在不想再编译了。
    中基是基于sa1110芯片的,主要部分和assabet开发板一样。以下linux头文件是基于这样的系统产生的,不过我想也能用于其他型号的芯片。
    先说说我的编译环境,一台384M内存的p4电脑,win2000系统,开vmware虚拟机,装了一个puppy linux 3.01,这个linux以小巧见称。可想而知有多慢了。
    个人感觉,编译这个很考人品,人品不好总会碰到一些稀奇古怪的问题。呵呵,我估计是那个人品最差的。
    虽然我已经很小心,最后一遍命令都是粘贴上去执行的,后面又进行了一些修改,主要是安装目录,但文中难免有错漏,发现了请指出。
    初学者可以尝试自己编译工具链,能够学到一下东西。
    所有用到的软件都是最新版的。
    好了,闲话少说,开干。

    1.下载
    ftp://mirrors.kernel.org/gnu/binutils/binutils-2.18.tar.gz
    ftp://mirrors.kernel.org/gnu/gcc/gcc-4.3.2/gcc-4.3.2.tar.gz
    ftp://mirrors.kernel.org/gnu/gdb/gdb-6.8.tar.gz
    ftp://mirrors.kernel.org/gnu/glibc/glibc-2.7.tar.gz
    ftp://mirrors.kernel.org/gnu/glibc/glibc-ports-2.7.tar.gz
    http://ftp.osuosl.org/pub/clfs/conglomeration/glibc/glibc-2.7-libgcc_eh-1.patch
    ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.27.tar.gz
    http://www.mpfr.org/mpfr-current/mpfr-2.3.2.tar.gz
    ftp://ftp.gmplib.org/pub/gmp-4.2.4.tar.gz

    2.建立工作目录
    我的工作目录放在一个单独的盘上,/mnt/hdc1。你可以任选一个目录做工作目录,例如~/work。将下载的文件全部放到工作目录下。
    工作目录中建立目录build,用来放解压后的源码和build时产生的文件,最终产生的工具放到/usr/armtools下。
    3.设置环境变量
    在etc/ld.so.conf中加上一行/usr/local/lib,用来设置动态库的搜索目录,已经有的话就不用加了,因为gmp和mpfr会装到这里,不加以后的编译通不过。
    开一个终端窗口
    export TARGET=arm-linux
    export PREFIX=/usr/armtools
    export PATH=$PATH:/usr/armtools/bin
    export BUILD_DIR=/mnt/hdc1/build
    4.安装gmp和mpfr库,这两个库是gcc需要的,老版本如果不用fortan77的话不需要,但新版本只编译c也需要。有的话就不用装了。
    cd /mnt/hdc1 进入工作目录
    cd build
    tar -zxvf ../gmp-4.2.4.tar.gz 这里有个技巧,打完gm后直接按tab键文件名会自动补全。后面需要输入目录的地方都可以这么用。
    cd gmp-4.2.4
    ./configure
    make
    make check 文档里说这个非常重要。
    make install
    cd ..
    rm -rf gmp-4.2.4 装完源目录没用了,删掉,节省空间。

    ldconfig /usr/local/bin
    tar -zxvf ../mpfr-2.3.2.tar.gz 这里有个技巧,打完gm后直接按tab键文件名会自动补全。后面需要输入目录的地方都可以这么用。
    cd mpfr-2.3.2
    ./configure
    make
    make check 文档里说这个非常重要。
    make install
    cd ..
    rm -rf mpfr-2.3.2 装完源目录没用了,删掉,节省空间。

    ldconfig /usr/local/bin 更新一下缓存
    完成,这一步一般不会出问题。
    5.编译binutils
    tar -zxvf ../binutils-2.18.tar.gz
    mkdir binutils-2.18-build
    cd binutils-2.18-build
    ../binutils-2.18/configure --target=$TARGET --prefix=$PREFIX
    make
    make install
    cd ..
    rm -rf binutils-2.18
    rm -rf binutils-2.18-build
    ok,这一步也很简单,完成后armtools里会有很多文件。
    6.编译bootstrap gcc
    tar -zxvf ../gcc-4.3.2.tar.gz
    mkdir gcc-4.3.2-build
    cd gcc-4.3.2-build
    ../gcc-4.3.2/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c --with-local-prefix=$PREFIX/arm-linux --without-headers --with-newlib --disable-shared --disable-threads --disable-libmudflap --disable-libssp
    这一步参数比较多,大概说一下
    --target=$TARGET 目标,arm-linux,就是要产生linux下编译arm程序的编译器
    --prefix=$PREFIX 安装目录
    --enable-languages=c 只产生c编译器
    --with-local-prefix=$PREFIX/arm-linux 不知道有啥用,实在不想再编译一遍试验了,谁有空可以试试不加行不行。
    --without-headers 不使用头文件,因为还没有glibc
    --with-newlib 这个不太明白,似乎是编译一个自带的库
    --disable-shared 不编译共享库
    --disable-threads 不编译线程支持
    --disable-libmudflap 禁止mudflap库,这个库需要glibc支持
    --disable-libssp 禁止ssp库,这个库需要glibc支持

    make all-gcc 编译安装gcc
    make install-gcc
    make all-target-libgcc 编译安装库,不做的话编译glibc时找不到库
    make install-target-libgcc
    cd ..
    rm -rf gcc-4.3.2-build
    7.建立linux头文件
    tar -zxvf ../linux-2.6.27.tar.gz
    cd linux-2.6.27
    make ARCH=arm menuconfig
    菜单最下面选择load一个arm板子的config文件,我load的arch/arm/configs/assabet_defconfig,然后保存为.config。退出
    make ARCH=arm CROSS_COMPILE=$PREFIX/bin/arm-linux- 出现CC什么的时候就可以停止了。
    cd ..
    2.6.27版和2.6.26.5版比目录结构发生了变化,所以编译glibc时要改路径,否则找不到头文件。编译glibc时候用到了特定arm芯片(例如我用的sa1100)的头文件,难道编译出来的glibc只能用在特定的芯片上吗,有知道的说一下。
    8.编译glibc
    tar -zxvf ../glibc-2.7.tar.gz
    cd glibc-2.7
    tar -zxvf ../../glibc-ports-2.7.tar.gz glibc本身是不支持arm等的,需要加这个port。
    mv glibc-ports-2.7 ports
    打补丁,sed -i 's/aaa/bbb/' file 就是把file里的aaa替换成bbb,bbb里面的&代表 aaa, 代表tab, 代表换行。你也可以用文本编辑器来做,用sed做要注意不要打错任何一个字符,空格啦,大小写啦都要注意。
    sed -i 's/-nostdinc -isystem $ccheaders /-nostdinc -isystem $ccheaders -isystem $ccheaders-fixed /' configure.in
    sed -i 's/-isystem $cxxheaders /-isystem $cxxheaders -isystem $cxxheaders-fixed /' configure.in
    sed -i 's/# define UNDOCARGS_5 UNDOCARGS_4/& # define DOCARGS_6 UNDOCARGS_5 # define UNDOCARGS_6 UNDOCARGS_5/' ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h
    sed -i 's/#include /& #include /' ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.h
    sed -i 's/__deprecated/__attribute__((deprecated))/' ../linux-2.6.27/arch/arm/include/asm/memory.h
    patch -p1 < ../../glibc-2.7-libgcc_eh-1.patch cd .. mkdir glibc-2.7-build cd glibc-2.7-build CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib ../glibc-2.7/configure --host=$TARGET --prefix=$PREFIX/$TARGET --enable-add-ons --with-headers=$BUILD_DIR/linux-2.6.27/include:$BUILD_DIR/linux-2.6.27/arch/arm/include:$BUILD_DIR/linux-2.6.27/arch/arm/mach-sa1100/include libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes cross_compiling=yes build_alias=i386-linux-gnu 上面这句里的cross_compiling=yes build_alias=i386-linux-gnu不是必需的,我第一遍编 译时没加也通过了,但后来不知道为什么就不行了,如果出错或者make出错可以加上试试,主要是因为configure自动判定交叉编译判断错误,把交叉 编译出来的文件在本地执行,当然执行不了啦。 make make install cd .. rm -rf glibc-2.7-build rm -rf glibc-2.7 9.拷贝linux头文件 cp -r linux-2.6.27/include/linux $PREFIX/$TARGET/include cp -r linux-2.6.27/arch/arm/include/asm $PREFIX/$TARGET/include mv $PREFIX/$TARGET/include/asm $PREFIX/$TARGET/include/asm-arm cp -r -f linux-2.6.27/include/asm-arm $PREFIX/$TARGET/include cp -r linux-2.6.27/include/asm $PREFIX/$TARGET/include cp -r linux-2.6.27/include/asm-generic $PREFIX/$TARGET/include cp -r linux-2.6.27/arch/arm/mach-sa1100 $PREFIX/$TARGET/include mv $PREFIX/$TARGET/include/mach-sa1100 $PREFIX/$TARGET/include/mach 这些文件不但编译glibc gcc时有用,而且似乎在以后编译应用程序的时候也可能有用,因为glibc库的头文件里有包含他们,所以我把他们拷贝到安装目录里。 10.编译gcc mkdir gcc-4.3.2-build cd gcc-4.3.2-build ../gcc-4.3.2/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --with-local-prefix=$PREFIX/$TARGET make make install cd ../.. rm -rf build 到此,工具链就算装好了,可以写个hello world程序来试验一下了。 然后把我前面的艰辛历程贴出来,如果大家编译的时候发生什么问题,可以在里面找一下有没有我碰到过的。格式嘛,我就不排版了,大家凑活看吧。 1. 安装linux 的头文件,可以在编译glibc之前再做 * 个人认为这一步得到的头文件应该只和arm有关,和arm什么板子,什么型号没多大关系 * 解压缩,打补丁 cd ~/tars/SourceDir tar -zxf ../linux-2.4.5.tar.gz cd linux zcat ../../patch-2.4.5-rmk7.gz | patch -p1 打补丁不知道为什么出错,先不打了。原来是patch-2.6.26.5.bz2是给linux-2.6.26打补丁的,不是给2.6.26.5打补丁的 * 修改 Makefile 建议先删除 .config 文件, 否这以后会遇到麻烦。没用 * 将Makefile中ARCH := ......改为:ARCH=arm #。似乎没用 * 执行一下 make clean。一开始不需要 * 我的做法:make ARCH=arm menuconfig * 选择load一个arm板子的config文件,我load的ARCH/arm/configs/assabet_defconfig,然后保存为.config。退出 * make ARCH=arm dep * 加上ARCH=arm是因为不加的话会有好多提问,像是否支持多cpu等,后面的dep不知道什么意思,待查。 * 产生了include/linux/autoconf.h,但是没有version.h。不知道是不是现在的版本不需要。 * 网上查的make dep的意思,不过还是不太明白 * dependence 依赖。 make dep的意思就是说:如果你使用程序A(比如支持特殊设备),而A需用到B(比如B是A的一 个模块/子程序)。 而你在做make config的时候将一个设备的驱动 由内核支持改为module,或取消支持,这将可能影响到B的一个参数 的设置,需重新编译B,重新编译或连接A....如果程序数量非常多, 你是很难手工完全做好此工作的。 所以,你要make dep。如果你make menu或make config或make xconfig后,直接reboot,会更快。 只是你的内核根本没有任何改变。^=^ make xconfig; make dep; make clean; make bzImage; make modules; make modules_install * 又作了一次,发现make dep现在不起作用,要用make ARCH=arm来建立头文件。 * 要用make ARCH=arm CROSS_COMPILE=/mnt/home/arm/armtools/bin/arm-linux-来编译,必须先编译好bootstrap gcc后才能这样用 * 拷贝头文件,感觉不需要拷贝,编译glibc的时候加上路径就好了。 cp -dR include/linux ~/armtools/arm-linux/include cp -dR include/asm-arm ~/armtools/arm-linux/include/asm 1. 编译安装binutils  * 解压缩 cd ~/tars/SourceDir tar -zxf ../binutils-2.11.gz * 编译 cd ~/tars/BuildDir mkdir binutils cd binutils ../../SourceDir/binutils-2.11/configure --target=arm-linux --prefix=~/armtools make all install * 这一步没什么问题,很顺利 2. 编译安装gcc 的c 编译器   * 解压缩 cd ~/tars/SourceDir tar -zxf ../gcc-2.95.3.tar.gz * 修改gcc 的t-linux 文件在t-linux文件中的TARGET_LIBGCC2_CFLAGS上加上__gthr_posix_h inhibit_libc cd gcc-2.95.3/ gcc/config/arm mv t-linux t-linux-orig sed 's/TARGET_LIBGCC2_CFLAGS =/TARGET_LIBGCC2_CFLAGS = -D__gthr_posix_h -Dinhibit_libc/' <> t-linux-core
    cp ./t-linux-core ./t-linux

    *

    编译

    cd ~/tars/BuildDir
    mkdir gcc-core
    cd gcc-core
    ../../SourceDir/gcc-2.95.3/configure
    --target=arm-linux
    --prefix=~/armtools
    --enable-languages=c
    --with-local-prefix=~/armtools/arm-linux
    --without-headers
    --with-newlib
    --disable-shared
    make all install

    * ./configure 时需要gmp和mpfr库支持,下载,安装,顺利,已做成pet包。换了一台机重新编译的时候,发现编译mpfr的时候会出错,找不到库,还是要加上下面那个路径。
    * ./configure 通过
    * make 出错,查看arm-linux/libgcc/config.log,说找不到libmpfr.so.1,估 计是做的pet包没有将ld搜索路径加上,先加上环境变量试下,回头再修改pet包。 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
    * 加上后上个问题没有了,又有新问题。
    * config.log says:
    * configure:2747: checking for /mnt/hdc1/build/gcc-core/./gcc/xgcc -B/mnt/hdc1/build/gcc-core/./gcc/ -B/mnt/hdc1/armtools/arm-linux/bin/ -B/mnt/hdc1/armtools/arm-linux/lib/ -isystem /mnt/hdc1/armtools/arm-linux/include -isystem /mnt/hdc1/armtools/arm-linux/sys-include option to accept ANSI C
    configure:2817: /mnt/hdc1/build/gcc-core/./gcc/xgcc -B/mnt/hdc1/build/gcc-core/./gcc/ -B/mnt/hdc1/armtools/arm-linux/bin/ -B/mnt/hdc1/armtools/arm-linux/lib/ -isystem /mnt/hdc1/armtools/arm-linux/include -isystem /mnt/hdc1/armtools/arm-linux/sys-include -c -O2 -g -g -O2 conftest.c >&5
    conftest.c:10:19: error: stdio.h: No such file or directory
    conftest.c:11:23: error: sys/types.h: No such file or directory
    conftest.c:12:22: error: sys/stat.h: No such file or directory
    conftest.c:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
    conftest.c:44: error: expected declaration specifiers or '...' before 'FILE'
    configure:2823: $? = 1
    * try to add --disable-libiberty and make it
    * 上面的没用,改--disable-shared为--disable-threads,似乎这个错误过去了
    * 发现修改t-linux里的-D__gthr_posix_h这个现在已经没用了。-Dinhibit_libc这个参数似乎可以用--with-newlib代替。
    * 然后又出找不到crti.o的错误。重新加上--disable-shared,搞定
    * 然后又出问题,c编译器不能建立可执行文件。找不到crt1.o。查看发现gcc编译完后进行了编译测试,但这时候还没有这些启动文件,据说这些是编译glibc产生的。
    * configure时加上--disable-libmudflap,不加似乎也行,不要理会错误,直接make install就可以把gcc装上了。似乎有问题,make glibc的时候找不到头文件。
    * 加上--disable-libssp --disable-libgomp终于编译通过了,make install没有问题。
    * 重新make一次,不知道怎么又出错了,奇怪。而且make clean有的时候只显示几行,而有的时候显示一大堆,不知道为什么。
    * 改成make all-gcc和make install-gcc通过,不知道行不行。
    3. 编译glibc
    1. 因为现在glibc包不支持arm,所以要加上port包,解压port包到glibc原目录,改名为ports。
    2.

    CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib ../../SourceDir/glibc-2.2.3/configure --host=arm-linux
    --prefix=~/armtools/arm-linux --enable-add-ons --with-headers=~armtools/arm-linux/include

    3. 报错configure: error: forced unwind support is required
    4. 回到gcc,try make all-target-libgcc make install-target- libgcc 通过,但上述问题还在。第二次编译产生cannot compute sizeof(long double) 的错误。这个错误又好像不 是这个引起。结果是下面两句写错了。还是不对,加上--build=i686-pc-linux-gnu后通过
    5. 加上两句echo "libc_cv_forced_unwind=yes" > config.cache
    echo "libc_cv_c_cleanup=yes" >> config.cache,然后 configure加上 --cache-file=config.cache,通过。这两句可以直接把双引号里的内容写到configure后面做参 数,而不用--cache- file参数。
    6. make又出问题,找不到../include/limits.h,打补丁http://sources.redhat.com/bugzilla/show_bug.cgi?id=5442后通过。

    glibc/libc/configure.in
    if test -n "$sysheaders"; then
    ccheaders=`$CC -print-file-name=include`
    - SYSINCLUDES="-nostdinc -isystem $ccheaders
    + SYSINCLUDES="-nostdinc -isystem $ccheaders -isystem $ccheaders-fixed

    1. 再出问题,找不到errno.h,copy linux源目录下include/asm-generic到armtools/arm-linux/include下,通过
    2. /usr/local/arm-linux/include/asm/memory.h:191: error: expected '=', ',', ';', 'asm' or '__attribute' before 'unsigned'
    /usr/local/arm-linux/include/asm/memory.h:196: error: expected '=', ',', ';', 'asm' or '__attribute' before 'void'
    3. 找不到解决方法,尝试修改autoconf.h里的#define CONFIG_ENABLE_WARN_DEPRECATED 1为0,无效
    4. 找了好久,分析源码,终于找到问题所在,但在网上查不到解决办法,只能自己改了,应该不会有其它问题。这个问题的原因是 ioperm.c(port里arm 中带的)包含了linux头文件asm/page.h,page.h又包含了linux /memory.h,memory.h包含了linux /compiler.h,这里面有个条件编译,如果定义了__KERNEL__就会包含 compiler_gcc4.h等等,反正会定义一个 __deprecated属性,而如果没有定义__KERNEL__就不会定义这个属性,但是 memory.h里两次用到这个属性,结果就出问题。我的改法是把memory.h里的 __deprecated改成 __attribute__((deprecated))。第二次编译又没发现这个问题,奇怪。可能是升级了linux版本的原因。
    5. 然后不出所料,还是有问题,: Assembler messages:
    :2: Error: bad instruction `docargs_6'
    :2: Error: bad instruction `undocargs_6',这个网上有解决办法。
    6.

    改ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h里增加蓝色的两行
    # define DOCARGS_5 DOCARGS_4
    # define UNDOCARGS_5 UNDOCARGS_4

    # define DOCARGS_6 DOCARGS_5
    # define UNDOCARGS_6 UNDOCARGS_5

    # ifdef IS_IN_libpthread
    # define CENABLE bl PLTJMP(__pthread_enable_asynccancel)
    # define CDISABLE bl PLTJMP(__pthread_disable_asynccancel)

    7. lowlevelloch.c:34出问题

    在ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.h里加一行
    #include 
    #include 
    +#include 

    8. 终于make通过了,make install
    9. 通过,开始编译gcc
    10.

    ../../SourceDir/gcc-2.95.3/configure --target=arm-linux --prefix=~/armtools
    --enable-languages=c,c++ --with-local-prefix=~armtools/arm-linux

    11. make
    12. make install
    13. 成功
    14. 编译一个例子,然后准备开始第二次编译工具链
    15. 看到有新的linux,换用新的linux,结果好多问题,include/asm下的东西都移走了,移到arch/arm/include/asm下了,编译glibc又出好多新问题
    16. 第二次编译glibc产生cannot compute sizeof(long double) 的错误。这个是 configure自动识别build类型错误,并且认为不是交叉编译造成的,加上--build=i686-pc-linux-gnu后通过 configure,但make产生redefinition of '__copysign' 的错误,改成--build=i386-linux- gnu后通过
    17. 又出config-name.h找不到的问题,这个文件应该是configure产生的。
    18. 看样子是和我用虚拟机有关,编译工具链个人感觉极考人品,顺不顺利看人品了。
    19. 上面发现的问题看来是和configure检查系统环境出现偏差有关
    20. 改成CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux- ranlib ../glibc-2.7/configure --host=arm-linux --prefix=/mnt/hdc1 /armtools1 --enable-add-ons --with-headers=/mnt/hdc1/build/linux-2.6.27 /include:/mnt/hdc1/build/linux-2.6.27/arch/arm /include cross_compiling=yes build_alias=i386-linux-gnu后配置通过,make出现问题。还是 因为linux改了目录结构引起的,拷贝需要的文件后ok
    21. 在编译gcc的时候不小心输错目录,在原文件目录下进行了编译,结果出错。一定不能在源文件目录下编译。
    22. 第三次编译glibc出ld找不到-lgcc的问题,是没有make all-target-libgcc和make install-target-libgcc
    23. 找不到-lgcc_eh,原因是没打补丁,又要退回去重做。

  • 相关阅读:
    【博弈论】取火柴游戏
    【贪心】马拉松接力赛
    【贪心】0/1背包
    【贪心】赶作业
    C# 设计模式 (一)
    C# 反射入门
    C# WinForm 访问webService天气预报
    WebService 测试地址
    C# Windows服务相关
    CSS 案例学习
  • 原文地址:https://www.cnblogs.com/huazhen/p/3535580.html
Copyright © 2011-2022 走看看