嵌入式软件开发之------浅析制作ARMv8 native gcc 编译器(十)

导读:在学习嵌入式的时候,需要搭建 交叉编译 环境,也就是说在PC/服务器上编译嵌入式产品用的软件。或者具体点说,很多人开发的产品是基于ARM、MIPS的嵌入式设备,在自己的电脑上或服务器(通常是X86机器)使用交叉编译工具(gcc),来编译产品软件。网上也有很多交叉编译工具链的制作,甚至还有 crosstool-ng  用来制作 交叉编译用的gcc,如果不想自己制作,还可以下载别人制作好的工具链,比如ARM 用的 Linaro Toolchain带来了很多的方便。目前嵌入式领域ARM已经占领了大部分的份额,之前ARMv7时代,嵌入式设备性能弱,内存小,显然在嵌入式设备上安装gcc并不是一个明智的选择,而ARMv8已经不是ARMv7的简单升级,甚至可以理解为全新的架构,只不过兼容ARMv7的指令集而已。ARMv8重新设计了架构,很明显为了高性能和通用计算做了很多优化,也渐渐的出现了ARM版本的服务器,发展势头不容小觑。当前接触过的高端ARMv8处理器,单核和多核性能已经超过了intel部分中低端处理器。为了更深的研究ARMv8架构,自己买了个NanoPi M4的开发板,主控芯片用的RK3399,两个A72加4个A53,刚拿到手就突发奇想,为何不将gcc安装到自己的开发板里呢?然后百度谷歌了一下,几乎都是cross compile的制作过程,没有找到制作ARM直接使用的gcc,一下就激起了兴趣,就喜欢做别人没做过的事,享受探索未知的过程。下面就是制作过程。

一、基础知识

    编译过 交叉工具链 (太多博客教程了)的人 configure的时候遇到三个很基本的设置,build、host和target。三个设置的含义如下:

build:当前编译gcc代码的机器,通常都是x86,我自己就是用win10+vmware+ubuntu18.04

host :编译出来的gcc'运行在哪个平台上

target:用编译出来的gcc再编译的软件运行在哪个平台上

三个词确实有点绕,就拿编译交叉工具链 aarch64-linux-gnu-xx来解释,当然是用x86的机器来编译生成aarch64-linux-gnu-xx(build),生成的aarch64-linux-gnu-xx当然也是运行在x86的平台上(host),用aarch64-linux-gnu-xx编译的软件是运行在aarch64上的(target)。很显然交叉工具链是 build=host=x86,target=aarch64,这种形式成为cross gcc,显然要编译aarch64上的gcc,build=x86,host=target=aarch64,这种形式成为native gcc。build通常无需配置,configure的时候自动检测。所以编译native gcc只是cross gcc 最大的区别是host不一样。corss gcc 所需要的binutild,kernel header,gmp,mpfr,mpc,glibc,native gcc 一样需要。事实上,我在制作native gcc的时候,就是将cross gcc的制作过程将host 改成了aarch64-linux-gnu 而已。

而cross gcc 的编译过程从buildroot的编译过程中摘抄出来的,也并没有详细了解每一个配置项的含义。

本人的编译环境是win10+vmware+ubuntu18.04,其中ubuntu需要安装一些工具和库,如果遇到缺少一些库出现的错误,也很容易百度到。

源代码用的:linux4.4、gcc-linaro-7.4、gmp-6.1.2、mpfr-3.1.6、mpc-1.0.3、glibc-2.26,其中交叉编译工具链gcc-linaro-7.5。(想想为什么用交叉工具链?因为编译出来的gcc是要运行在ARM平台上啊,难不成指望x86的gcc编译出来的gcc能在ARM上运行?)

二、制作过程

1、建立基本的文件目录

其实建立文件目录只是为了更好的区分安装路径,并没有什么规则,只要自己分的清,怎么着都行,像我自己建立的nativetool文件,然后分别建立了glibc、kernel_headers、src、target、tmp

glibc是安装glibc的路径,kernel_headers 是linux头文件的路径,src是存放用到的源代码的路径,target是编译生成gcc的安装路径,tmp是gmp、mpfr和mpc的安装路径。

surpass@ubuntu:~/share/nativetool$ ls
glibc  kernel_headers  src  target  tmp

注意后面的步骤make -jx根据自己的CPU核数和内存大小来定,我自己电脑设置的4核8g内存,用make -j4能过,开始用的make -j ,编译gcc代码的时候,很快内存耗尽,又分配10G的swap空间也很快耗尽,如果出现内存耗尽的情况,检查是否设置的编译线程数太多了。

2、安装linux的头文件

编译native gcc的过程中,需要依赖linux的头文件,你的ARM平台上用的哪个版本的linux就是用哪个版本的linux头文件,下面是安装头文件路径的命令(切换到linux代码路径下,同时也将头文件安装到了glibc中)。

make mrproper
make arch=aarch64 headers_check
make ARCH=arm64 INSTALL_HDR_PATH=/home/surpass/share/nativetool/glibc/usr headers_install
make ARCH=arm64 INSTALL_HDR_PATH=/home/surpass/share/nativetool/kernel_headers headers_install

3、编译安装binutils

