• 简单交叉编译学习


    交叉编译

    交叉编译是在一个平台上生成另一个平台上的可执行代码。 同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。
    通常是自己的电脑写好代码编译之后发到嵌入式设备或者盒子之类的去执行,或者另一个版本系统没有的东西,例如opencv,从有的系统版本编译到没有的系统版本中

    本文目标

    在x86_64服务器上编译一个arm或者aarch64的文件,并且在对应的机器上可以执行

    简单概念了解(来源

    • GCC 的命名规则为:arch [-vendor] [-os] [-(gnu)eabi]-gcc
      比如 arm-linux-gnueabi-gcc , arm-none-eabi-gcc, aarch64-linux-gnu-gcc
      1. arch:芯片架构,比如 32 位的 Arm 架构对应的 arch 为 arm,64 位的 Arm 架构对应的 arch 为 aarch64
      2. vendor :工具链提供商,大部分工具链名字里面都没有包含这部分
      3. os :编译出来的可执行文件(目标文件)针对的操作系统,比如 Linux
    • arm-none-eabi-gcc 一般适用用于 Arm Cortex-M/Cortex-R 平台,它使用的是 newlib 库
    • arm-linux-gnueabi-gcc 和 aarch64-linux-gnu-gcc 适用于 Arm Cortex-A 系列芯片,前者针对 32 位芯片,后者针对 64 位芯片,它使用的是 glibc 库。可以用来编译 u-boot、linux kernel 以及应用程序
    • 32 位的 Arm 和 64 位的 Arm,它们的指令集是不同的,所以需要使用不同的工具链。当然,Arm64 为了保证前向兼容,提供了一个 32 位的兼容模式,所以我们用 arm-linux-gnueabi-gcc 编译的应用程序也是可以直接在Arm64 的系统上运行的,但是 Linux Kernel 和 U-Boot 就不行,除非你提前把 CPU 切换到 32 位模式。曾经有个项目使用了一颗四核的 Arm64 芯片,但是内存只有64M,为了节省空间,在 CPU 运行到 U-Boot 之前,我们就把它切到了 32 位模式,后面的 U-Boot、Linux Kernel,应用全部都用 32 位编译,加上 Thumb 指令集,节省了不少空间
    • make:类似批处理的程序,来批处理编译源文件
    • makefile:make批处理编译规则文件
    • cmake:读入所有源文件之后,自动生成makefile
    • cmakelist:cmake所依据的规则

      图片来源

    工具链的下载安装

    • 下载
      推荐直接使用国内的镜像下载
    ## 来源https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchain/   //对比原文的少了一个s,清华把文件库路径进行了整理
    wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchain/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz
    wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchain/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
    

    名词解释来源
    * abi:二进制应用程序接口,允许编译好的目标代码在使用兼容ABI的系统中无需改动就能运行
    * eabi:嵌入式的abi,可以看作是一种简化的abi,体积小,运行快,适合嵌入式设备的
    * gnueabi:The GNU C compiler for armel architecture,适用于armel架构 针对旧的 32 位 ARM 处理器,而不支持硬件浮点单元(FPU)
    * gnueabihf: The GNU C compiler for armhf architecture,适用于armhf架构,仅适用于较新的 32 位 ARM 处理器,其至少实现了 ARMv7 架构,且支持 ARM 矢量浮点规范(VFPv3)
    第 3 版,开启需要硬件的支持,在Debian的wiki上要求ARMv7 CPU、Thumb-2指令集以及VFP3D16浮点处理器。
    * arm64: 适用于 64 位 ARM 处理器,其至少实现了 ARMv8 架构

    gnueabi和gnueabihf其实是gcc的选项-mfloat-abi的默认值不同,gcc的选项-mfloat-abi有三种值soft,softfp,hard(其中后两者都要求arm里有fpu浮点运算单元,soft与后两者是兼容的,但softfp和hard两种模式互不兼容):

    1. soft : 不用fpu进行浮点计算,即使有fpu浮点运算单元也不用,而是使用软件模式。
    2. softfp : armel架构(对应的编译器为gcc-arm-linux-gnueabi)采用的默认值,用fpu计算,但是传参数用普通寄存器传,这样中断的时候,只需要保存普通寄存器,中断负荷小,但是参数需要转换成浮点的再计算。
    3. hard : armhf架构(对应的编译器gcc-arm-linux-gnueabihf)采用的默认值,用fpu计算,传参数也用fpu中的浮点寄存器传,省去了转换, 性能最好,但是中断负荷高。
    • 解压
    xz -d gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz
    xz -d gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
    
    • 安装
    sudo mkdir -p /usr/local/toolchain  //目录可以更改,但是更改之后后续的目录也需要一起更改
    tar -xvf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar -C /usr/local/toolchain/
    sudo tar -xvf gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar -C /usr/local/toolchain/
    ls /usr/local/toolchain/
    //输出gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf  gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu
    
    • 添加环境变量
    vim ~/.bashrc
    PATH=$PATH:/usr/local/toolchain/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin:/usr/local/toolchain/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu/bin //将这句话加到文件的末尾
    source ~/.bashrc //使配置生效
    arm-linux-gnueabihf-gcc -v //输出gcc的版本号
    aarch64-linux-gnu-gcc -v //输出gcc的版本号
    

    编译

    • 我们在/root下添加一个c文件并写入内容
    sudo cd /root && cat << EOF > hello.c
    #include <stdio.h>
    
    int main()
    {
      printf("hello world \n");
      return 0;
    }
    EOF
    
    • 执行编译
      make编译和arm-linux-gnueabihf- 编译是一个效果,make命令执行的时候会去找makefile,在makefile中找到需要编译的版本,然后去执行对应的编译命令,而arm-linux-gnueabihf-这种是直接指定了编译版本
    arm-linux-gnueabihf-gcc hello.c -o armHello //编译arm版本的armHello文件,在arm服务器上可以使用./armHello执行
    aarch64-linux-gnu-gcc hello.c -o aarch64Hello //编译aarch64版本的aarch64Hello文件,在aarch64服务器上可以使用./aarch64Hello执行
    

    执行

    • 上传文件到指定的服务器
    scp -P 22 /root/armHello root@192.168.1.66:/root/armHello  //-P 22 可以省略,指定端口号,假设192.168.1.66是arm的服务器,需要输入登陆密码
    ssh root@192.168.1.66 //输入密码登陆
    cd /root && ./armHello
    ## aarch64Hello测试执行也是上面的顺序,最后的输出应该是
    hello world
    

    小白学习,错误之处欢迎指正

    参考链接

    https://cloud.tencent.com/developer/article/1571937
    https://www.runoob.com/linux/linux-comm-scp.html
    https://blog.csdn.net/forgetjoker/article/details/116295386
    https://zhuanlan.zhihu.com/p/340444117 //推荐阅读
    https://openskill.cn/article/1780 //推荐阅读
    https://www.cnblogs.com/xiaotlili/p/3306100.html //推荐阅读
    https://www.cnblogs.com/zhangjiankun/p/4852899.html //推荐阅读

  • 相关阅读:
    Android应用四大组件和应用程序的生命周期
    DOCTYPE html PUBLIC 指定了 HTML 文档遵循的文档类型定义
    Web前端灰框技术
    用JS实现在页面关闭或刷新时触发特定的事件
    style.display的全部属性值
    Android SDK更新的问题
    页面灰框模式精彩实现
    解决sql 语句中truncate语句不支持变量的问题
    获取网页中图片链接的路径的正则表达式
    web页面自动保存本页面的内容到本地
  • 原文地址:https://www.cnblogs.com/spatxos/p/16544176.html
Copyright © 2020-2023  润新知