前言
有一个很老嵌入式板子, 是arm9的。原厂给的交叉编译器非常老了, 版本是gcc-4.4.4。这个版本是是不支持c++11的,我想把自己写的程序移植上去,就十分困难。因为我自己的程序是使用C++11的。所以,就打算更新交叉编译器,编译一个支持c++11的编译器。
本机环境
操作系统: manjaro-deepin
gcc: 8.1.1
g++: 8.1.1
下载需要的源码
Binutils
Binutils 2.29 37.1 MB 2017/7/24 上午8:00:00
地址:
ftp://ftp.gnu.org/gnu/binutils/binutils-2.29.tar.gz
Binutils是GNU工具之一,他包括连接器、汇编器和其他用于目标文件和档案的工具,他是二进制代码的处理维护工具。安装Binutils工具包含的程式有addr2line、ar、as、c++filt、gprof、ld、nm、objcopy、objdump、ranlib、readelf、size、strings、strip、libiberty、libbfd和libopcodes
Glibc
glibc 2.20 23.8 MB 2014/9/7 上午8:00:00
地址:
ftp://ftp.gnu.org/gnu/glibc/glibc-2.20.tar.gz
glibc是gnu发布的libc库,也即c运行库。glibc是linux系统中最底层的api,几乎其它任何的运行库都会倚赖于glibc。
需要关注的是,glibc版本和kernel内核版本相关。
glibc-2.24以上版本需要内核3.1以上。我们当前的内核版本为2.6.35。所以使用了glibc-2.20
libc-linuxthreads 2.5 237 kB 2006/10/2 上午8:00:00
地址:
ftp://ftp.gnu.org/gnu/glibc/glibc-linuxthreads-2.5.tar.bz2
这个glibc-thread下载完成之后,直接解压到glibc的目录即可
GCC
gcc 5.4.0 2016/6/3 上午8:00:00
地址:
ftp://ftp.gnu.org/gnu/gcc/gcc-5.4.0/gcc-5.4.0.tar.gz
gcc是GNU编译器套件(GNU Compiler Collection),它包括了C、C++、Objective-C、Fortran、Java、Ada、Go语言的前端和这些语言的库.
我们在这里只使用c/c++的部分.
gcc-5.4.0是支持c++11的, 同时支持错误推测。所以选择这个版本
autoconf 和 automake
autoconf必须是2.64版本,否则gcc-5.4.0编译会出现问题。过高和过低都不行。
automake必须是1.11.1版本,否则gcc-5.4.0编译会出现问题。过高和过低都不行。
安装完之后,试用一下automake, 看是否报错,如果报错,参考:https://blog.csdn.net/rainforest_c/article/details/82722198
这是因为本机的perl版本比较高了,而automake旧版本则用了老语法.
这一点非常坑, 遇到时候搞了好久. 安装到临时目录后,然后export到当前的path目录
开始编译
编译Binutils
1 | tar -zxvf binutils-2.29.tar.gz |
这个参数比较简单:--prefix
安装的目标位置--target
目标机器,格式是以-
分隔,开头是芯片架构,我们是arm
. 然后是制造商,这个可以自己写. 后面的就是操作系统和运行结构--disable-nls
禁用本地化支持,应该是和语言翻译相关,不影响
第一次编译GCC
为什么是第一次,因为我们开始什么都没有,只能先编译一个最小的支持C语言的编译器。
然后用我们的这个C语言的编译器,去编译Glibc,等Glibc编译完成后,才能编译完整的GCC工具链
1 | tar -zxvf gcc-5.4.0.tar.gz |
在download_prerequisites
这个脚本里, 会下载gcc所依赖的其他库。并且在编译gcc的时候,会自动编译。
但是,脚本里的下载链接不是很好用,经常下载不了。可以在ftp://ftp.gnu.org/gnu/
里找到对应版本,进行替换,或者自己找的替换即可。
配置完依赖库之后:
1 | mkdir build |
gcc的配置比较复杂,可参考链接https://gcc.gnu.org/install/configure.html
。
在这里讲一些比较重要的。可能会配错的,也是一些坑。
--without-headers
必须添加,因为我们第一次编译,不使用操作系统头文件,所以关闭该选项--with-tune=arm926ej-s
非常重要,因为我们是交叉编译,该选项指定了交叉编译的架构,比如我那个芯片就使用了arm926ej-s。所有的选择,在文档中可查看--disable-shared
第一次编译,必须禁止shared,否则,在编译gcc库的时候,libgcc_s.so 依赖glibc,但是这个时候我们glibc还没有编译。静态链接不需要符号实现,所以只能编译静态库。--disable-threads
第一次编译,必须禁止, 因为thread需要thread.h, 这个时候还没有内核头文件。--enable-maintainer-mode
需要添加,经过采坑,该选项涉及gcc的visibility attribut
特性。而该特性在glibc-2.20编译中需要用到
其他大部分都是关闭特性,在其他的大部分教程中都有提及,就不详细说了
安装内核头文件
进入内核的目录
1 | make ARCH=arm CROSS_COMPILE=arm-sm01-linux-gnueabi- INSTALL_HDR_PATH=~/project/new_gcc/header headers_install |
INSTALL_HDR_PATH 就是安装目录地址,编译Glibc的时候要用到. 该部分较简单
编译Glibc
1 | tar -zxvf glibc-2.20.tar.gz |
然后把下面的内容, 放到config.cache文件中,这个文件可以自己创建
1 | libc_cv_forced_unwind=yes |
之后配置:
1 | ../configure --build=i686-build_pc-linux-gnu --host=arm-sm01-linux-gnueabi --target=arm-sm01-linux-gnueabi --prefix=`pwd`/install --with-headers=/home/dangjiahe/project/new_gcc/header/include --with-binutils=/home/dangjiahe/project/new_gcc/gcc-5.4.0/build/install/bin --with-tls --with-_thread --enable-sim --enable-nptl --enable-add-ons --disable-profile --cache-file=config.cache --enable-kernel=2.6.35 --without-gd --without-cvs --enable-static --enable-shared |
其中:--with-headers
指定内核安装的地址--with-binutils
指定binutils的安装地址--enable-kernel
指定内核版本--enable-static
必须指定, 否则第二次编译gcc后,会有找不到crti.o的问题
编译到后面,如果报lgcc找不到,则记录编译出libgcc.a的那个目录,然后再makefile中加入-L${目录}. 再编译即可.
第二次编译gcc
1 | cd ./gcc-5.4.0/build |
配置里:--with-build-sysroot
指定的是编译时,依赖的sysroot目录,为glibc的安装目录--with-sysroot
指定的是,编译结束后,gcc编译时的sysroot目录,在sysroot目录里要包含/usr/include和/usr/lib. 这样编译出的gcc编译时才不会报错。这两个目录需要用户根据情况自己创建--prefix
安装目录,安装目录要指定和glibc相同的安装目录,这样编译结束后,拿给别用,sysroot才能自动找到上面创建的include和lib
编译完成之后,整理一下,即完成编译,可以跑demo试试