切换到binutils代码路径下,

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
MAKEINFO=true \
CONFIG_SITE=/dev/null \
./configure \
--prefix="/home/surpass/share/nativetool/target/usr" \
--enable-shared \
--disable-static \
--disable-gtk-doc \
--disable-gtk-doc-html \
--disable-doc \
--disable-docs \
--disable-documentation \
--disable-debug \
--with-xmlto=no\
--with-fop=no \
--disable-dependency-tracking  \
--disable-multilib \
--disable-werror \
--host=aarch64-zlk-linux \
--target=aarch64-zlk-linux-gnu \
--disable-shared --enable-static \
--with-sysroot=/home/surpass/share/nativetool/glibc/ \
--enable-poison-system-directories \
--disable-sim \
--disable-gdb \

编译:
make -j4

安装:
make -j4 install

3、编译安装gmp、mpfr和gmp

配置项和编译命令都一样,所以就放在一起

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
CONFIG_SITE=/dev/null \
./configure \
--prefix="/home/surpass/share/nativetool/tmp/" \
--host=aarch64-zlk-linux   \
--target=aarch64-zlk-linu

编译:
make -j4

安装:
make -j4 install 

4、编译安装glibc

编译glibc的时候不要直接在glibc代码路径下配置,另外建立一个文件夹来配置编译,我是在glibc'源代码下建立了build文件夹,然后切换到build下

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS_FOR_BUILD="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_BUILD="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
FCFLAGS_FOR_BUILD="" \
DEFAULT_ASSEMBLER="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
DEFAULT_LINKER="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
CPPFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" \
CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
CXXFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
LDFLAGS="" FCFLAGS=" -Os " \
FFLAGS=" -Os " \
STAGING_DIR="/home/surpass/share/nativetool/glibc" \
INTLTOOL_PERL=/usr/bin/perl \
CFLAGS="-O2 " \
CPPFLAGS="" \
CXXFLAGS="-O2 " \
ac_cv_path_BASH_SHELL=/bin/bash \
libc_cv_forced_unwind=yes \
libc_cv_ssp=no \
ac_cv_prog_MAKE="/usr/bin/make -j5"  /bin/bash \
../configure \
--target=aarch64-zlk-linux-gnu \
--host=aarch64-zlk-linux-gnu \
--build=x86_64-pc-linux-gnu \
--prefix=/usr \
--enable-shared  \
--without-cvs \
--disable-profile \
--without-gd \
--enable-obsolete-rpc \
--enable-kernel=4.4 \
--disable-experimental-malloc \
--with-headers=/home/surpass/share/nativetool/kernel_headers/include \

编译:
make -j4

安装:
make -j4 install_root=/home/surpass/share/nativetool/glibc install

5、编译gcc

同样在gcc源代码路径下建立build目录,然后切换到build目录下,

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS_FOR_BUILD="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_BUILD="-L/home/surpass/share/nativetool/glibc/lib -Wl,-rpath,/home/surpass/share/nativetool/glibc/lib" \
AR_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
CPPFLAGS_FOR_TARGET="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_TARGET="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_TARGET="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_TARGET="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
MAKEINFO=missing \
CFLAGS_FOR_TARGET="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
CXXFLAGS_FOR_TARGET="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
../configure \
--prefix="/home/surpass/share/nativetool/target/usr" \
--host=aarch64-zlk-linux-gnu \
--target=aarch64-zlk-linux-gnu \
--with-sysroot=/home/surpass/share/nativetool/glibc/ \
--enable-static  \
--enable-__cxa_atexit \
--with-gnu-ld \
--disable-libssp \
--disable-multilib \
--with-gmp=/home/surpass/share/nativetool/tmp/ \
--with-mpc=/home/surpass/share/nativetool/tmp/ \
--with-mpfr=/home/surpass/share/nativetool/tmp/ \
--disable-libquadmath \
--enable-tls \
--disable-libmudflap \
--enable-threads \
--without-isl \
--without-cloog \
--disable-decimal-float \
--with-abi="lp64" \
--with-cpu=cortex-a72.cortex-a53 \
--enable-languages=c,c++ \
--with-build-time-tools=/home/surpass/share/tool/aarch64-linux-gnu/bin/ \
--enable-shared \
--disable-libgomp \

编译:
make -j4 

安装:
make -j4 install

总结:

    上面的过程,其实就是从buildroot编译cross gcc 的过程中摘抄出来改了一下,编译期间也遇到了不少的问题,百度谷歌也很少能查的到,只有查看分析log。上面没有给配置项添加注释,我也没有去查源代码中的自带的说明弄清每一项配置的含义,个人觉得很多时候解决问题并不一定都需要做到精通,毕竟人的精力和时间都是有限的,时间应该花在知识面的拓展上,每一项技能掌握个百分之六七十,然后知识面非常的广,如果遇到某方面的问题,再花时间专门研究做到精通。笔者工作这几年深刻的感觉到,知识面的广度很多时候比只深度掌握几个点知识重要的多的多,很多的时候不是因为不精通解决不了问题,而是因为不知道造成的大量时间浪费。尤其是对于一些新技术问题的解决,知识面广的人表现出来的优势远不是只懂某几样技术的人可比的,而对于某些人所谓精通的领域,也是稍微多花点时间也可以达到差不多的水平。所以对于笔者,时间花在尽可能多的知识面覆盖上,并且至少能理解个百分之五十,实际工作中也发现这是个正确的路子。

 

 

 

你可能感兴趣的:(linux,gcc,compile,linux,aarch64,arm64,native,gcc,cross,gcc)