用 crosstool-NG 制作自己所需的交叉编译工具链

 

本文记录如何使用 crosstool-NG 工具制作所需的交叉编译工具链

本文记录如何使用 crosstool-NG 工具制作所需的交叉编译工具链

什么是 crosstool-NG

crosstool-NG,全称是Crosstool Next Generation,即下一代crosstool,即crosstool的升级版。而 crosstool,是个交叉编译器的制作工具。crosstool-NG是作者Yann E. MORIN,在Dan Kegel写的crosstool的基础上,做了全新的升级。目的在于更加便利f地制作交叉编译器。

crosstool-NG的特点

  1. 支持(类似于Linux内核配置的那个)menuconfig

    menuconfig,用的最为广泛,支持度最好,最好用。

  2. 支持足够多,且越来越多的架构(architecture)

    Alpha, ARM, AVR32 (EXP), Blackfin (EXP), MIPS, OpenRISC/or32(+), PowerPC, s390, SPARC (EXP), SuperH (EXP), x86

  3. 支持工具链中可选多种不同的C库等模块

    • 支持基于uClibc, glibc或eglibc的工具链
    • 支持其他类型的,也很容易添加
  4. 支持不同目标OS平台

    • Linux
    • bare metal
  5. 补丁仓库

    为许多种现存的,已知bug的,需要打包的各种模块,提供了一个补丁仓库。

    如此可以实现:可以自动去帮你打上,已知的,需要打补丁的各种模块

  6. 支持不同的线程模型

    • NPTL
    • linuxthreads
  7. 支持软浮点和硬件浮点

  8. 支持multlib的工具链

  9. 支持很多用来调试(debug)的工具

    • 本地的和跨平台的gdb,gdbserver
    • 调试库:dmalloc, duma
    • 以及一些其他功能,比如从编译失败的那一步,恢复重新编译,从而节省你的大量的时间和精力

crosstool-ng 使用的步骤

  1. 下载、编译、安装 crostool-ng 工具本身

  2. 用 crostool-ng 制作(配置和编译)需要的交叉编译工具

    • 在 crostool-ng 中配置要制作的交叉编译器的各种参数

      • 比如CPU是arm还是mips还是其他
      • 运行目标平台是Linux还是bare metal,
      • 所用的C库是elibc,还是glibc,还是uclibc等,等等的配置
    • 配置的流程

      • 直接利用已有的配置

        crosstool-ng,本身已经支持很多种体系结构的配置,使用命令:ct-ng some_default_config

      • 手动修改已有配置

        找一个和你的需求最接近的一个配置,利用该配置,然后再去修改一些参数,达到最终你想要的效果

        ct-ng some_default_config
        ct-ng menuconfig
        
  • 编译
    • 等所有的配置都完毕后,就可以去编译,生成你所需要的交叉编译器了
      • 命令:ct-ng build

下载和安装crosstool-ng

下载crosstool-ng

crosstool-ng官方网站去下载。这里要注意 crosstool-ng 的最新版不是列表最下面的那份,而是列表第一行注明的 00-LATEST-is-1.23.0 版本。

设置好目录结构

一般常见的做法是:单独为后续使用crosstool-ng制作交叉编译去,而建立一个单独的文件夹

即,执行后续的ct-ng menuconfig, ct-ng build等命令,所处在的路径

比如:我之前,除了,解压crosstool所得的文件夹crosstool-ng-1.24.0之外,去建立了一个对应的文件夹:crosstool-ng-1.24.0_build

同时,为了后续crosstool-ng下载对应的各个包,也建立了对应的src和x-tools两个文件夹。

然后,此刻的目录结构就是:

# cd software/pkg/crosstool-ng   
# ls -l
crosstool-ng-1.24.0  
crosstool-ng-1.24.0_build 
crosstool-ng-1.24.0.tar.bz2  
src  
x-tools
  1. crosstool-ng-1.24.0 的源码包解压后的文件夹,包含了crosstool-ng的相关源码
  2. 专门为后期使用crosstool-ng去建立交叉编译器的编译(build)而专门建立的文件夹。对应的后续ct-ng menuconfig,ct-ng build等命令,都是在此文件夹下执行的。
  3. 为crosstool-ng中,后续需要下载各种软件的源码包而准备的。crosstool-ng中,在开始执行build之后,会去下载对应的源码包,都会存放到这个文件夹下
  4. x-tools这个文件夹是用crosstool-ng所生成的交叉编译器,所在的路径。对应的配置中会有类似于:(${HOME}/software/pkg/crosstool-ng/x-tools/${CT_TARGET}) Prefix directory 的配置,用来指定生成的交叉编译器存放在何处。此时,就是去设置为此处对应的路径即可。

如此,后续的编译,才显得,相对更加有组织,不至于显得结构太混乱。

安装

把下载到的 crosstool-ng 解压后,执行:

./configure --prefix=/opt/crosstool-ng
make
make install

安装问题解决

  1. missing required tool: flex

    sudo apt install flex
    
  2. install-info 错误

    正在处理用于 man-db (2.7.5-1) 的触发器 ...
    在处理时有错误发生:
     install-info
    E: Sub-process /usr/bin/dpkg returned an error code (1)
    
    • 更新info文件夹即可

      sudo mv /var/lib/dpkg/info/ /var/lib/dpkg/info_old/
      sudo mkdir /var/lib/dpkg/info/
      sudo apt-get update
      sudo apt-get -f install
      sudo mv /var/lib/dpkg/info/* /var/lib/dpkg/info_old/
      sudo rm -rf /var/lib/dpkg/info
      sudo mv /var/lib/dpkg/info_old/ /var/lib/dpkg/info/
      
  3. missing required tool: makeinfo

    sudo apt install texinfo
    
  4. missing required tool: help2man

    sudo apt install help2man
    
  5. configure: error: could not find curses header, required for the kconfig frontends

    sudo apt-get install libncurses5-dev
    
  6. could not find GNU libtool >= 1.5.26

    sudo apt-get install automake
    

crosstool-ng 的常用命令

ct-ng help

查看crosstool-ng所拥有的功能

# ct-ng help
This is crosstool-NG version 1.24.0

Copyright (C) 2008  Yann E. MORIN <yann.morin.1998@free.fr>
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

See below for a list of available actions, listed by category:
请看下面按类别列出的可用行动清单:

Configuration actions:
  show-config        - Show a brief overview of current configuration
  saveconfig         - Save current config as a preconfigured target
  menuconfig         - Update current config using a menu based program
  nconfig            - Update current config using a menu based program
  oldconfig          - Update current config using a provided .config as base
  upgradeconfig      - Upgrade config file to current crosstool-NG
  extractconfig      - Extract to stdout the configuration items from a
                       build.log file piped to stdin
  savedefconfig      - Save current config as a mini-defconfig to ${DEFCONFIG}
  defconfig          - Update config from a mini-defconfig ${DEFCONFIG}
                       (default: ${DEFCONFIG}=./defconfig)
  show-tuple         - Print the tuple of the currently configured toolchain

  show-config        -	显示当前配置的简要概述
  saveconfig         -	将当前配置保存为预配置的目标。
  menuconfig         -	使用基于菜单的程序更新当前配置
  nconfig            -	使用基于菜单的程序更新当前配置
  oldconfig          -	使用提供的.config作为基础更新当前配置。
  upgradeconfig      -	将配置文件升级到当前的crosstool-NG。
  extractconfig      -	将配置项从build.log文件中提取到stdin。
  savedefconfig      -	将当前配置作为迷你defconfig保存到${DEFCONFIG}。
  defconfig          -	从mini-defconfig更新配置 ${DEFCONFIG}(默认:${DEFCONFIG}=./defconfig)
  show-tuple         -	打印当前配置的工具链元组。



Preconfigured toolchains (#: force number of // jobs):
  list-samples       - Prints the list of all samples (for scripting)
  show-<sample>      - Show a brief overview of <sample> (list with list-samples)
  <sample>           - Preconfigure crosstool-NG with <sample> (list with list-samples)
  build-all[.#]      - Build *all* samples (list with list-samples) and install in
                       ${CT_PREFIX} (set to ~/x-tools by default)
                       
  list-samples		 - 打印所有样本的列表(用于脚本)。
  show-<sample>		 - 显示<sample>的简要概述(列表与列表-样本)。
  <sample>			 - 用<sample>预先配置crosstool-NG(list-sample的列表)。
  build-all[.#]      - 编译所有样本 (使用 list-samples) 并安装到${CT_PREFIX}(默认设置为 ~/x-tools)

Build actions (#: force number of // jobs):
  list-steps         - List all build steps
  source             - Download sources for currently configured toolchain
  build[.#]          - Build the currently configured toolchain
  
  list-steps		 - 列出所有构建步骤
  source			 - 下载当前配置的工具链的源码。
  build[.#]			 - 构建当前配置的工具链

Clean actions:
  clean              - Remove generated files
  distclean          - Remove generated files, configuration and build directories
  
  clean				 - 删除生成的文件
  distclean          - 删除生成的文件、配置和构建目录。

Distribution actions:
  check-samples      - Verify if samples need updates due to Kconfig changes
  update-samples     - Regenerate sample configurations using the current Kconfig
  updatetools        - Update the config tools
  
  check-samples		 - 验证样本是否因Kconfig的改变而需要更新。
  update-samples	 - 使用当前的Kconfig重新生成样本配置。
  updatetools		 - 更新配置工具

Environment variables (see http://crosstool-ng.github.io/docs/build/)
  STOP=step          - Stop the build just after this step (list with list-steps)
  RESTART=step       - Restart the build just before this step (list with list-steps)
  CT_PREFIX=dir      - Install samples in dir (see action "build-all", above).
  V=0|1|2|<unset>    - <unset> show only human-readable messages (default)
                       0 => do not show commands or human-readable message
                       1 => show only the commands being executed
                       2 => show both
                       
  STOP=step			 - 在这一步之后停止构建(列表与列表步骤)
  RESTART=step		 - 在此步骤之前重新启动构建(list with list-steps)
  CT_PREFIX=dir		 - 将样本安装在 dir (参见上面的 "build-all" 动作)V=0|1|2|<unset>    - <unset> 只显示人类可读的信息(默认)。
						   0 => 不显示命令或人类可读的信息。
						   1 => 只显示正在执行的命令
						   2 => 显示两个

Use action "menuconfig" to configure your toolchain
Use action "build" to build your toolchain
Use action "version" to see the version
See "man 1 ct-ng" for some help as well

使用动作 "menuconfig "来配置你的工具链。
使用动作 "build "来构建你的工具链。
使用动作 "version "查看版本
请参阅 "man 1 ct-ng "的一些帮助。
  1. 查看当前有哪些(默认的)示例配置,可以用:

    ct-ng list-samples
    
  2. 查看单个的某个示例配置的核心参数,用:

    ct-ng show-<sample>
    
  3. 直接借用(使用,调用)该默认配置,用:

    ct-ng <sample>
    

ct-ng list-steps

ct-ng list-steps可以查看本身的build过程分成哪几步

# ct-ng list-steps                                            
Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc_main
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.
使用"<step>"作为只执行该步骤的动作。
使用 "+<step>"作为执行到该步骤的操作。
使用"<step>+"作为从该步骤开始执行的动作。

ct-ng list-samples

ct-ng list-samples查看当前已包含哪些默认的示例配置

# ct-ng list-samples
Status  Sample name
[G...]   aarch64-rpi3-linux-gnu
[G..X]   aarch64-unknown-linux-android
[G...]   aarch64-unknown-linux-gnu
[G...]   aarch64-unknown-linux-uclibc
[G...]   alphaev56-unknown-linux-gnu
[G...]   alphaev67-unknown-linux-gnu
[G...]   arc-arc700-linux-uclibc
[G...]   arc-multilib-elf32
// 省略....
[G..X]   x86_64-w64-mingw32,x86_64-pc-linux-gnu
[G...]   x86_64-ubuntu12.04-linux-gnu
[G...]   x86_64-ubuntu14.04-linux-gnu
[G...]   x86_64-ubuntu16.04-linux-gnu
[G...]   x86_64-unknown-linux-gnu
[G...]   x86_64-unknown-linux-uclibc
[G..X]   x86_64-w64-mingw32
[G..X]   xtensa-fsf-elf
[G...]   xtensa-fsf-linux-uclibc
 L (Local)       : sample was found in current directory
 G (Global)      : sample was installed with crosstool-NG
 X (EXPERIMENTAL): sample may use EXPERIMENTAL features
 B (BROKEN)      : sample is currently broken
 O (OBSOLETE)    : sample needs to be upgraded

ct-ng show-tuple

ct-ng show-tuple查看当前配置的是什么交叉编译器

在配置(和编译)之后,可以通过show-tuple,去查看到当前配置的交叉编译器是什么样的。

  • 没有配置之前

    # ct-ng show-tuple
    There is no existing .config file!
    You need to either run 'menuconfig',
    or configure an existing sample.
    /opt/crosstool-ng/bin/ct-ng:248: recipe for target '.config' failed
    make: *** [.config] Error 1
    
  • 配置好之后

    # ct-ng show-tuple
    make[6]: Entering directory '/home/wilson/software/pkg/crosstool-ng/crosstool-ng-1.24.0_build'
    arm-cortex_a8-linux-gnueabihf
    make[6]: Leaving directory '/home/wilson/software/pkg/crosstool-ng/crosstool-ng-1.24.0_build'
    

ct-ng version

ct-ng version查看当前crosstool-ng的版本

# ct-ng version
This is crosstool-NG version 1.24.0

Copyright (C) 2008  Yann E. MORIN <yann.morin.1998@free.fr>
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

crosstool-ng 本身的配置

对于常见的架构,比如arm,mips,powerpc等等,都已经有了可以正常编译的示例配置。下面就介绍如何利用现有的示例去配置 crostool-ng

使用现有的配置

假设我们要制作针对cortex-a8这款CPU的一个交叉编译器,在默认已有此配置了:arm-cortex_a8-linux-gnueabi

  1. 可以在使用之前先看看,该配置的主要参数是哪些:

    # ct-ng show-arm-cortex_a8-linux-gnueabi
    [G...]   arm-cortex_a8-linux-gnueabi
    	Languages       : C,C++
    	OS              : linux-4.20.8
    	Binutils        : binutils-2.32
    	Compiler        : gcc-8.3.0
    	C library       : glibc-2.29
    	Debug tools     : duma-2_5_15 gdb-8.2.1 ltrace-0.7.3 strace-4.26
    	Companion libs  : expat-2.2.6 gettext-0.19.8.1 gmp-6.1.2 isl-0.20 libelf-0.8.13 libiconv-1.15 mpc-1.1.0 mpfr-4.0.2 ncurses-6.1 zlib-1.2.11
    	Companion tools : automake-1.16.1 bison-3.3.2
    
  2. 使用默认配置

  # ct-ng arm-cortex_a8-linux-gnueabi
  
  CONF  arm-cortex_a8-linux-gnueabi
  #
  # configuration written to .config
  #
  ***********************************************************
  Initially reported by: Yann E. MORIN
  URL: http://ymorin.is-a-geek.org/
  ***********************************************************
  Now configured for "arm-cortex_a8-linux-gnueabi"
  1. 详细配置

    ct-ng menuconfig
    

自定义 crostool-ng 配置

自定义就需要自己对使用的CPU有深入的了解,配置的基本步骤和上面是一样的

crosstool-ng的配置参数详解

Paths and misc options

这个选项卡里是与 crosstool-ng 工具自身相关的配置参数。这些参数的配置可以让我们在使用此工具时更加便利。比如:

  1. 设置多线程,以加快编译速度,节省编译时间,
  2. 从之前错误的某步中恢复,继续编译,从而节省你的时间
  3. 在编译出错时,不退出,而提供机会给你修复错误,修复后,然后可以继续编译

Debug crosstool-NG

这里设置一些关于调试crosstool-NG的选项。可以从之前错误的步骤开始继续编译工具链。

  1. Save intermediate step

    Paths and misc options
    	[*] Debug crosstool-NG
    	[*]   Save intermediate steps
    

    如果你在这里说’y’,那么你就可以在任何一步重新启动crosstool-NG。目前无法在任何调试设施上重新启动,他们是作为一个整体来对待的.

    要获得完整的操作系统步骤列表,运行:ct-ng list-steps。

    所以此处,先要选上:Debug crosstool-NG 表示使用crosstoo-ng的调试方面的功能;再去选上:Save intermediate steps,意思是:编译完毕每一步之后,都会保存对应的状态

    如此,就可以实现从之前出错的步骤恢复而继续编译的效果了。

    具体就是找到之前编译最后成功的那一步(last successful step)。然后去执行:

    ct-ng last_successful_step+
    

    就可以继续恢复继续编译了。

Interactive shell on failed command

Paths and misc options
	[*] Debug crosstool-NG
	[*]   Interactive shell on failed commands

如果你在这里设置’y’,那么每个失败的命令都会产生一个交互式shell。

这个shell将拥有与失败的命令运行时相同的环境,工作目录将被设置为失败的命令运行时的目录。

在你修复问题后,你可以用以下任何一个退出代码退出交互式shell。

  1. 问题已解决,继续用下一条命令进行编译。
  2. 问题已解决,重新运行失败的命令。
  3. 终止构建

注意:’2’只适用于通过CT_DoExecLog运行的命令

当编译失败时,不是直接退出编译,而是提供一个交互式的shell,然后你可以(另开一个终端)去修复你的问题;修复问题后,再通过 exit N,实现对应的返回N的值,达到对应的效果:

  • exit 1:(不重新执行,之前错误的那个命令)而接着直接继续编译

  • exit 2: 重新执行之前错误的那个命令,然后接着继续执行

    常用于:当某个.c文件编译出错了,然后你另起一个终端,去修改了该.c文件,解决了错误。

    然后就可以通过 exit 2 而使得,重新执行命令,重新编译该.c文件,而使得可以正常编译,继续编译。

  • exit 3:直接退出编译,相当于,直接按Ctrl+C,而中断编译

Local tarballs directory

  • 功能:源码包下载保存路径
    • 即之前配置好的各种模块,包括C库,GCC,binutils等等所有的东西。
    • crosstool-ng 会从网上下载下来(或自行下载),都放在此文件夹中,也就是前面提到的src 目录
  • 设置值:${HOME}/software/pkg/crosstool-ng/src

Prefer buildroot-style layout of the downloads

  • 功能:设置成 buildroot 风格的目录布局
    • Buildroot 改变了下载目录的布局,将每个软件包的文件放入以该软件包命名的子目录中。
    • 启用此选项可让crosstool-NG创建类似的布局。
    • 如果设置了这个选项,并且所需的存档位于传统的、扁平化布局的目录中,那么存档将被移动到一个子目录中。
    • 如果不设置此选项,子目录既不会被检查,也不会用于存储下载。

Working directory

  • 功能:工作目录
    • 将此选项设置为完成所有编译操作的目录。 默认值是${CT_TOP_DIR}/.build,如果这个选项为空也会使用默认值。
    • 你不需要改变这个选项,除非是在一个非常特殊的设置中。
      • 您的 crosstool-NG 源码目录在网络上。
      • 你用–local配置了crosstool-NG。
      • 这种设置是很麻烦的,因为任何涉及源文件访问的操作都必须通过网线。
      • 在这种情况下,你应该将CT_WORK_DIR设置为指向你的机器的本地路径,以避免任何网络开销。
  • 设置值:默认值

prefix directory

  • 功能:前缀路径
    • 编译出的交叉工具链的运行路径
  • 设置值:${HOME}/software/pkg/crosstool-ng/x-tools/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}

Remove the prefix dir prior to building

  • 功能:构建之前删除PREFIX_DIR(上面)
    • 当你在尝试不同的设置时(由于构建失败或功能测试),这可能是有用的。在这种情况下,为了避免使用一个可能损坏的以前的工具链,安装位置会被删除,以便重新开始。
    • 如果你正在构建一个最终的工具链,并通过一个预先安装好的程序安装到一个目录中,那么删除该目录将是破坏性的。
  • 设置值:默认值

Strip host toolchain executables

  • 功能:剥离主机主机可执行文件中的多余信息
    • 所有的构建主机可执行文件都包含很多不必要的信息。
    • 通过剥离主机可执行文件,可以稍微加快大型项目的编译速度。
    • 注意:它不会剥离目标库,只剥离主机可执行文件。

Number of parallel jobs

  • 功能:设置多线程
    • 允许同时运行的作业数量,设置为高于你的处理器数量,但不要太高。
    • 一个好的经验法则是你拥有的处理器数量的两倍。
    • 输入1:一次只能有一个工作
    • 输入0:根据主机的处理器数量自动设置。

设置好此参数后,后续直接去build:

ct-ng build

即可自动以对应的多线程去编译了。无需后续手动再在build上参数,即无需:

ct-ng build.4

Target options

append ‘hf’ to the tuple

  • 功能:工具链以 eabihf 结尾而不是以 eabi 结尾
    • eabihf 表明工具链是使用了 hard-float 的 ABI
    • eabi 表明工具链使用 soft-float 的 ABI
    • 并不是所有版本的 gcc/binutils 都支持这样的元组, 并不能用 eabihf 来编译。在4.7.2之前的gcc版本都存在eabihf的问题

Suffix to the arch-part

  • 功能:架构名称
    • 有些架构有多个变体,能够指定变体是相当方便的。例如, “armv5tel-“被用作前缀而不是更通用的 “arm-“,或者用 “alphaev6-“代替 “alpha-“

target 的核心参数

crosstool-ng中的Architecture level, Emit assembly for CPU, Tune for CPU,分别对应的是gcc中的-march=xxx, -mcpu=xxx, -mtune=xxx

  1. Architecture level(架构级)
    • 变量名:CT_ARCH_ARCH
      • GCC使用这个名称来决定它在生成汇编代码时可以发出什么样的指令。这个选项可以和ARCH_CPU选项(上面)或者(命令行)-mcpu=option一起使用,也可以用于替换它们。这就是配置标志-with-arch=XXXX,运行时标志-march=XXX
      • 从gcc手册中为你选择的gcc版本和你的目标CPU选择一个值
      • 如果您不知道,或者您的目标架构不提供此选项,请留空
    • 对于此处的march,需要自己去找gcc中的march的说明,然后找到针对xscale的说明,然后才知道填写何值。
      • 我们在GCC官网的ARM Options一节看到:
        • GCC中的这些-m选项是为ARM端口定义的
        • -march=name[+extension…]
  • 指定了目标ARM架构的名称,也就是指令集版本。GCC使用这个名称来确定在生成汇编代码时可以发出什么样的指令
    • 指令集就是CPU提供的API接口
  • 允许值: ‘armv7-r’, ‘armv8-r’…
  1. Emit assembly for CPU

    • 变量名:CT_ARCH_CPU
      • 相当于:-mcpu=name[+extension…]
      • 指定目标ARM处理器的名称,也就是ARM核。这指定目标ARM处理器的名称。GCC使用该名称来推导目标ARM体系结构的名称(如由-march指定)和要针对其性能进行调整的ARM处理器类型(如由-mtune指定)。 如果将此选项与-march或-mtune结合使用,则这些选项优先于此选项的适当部分。
      • 允许值:‘cortex-a7’, ‘cortex-a8’, ‘cortex-a9’….
  2. Tune for CPU

    • 变量名:CT_ARCH_TUNE
      • 相当于:-mtune=name
      • 这个选项指定目标ARM处理器的名称,GCC应该为该处理器调优代码的性能。对于一些ARM实现,使用这个选项可以获得更好的性能。
      • 允许的名字是:‘arm7tdmi’, ‘arm7tdmi-s’, …. ‘cortex-a8’
    • 比如S5PV210的SoC,它集成了ARM Cortex-A8内核,实现了ARMV7-A的架构与配套外设
      • -march=armv7-a,与具体汇编指令有关
      • -mcpu=cortex-a8,主要与优化有关
      • -mtune=cortex-a8,与性能优化有关
  3. FPU 功能

    Target options  --->
        (neon) Use specific FPU                                                                   		Floating point: (softfp (FPU))  --->
    
  • 使用指定的 FPU

    关于ARM的浮点运算,可以参看《附录:使用硬件浮点实现浮点运算》

    • 变量名:CT_ARCH_FPU
    • 功能:
      • 在某些目标上(例如ARM),你可以指定要发射代码的FPU种类
      • 这就是配置标志--with-fpu=XXX,以及运行时标志--mfpu=XXX
      • 请看下面的内容,到底是要实际发出FP操作码,还是要模拟它们(即用硬件还是软件模拟)
        • 从gcc手册中选择一个适合你所选择的gcc版本和目标CPU的值。
        • 如果你不知道,或者你的目标架构没有提供这个选项,请留空。
      • 查找gcc手册-mfpu=name 选项
        • 指定了目标机上有哪些浮点硬件(或硬件仿真)可用
        • 允许的名字是: ‘auto’, ‘vfpv2’, …, ‘fp-armv8’, ‘neon-fp-armv8’
        • 默认设置“auto”是特殊的。 它使编译器根据-mcpu和-march的设置选择浮点和高级SIMD指令。
      • 通过架构 ARMv7-A 和内核 cortex-a8 可以找到它支持 NEON 和 VFPV3
        • 编译时,kernel、rootfs和app的指定必须一致才行
    • 设置值:neon
      • 使用 neon 时,会自带 VFP 功能
  1. Target CFLAGS
    • 变量名:CT_TARGET_CFLAGS
  • 功能:
    • 用于在编译工具链的库时添加特定的选项,这些库将在目标机上运行(例如libc.so)。
      • 自动使用。你不需要在这里指定它们。
      • 如果你不知道,请留空。
    • 设置值:-O
      • 启用优化标志会使编译器尝试以牺牲编译时间和调试程序的能力为代价来提高性能和/或代码大小
      • 在没有任何优化选项的情况下,编译器会降低编译成本,并使调试产生预期的结果。
      • 使用-O,编译器将尝试减少代码大小和执行时间,而不执行任何占用大量编译时间的优化。
  1. Target LDFLAGS
    • 变量名:CT_TARGET_LDFLAGS
    • 功能:
      • 用于在链接工具链的库时添加特定的选项,这些库将在你的目标上运行。
      • 当编译器将目标文件链接到可执行输出文件时,这些选项将发挥作用
    • 设置值:默认值

配置 Toolchain options

  1. Use sysroot’ed toolchain
    • 变量名:CT_USE_SYSROOT
    • 功能:
      • 使用gcc “新的”sysroot特性:库在prefix/target/sysroot/libprefix/target/sysroot/usr/lib之间分离
    • 设置值:”Y”
    • sysroot 的路径是:${CT_PREFIX_DIR}/${CT_TARGET}/${CT_SYSROOT_DIR_PREFIX}/${CT_SYSROOT_NAME}
  2. Build Static Toolchain
    • 变量名:CT_STATIC_TOOLCHAIN
    • 功能:
      • 构建静态主机二进制文件
      • 如果你想把工具链移到另一个主机上,而你又不确定这个主机是否有所需的系统库版本,那么你可以在这里说 “Y”,所有的主机工具都会被静态地链接起来
  3. Tuple’s vendor string
    • 变量名:CT_TARGET_VENDOR
    • 功能:
      • 目标元组的供应商部分
      • 交叉编译器名称的格式:arch-vendor-kernel-system
    • 设置值:cortex_a8
  4. Tuple’s sed transform
    • 变量名:CT_TARGET_ALIAS_SED_EXPR
    • 功能:
      • 通常,你会在目标元组前加上破折号和组件名称来调用你的工具链组件 (尤其是 gcc)(例如 armeb-unknown-linux-uclibc-gcc)。
      • 您可以在这里输入一个 sed 表达式来应用于 ${CT_TARGET} 来为您的工具链创建一个别名。
      • 例如, s/${CT_TARGET_VENDOR}/foobar/ 将为上述工具链创建 armeb-foobar-linux-uclibc 的别名。
      • 你不应该在这里输入任何东西,除非你打算手动调用这些工具(基于autotools./configure将使用标准名称)。
    • 设置值:默认值

Operating System

  1. Target OS
    • 分成裸机(bare-metal)和linux
    • bare-metal 只适用于 bootloader 等没有内核的程序,因为 APCI 的东西依赖于目标C库头文件的可用性
  2. Version of linux
  • 功能:指定使用的 linux 内核版本
    • 对于你进行嵌入式开发时所选择的Linux版本,应该和此处交叉编译器配置的Linux内核版本要一致
    • 对于供应商仓库外的源码或来自自定义位置的源码,制定好描述这些自定义源码的版本。基于这个版本,crosstool-NG可能会在构建linux时应用一些这些版本的非常规模式
      • 可以自己下载所需要的linux源码,把源码放到 src 目录中
    • 可以指定目录或文件
      • 之后编译的时候,就可以找到你自己设置的Linux内核,并解压,去加载对应的头文件等内容了
    • 设置值:${HOME}/software/pkg/crosstool-ng/src/linux-2.6.19.1.tar.bz2

C compiler

Show gcc versions from

  • 功能:crosstool-ng中的gcc的版本选择

    • crosstool-ng现在支持Linaro版本的gcc

    • 如何开启 Linaro 版本的 gcc

      • 先开启实验性功能

        Paths and misc options
            [*] Try features marked as EXPERIMENTAL
        
      • 在此处就可以选择 Linaro 了

C-library

C 库有多个选择:

  1. bionic
    • Bionic是Android的C库。它是预先构建的,从Android NDK中提取出来的。该平台不支持TLS(线程本地存储),因此必须在编译器选项中禁用该选项
  2. glibc
    • 是Linux发行版的事实标准,功能丰富,但体积庞大,对于桌面类系统最有用
  3. Musl
    • Musl是一个新的标准库,用于支持新一代基于Linux的设备。
    • Musl是轻量级的,快速的,简单的,免费的,并且在标准的一致性和安全性方面力求正确

Threading implementation to use

线程模型主要分两种:linuxThreads和 NPTL,有关它们的说明见附录

这里选择 NPTL

Companion libraries

  1. Check the companion libraries builds
    • 强烈建议检查新建的配套库。不幸的是,这是一个非常密集的任务,需要很长的时间。
    • 因此,默认情况下,检查新构建的伴侣库是被禁止的,但建议你至少在机器上检查一次,如果它们能正常工作,则在随后的构建中禁止检查。
    • 如果你怀疑你的一个(或多个)同伴库是导致错误生成代码的原因,你应该在这里回答 “Y”。但是请注意,这将需要很长的时间。

Crosstool-NG 构建

在上面的配置完成后,就可以执行 ct-ng build 命令来构建自己所需的交叉编译工具链了,构建成功后,可以在项目的 x-tools 目录下看到工具链

# ls -l /home/wilson/software/pkg/crosstool-ng/x-tools
dr-xr-xr-x 8 wilson wilson 4096 Jul 13 09:45 arm-cortex_a8-linux-gnueabi
drwxrwxr-x 5 wilson wilson 4096 Jul 10 15:53 arm-cortex_a8-linux-gnueabihf
drwxrwxr-x 8 wilson wilson 4096 Jul 11 15:06 arm-cortex_a8-linux-musleabihf

# ls -l /home/wilson/software/pkg/crosstool-ng/x-tools/arm-cortex_a8-linux-gnueabi
dr-xr-xr-x 7 wilson wilson    4096 Jul 13 09:37 arm-cortex_a8-linux-gnueabi
dr-xr-xr-x 2 wilson wilson    4096 Jul 13 09:45 bin
-r--r--r-- 1 wilson wilson 1046156 Jul 13 09:45 build.log.bz2
dr-xr-xr-x 2 wilson wilson    4096 Jul 13 09:37 include
dr-xr-xr-x 4 wilson wilson    4096 Jul 13 09:37 lib
dr-xr-xr-x 3 wilson wilson    4096 Jul 13 09:37 libexec
dr-xr-xr-x 8 wilson wilson    4096 Jul 13 09:45 share

下面是我编译的过程的记录

# ct-ng build V=2

make[9]: Entering directory '/home/wilson/software/pkg/crosstool-ng/crosstool-ng-1.24.0_build'
BUILD_NCPUS=`getconf _NPROCESSORS_ONLN 2>/dev/null || echo 0` \
        /bin/bash /opt/crosstool-ng/share/crosstool-ng/scripts/crosstool-NG.sh
[INFO ]  Performing some trivial sanity checks
[INFO ]  Build started 20200713.091847
[INFO ]  Building environment variables
[EXTRA]  Preparing working directories
[EXTRA]  Installing user-supplied crosstool-NG configuration
[EXTRA]  =================================================================
[EXTRA]  Dumping internal crosstool-NG configuration
[EXTRA]    Building a toolchain for:
[EXTRA]      build  = x86_64-pc-linux-gnu
[EXTRA]      host   = x86_64-pc-linux-gnu
[EXTRA]      target = arm-cortex_a8-linux-gnueabi
[EXTRA]  Dumping internal crosstool-NG configuration: done in 0.08s (at 00:02)
[INFO ]  =================================================================
[INFO ]  Retrieving needed toolchain components' tarballs
[INFO ]  Retrieving needed toolchain components' tarballs: done in 0.50s (at 00:02)
[INFO ]  =================================================================
[INFO ]  Extracting and patching toolchain components
[EXTRA]    Extracting glibc-2.29
[EXTRA]    Patching glibc-2.29
[INFO ]  Extracting and patching toolchain components: done in 3.18s (at 00:05)
[INFO ]  Saving state to restart at step 'companion_tools_for_build'...
[INFO ]  =================================================================
[INFO ]  Installing automake for build
[EXTRA]    Configuring automake
[EXTRA]    Building automake
[EXTRA]    Installing automake
[INFO ]  Installing automake for build: done in 2.22s (at 00:08)
[INFO ]  =================================================================
[INFO ]  Installing bison for build
[EXTRA]    Configuring bison
[EXTRA]    Building bison
[EXTRA]    Installing bison
[INFO ]  Installing bison for build: done in 26.33s (at 00:34)
[INFO ]  Saving state to restart at step 'companion_libs_for_build'...
[INFO ]  =================================================================
[INFO ]  Installing ncurses for build
[EXTRA]    Configuring ncurses
[EXTRA]    Building ncurses
[EXTRA]    Installing ncurses
[INFO ]  Installing ncurses for build: done in 10.59s (at 00:45)
[INFO ]  Saving state to restart at step 'binutils_for_build'...
[INFO ]  Saving state to restart at step 'companion_tools_for_host'...
[INFO ]  Saving state to restart at step 'companion_libs_for_host'...
[INFO ]  =================================================================
[INFO ]  Installing zlib for host
[EXTRA]    Configuring zlib
[EXTRA]    Building zlib
[EXTRA]    Installing zlib
[INFO ]  Installing zlib for host: done in 0.77s (at 00:46)
[INFO ]  =================================================================
[INFO ]  Installing GMP for host
[EXTRA]    Configuring GMP
[EXTRA]    Building GMP
[EXTRA]    Installing GMP
[INFO ]  Installing GMP for host: done in 24.09s (at 01:10)
[INFO ]  =================================================================
[INFO ]  Installing MPFR for host
[EXTRA]    Configuring MPFR
[EXTRA]    Building MPFR
[EXTRA]    Installing MPFR
[INFO ]  Installing MPFR for host: done in 13.94s (at 01:24)
[INFO ]  =================================================================
[INFO ]  Installing ISL for host
[EXTRA]    Configuring ISL
[EXTRA]    Building ISL
[EXTRA]    Installing ISL
[INFO ]  Installing ISL for host: done in 11.09s (at 01:35)
[INFO ]  =================================================================
[INFO ]  Installing MPC for host
[EXTRA]    Configuring MPC
[EXTRA]    Building MPC
[EXTRA]    Installing MPC
[INFO ]  Installing MPC for host: done in 4.33s (at 01:40)
[INFO ]  =================================================================
[INFO ]  Installing expat for host
[EXTRA]    Configuring expat
[EXTRA]    Building expat
[EXTRA]    Installing expat
[INFO ]  Installing expat for host: done in 5.23s (at 01:45)
[INFO ]  =================================================================
[INFO ]  Installing ncurses for host
[EXTRA]    Configuring ncurses
[EXTRA]    Building ncurses
[EXTRA]    Installing ncurses
[INFO ]  Installing ncurses for host: done in 9.83s (at 01:55)
[INFO ]  =================================================================
[INFO ]  Installing libiconv for host
[EXTRA]    Skipping (included in GNU C library)
[INFO ]  Installing libiconv for host: done in 0.00s (at 01:55)
[INFO ]  =================================================================
[INFO ]  Installing gettext for host
[EXTRA]    Skipping (included in GNU C library)
[INFO ]  Installing gettext for host: done in 0.00s (at 01:55)
[INFO ]  Saving state to restart at step 'binutils_for_host'...
[INFO ]  =================================================================
[INFO ]  Installing binutils for host
[EXTRA]    Configuring binutils
[EXTRA]    Prepare binutils for static build
[EXTRA]    Building binutils
[EXTRA]    Installing binutils
[INFO ]  Installing binutils for host: done in 37.40s (at 02:33)
[INFO ]  Saving state to restart at step 'cc_core_pass_1'...
[INFO ]  =================================================================
[INFO ]  Installing pass-1 core C gcc compiler
[EXTRA]    Configuring core C gcc compiler
[EXTRA]    Building gcc
[EXTRA]    Installing gccC^[[D^[[D^[[C^[[A^[[D^[[A^[[D^[[A^[[D
[EXTRA]    Housekeeping for core gcc compiler
[EXTRA]       '' --> lib (gcc)   lib (os)
[INFO ]  Installing pass-1 core C gcc compiler: done in 165.30s (at 05:21)
[INFO ]  Saving state to restart at step 'kernel_headers'...
[INFO ]  =================================================================
[INFO ]  Installing kernel headers
[EXTRA]    Installing kernel headers
[EXTRA]    Checking installed headers
[INFO ]  Installing kernel headers: done in 7.09s (at 05:36)
[INFO ]  Saving state to restart at step 'libc_start_files'...
[INFO ]  =================================================================
[INFO ]  Installing C library headers & start files
[INFO ]    =================================================================
[INFO ]    Building for multilib 1/1: ''
[EXTRA]      Configuring C library
[EXTRA]      Installing C library headers
[EXTRA]      Installing C library start files
[INFO ]    Building for multilib 1/1: '': done in 6.76s (at 05:51)
[INFO ]  Installing C library headers & start files: done in 6.81s (at 05:51)
[INFO ]  Saving state to restart at step 'cc_core_pass_2'...
[INFO ]  =================================================================
[INFO ]  Installing pass-2 core C gcc compiler
[EXTRA]    Configuring core C gcc compiler
[EXTRA]    Building gcc
[EXTRA]    Installing gcc
[EXTRA]    Housekeeping for core gcc compiler
[EXTRA]       '' --> lib (gcc)   lib (os)
[INFO ]  Installing pass-2 core C gcc compiler: done in 223.95s (at 09:43)
[INFO ]  Saving state to restart at step 'libc_main'...
[INFO ]  =================================================================
[INFO ]  Installing C library
[INFO ]    =================================================================
[INFO ]    Building for multilib 1/1: ''
[EXTRA]      Cleaning up start files
[EXTRA]      Configuring C library
[EXTRA]      Building C library
[EXTRA]      Installing C library
[INFO ]    Building for multilib 1/1: '': done in 138.54s (at 12:10)
[INFO ]  Installing C library: done in 138.59s (at 12:10)
[INFO ]  Saving state to restart at step 'cc_for_build'...
[INFO ]  Saving state to restart at step 'cc_for_host'...
[INFO ]  =================================================================
[INFO ]  Installing final gcc compiler
[EXTRA]    Configuring final gcc compiler
[EXTRA]    Building final gcc compiler
[EXTRA]    Installing final gcc compiler
[EXTRA]    Housekeeping for final gcc compiler
[EXTRA]       '' --> lib (gcc)   lib (os)
[INFO ]  Installing final gcc compiler: done in 372.21s (at 18:44)
[INFO ]  Saving state to restart at step 'libc_post_cc'...
[INFO ]  Saving state to restart at step 'companion_libs_for_target'...
[INFO ]  =================================================================
[INFO ]  Installing libelf for the target
[EXTRA]    Configuring libelf
[EXTRA]    Building libelf
[EXTRA]    Installing libelf
[INFO ]  Installing libelf for the target: done in 3.55s (at 19:30)
[INFO ]  =================================================================
[INFO ]  Installing expat for target
[EXTRA]    Configuring expat
[EXTRA]    Building expat
[EXTRA]    Installing expat
[INFO ]  Installing expat for target: done in 5.16s (at 19:35)
[INFO ]  =================================================================
[INFO ]  Installing ncurses for target
[EXTRA]    Configuring ncurses
[EXTRA]    Building ncurses
[EXTRA]    Installing ncurses
[INFO ]  Installing ncurses for target: done in 23.32s (at 19:59)
[INFO ]  Saving state to restart at step 'binutils_for_target'...
[INFO ]  Saving state to restart at step 'debug'...
[INFO ]  =================================================================
[INFO ]  Installing cross-gdb
[EXTRA]    Configuring cross gdb
[EXTRA]    Building cross gdb
[EXTRA]    Installing cross gdb
[EXTRA]    Installing '.gdbinit' template
[INFO ]  Installing cross-gdb: done in 115.77s (at 22:38)
[INFO ]  =================================================================
[INFO ]  Installing native gdb
[EXTRA]    Configuring native gdb
[EXTRA]    Building native gdb
[EXTRA]    Installing native gdb
[INFO ]  Installing native gdb: done in 130.08s (at 24:48)
[INFO ]  =================================================================
[INFO ]  Installing ltrace
[EXTRA]    Copying sources to build dir
[EXTRA]    Configuring ltrace
[EXTRA]    Building ltrace
[EXTRA]    Installing ltrace
[INFO ]  Installing ltrace: done in 13.11s (at 25:01)
[INFO ]  =================================================================
[INFO ]  Installing strace
[EXTRA]    Configuring strace
[EXTRA]    Building strace
[EXTRA]    Installing strace
[INFO ]  Installing strace: done in 36.34s (at 25:38)
[INFO ]  Saving state to restart at step 'test_suite'...
[INFO ]  Saving state to restart at step 'finish'...
[INFO ]  =================================================================
[INFO ]  Finalizing the toolchain's directory
[INFO ]    Stripping all toolchain executables
[EXTRA]    Installing the populate helper
[EXTRA]    Installing a cross-ldd helper
[EXTRA]    Creating toolchain aliases
[EXTRA]    Collect license information from: /home/wilson/software/pkg/crosstool-ng/crosstool-ng-1.24.0_build/.build/arm-cortex_a8-linux-gnueabi/src
[EXTRA]    Put the license information to: /home/wilson/software/pkg/crosstool-ng/x-tools/arm-cortex_a8-linux-gnueabi/share/licenses
[INFO ]  Finalizing the toolchain's directory: done in 4.74s (at 26:28)
[INFO ]  Build completed at 20200713.094514
[INFO ]  (elapsed: 26:27.57)
[INFO ]  Finishing installation (may take a few seconds)...
[26:28] / make[9]: Leaving directory '/home/wilson/software/pkg/crosstool-ng/crosstool-ng-1.24.0_build'

附录

arch和cpu的关系

ARMv7和ARMv8是arm的一种标准而不是一块芯片,arm的cortex系列cpu都是采用的这两个体系结构。ARMv7是指32位的arm cpu芯片,ARMv8是指64位的arm cpu芯片。在ARMv7中,常用模式来表示当前所处的状态,而ARMv8则改成了异常等级来描述当前的状态(淘汰了以前的mode)

armv7的系统框架图

从图中可以看到,一个ARMv7的核可能包含以下部分:

  1. cpu processor:这就是我们常说的CPU;

    一个CPU里面,可能存在1到多个cluster,每个cluster包含1到多个processor。在每个cluster里面processor都是从0开始编号的

    cpu

  2. cache: 高速缓存;

  3. scu:缓存同步单元

  4. 在armv7 cortext-m当中没有cache和mmu

ARM 浮点运算

首先我们了解一下有关ARM浮点的几个概念

  1. VFP (vector floating-point)

    VFP(Vector Floating-point Coprocessor for ARM)向量浮点运算单元(协处理器),VFP除了提供浮点数基本运算(加、减、乘、除、开方、比较、取反)提供支持之外,最有特点是它向量(vectors)功能。它同时支持最多8组单精度4组双精度浮点数的运算。

  2. 硬浮点(hard-float)

    编译器将代码直接编译成硬件浮点协处理器(浮点运算单元FPU)能识别的指令,这些指令在执行的时候ARM核直接把它转给协处理器执行。FPU 通常有一套额外的寄存器来完成浮点参数传递和运算。使用实际的硬件浮点运算单元(FPU)会带来性能的提升。

  3. 软浮点(soft-float)

    编译器把浮点运算转成浮点运算的函数调用和库函数调用,没有FPU的指令调用,也没有浮点寄存器的参数传递。浮点参数的传递也是通过ARM寄存器或者堆栈完成。现在的Linux系统默认编译选择使用hard-float,如果系统没有任何浮点处理器单元,这就会产生非法指令和异常。因而一般的系统镜像都采用软浮点以兼容没有VFP的处理器

  4. 总结:

    • 软浮点是通过浮点库去实现浮点运算的,效率低;硬浮点是通过浮点运算单元(FPU)来完成的,效率高
    • 在使用浮点库实现浮点运算(soft-float)时,生成的汇编代码是bl __aeabi_fadd,到转到函数处
    • 使用硬件浮点实现浮点运算(hard-float)时,这是生成了协处理器指令,通过VFP协处理器完成计算

使用硬件浮点实现浮点运算(hard-float)

使用硬件浮点的时候,我们需要给编译器传递一些参数,让编译器编译出硬件浮点单元处理器能识别的指令。

  1. -mfpu=name 指定浮点协处理的类型

    参数-mfpu就是用来指定要产生那种硬件浮点运算指令,常用的有vfp(浮点)和neon(多媒体)等。

    ARM10 and ARM9:
         -mfpu=vfp(or vfpv1 or vfpv2)
         Cortex-A8:
         -mfpu=neon
    
    • NEON

      • NEON 技术是 ARM Cortex™-A 系列处理器的 128 位 SIMD(单指令,多数据)架构扩展,旨在为消费性多媒体应用程序提供灵活、强大的加速功能,从而显著改善用户体验。它具有 32 个寄存器,64 位宽(双倍视图为 16 个寄存器,128 位宽。)

      • 确认处理器是否支持NEON

        cat /proc/cpuinfo
        

        看是否有如下内容

        Features : swp half thumb fastmult vfp edsp neon vfpv3 tlsvfpv4 idiva idivt
        
    • VFP

      • ARM 浮点架构 (VFP) 为半精度、单精度和双精度浮点运算中的浮点操作提供硬件支持。它完全符合 IEEE 754 标准,并提供完全软件库支持。
      • VFP 代表用于矢量运算的矢量浮点架构。也就是浮点协处理的类型
      • VFP经过若干年的发展,有VFPv2 (一些 ARM9 / ARM11)、 VFPv3-D16(只使用16个浮点寄存器,默认为32个)和VFPv3+NEON (如大多数的Cortex-A8芯片) 。对于包含NEON的ARM芯片,NEON一般和VFP公用寄存器。
  2. -mfloat-abi=value

    • -mfloat-abi=soft
      • 等价于-msoft-float,直接调用软浮点实现库
      • GCC编译器已经有这个库了,一般在libgcc里面。这时是采用常用的指令来模拟浮点运算。使用的ARM芯片不支持硬浮点时,可以考虑使用这个参数。
    • -mfloat-abi=softfp,产生硬浮点指令。
      • 表明要使用FPU硬件来做浮点运算,只是,函数的参数传递到整数寄存器(r0-r3)中,然后再传递到FPU中
      • 生成的代码采用兼容软浮点调用接口(即使用-mfloat-abi=soft时的调用接口),这样带来的好处是:兼容性和灵活性。库可以采用-mfloat-abi=soft编译,而关键的应用程序可以采用-mfloat-abi=softfp来编译。特别是在库由第三方发布的情况下。
      • 能兼容带VFP的硬件以及soft-float的软件实现,运行时的连接器ld.so会在执行浮点运算时对于运算单元的选择,是直接的硬件调用还是库函数调用,是执行/lib还是/lib/vfp下的libm
    • -mfloat-abi=hard,产生硬浮点指令
      • 等价于-mhard-float
      • 表明要使用FPU硬件来做浮点运算,并且,函数的参数直接传递到FPU的寄存器(s0、d0)中。
      • 生成的代码采用硬浮点(FPU)调用接口。这样要求所有库和应用程序必须采用这同一个参数来编译,否则连接时会出现接口不兼容错误。
    • 总结
      • soft是指所有浮点运算全部在软件层实现,效率当然不高
      • softfp是目前armel的默认设置,它将浮点计算交给FPU处理,但函数参数的传递使用普通寄存器
      • hard 使用FPU浮点寄存器将函数参数传递给FPU处理
      • gcc编译的时候,使用-mfloat-abi选项来指定浮点运算使用的是哪种
        • soft不使用fpu
        • armel使用fpu,使用普通寄存器
        • armhf使用fpu,使用fpu的寄存器
      • 编译时,kernel、rootfs和app的指定必须一致才行

    eabi:embedded applicaion binary interface,嵌入式二进制接口 armel:arm eabi little endian的缩写,软件浮点。 armhf:arm hard float的缩写,硬件浮点。 arm64:64位的arm默认就是hf的,因此不需要hf的后缀。

常见的芯片和VFP配置

厂商 SoC 架构 VFP SIMD 备注
Freescale iMX5x armv7 VFPv3 NEON Cortex-A8; NEON only reliable in Tape-Out 3 or above
Qualcomm Snapdragon armv7 VFPv3 NEON Qualcomm “Scorpion” core
Samsung S5PC100 armv7 VFPv3 NEON Cortex-A8

ARM V7_VFP,ARM V7_VFPV3 与ARM V7_NEON 介绍

都出现在ARM v7版本,区别如下:

  • ARM V7_VFP只包含VFPv2
  • ARM V7_VFPV3里的VFP改进到了v3版本
  • ARM V7_NEON应该在V3版本上增加了NEON(主要提高媒体和信号处理功能的速度)

VFP

在 ARMv7 体系结构之前,VFP 代表矢量浮点体系结构,并曾用于矢量运算。

对于许多应用来说,设置硬件浮点至关重要,并且硬件浮点可用作使用高级设计工具(如 MatLab、MATRIXx 和 LabVIEW)直接对系统建模和派生应用程序代码的片上系统 (SoC) 设计流程的一部分。在与 NEON™ 多媒体处理功能结合使用时,硬件浮点可用于增强图像应用程序的性能(如缩放、2D 和 3D 转换、字体生成和数字过滤)。

迄今为止,VFP 主要有三个版本:

  • VFPv1 已废弃。要获取详细信息,可向 ARM 发送相关请求。
  • VFPv2 是对 ARMv5TE、ARMv5TEJ 和 ARMv6 体系结构中 ARM 指令集的可选扩展。
  • VFPv3 是对 ARMv7-A 和 ARMv7-R 配置文件中 ARM、Thumb 和 ThumbEE 指令集的可选扩展。可使用 32 个或 16 个双字长寄存器实现 VFPv3。术语 VFPv3-D32 和 VFPv3-D16 用于区别这两个实现选项。可通过半精度扩展对 VFPv3 进行扩展,这些扩展可在半精度浮点和单精度浮点之间提供双向转换功能。

NEON

  • NEON可增强许多多媒体用户体验:提高媒体和信号处理功能的速度
  • 观看任意格式的任意视频
  • 编辑和强化捕获的视频 – 视频稳定性
  • 锯齿消除渲染和合成
  • 游戏处理
  • 快速处理几百万像素的照片
  • 语音识别
  • 强大的多通道高保真音频处理

如何知道某架构是否支持NEON和VFPV

一般而言,SoC的ARM核,都是从ARM买的授权,所有你只需要到对应的SoC的产品介绍以及Datasheet看看其核心即可知道属于那个ARM Core,例如ARMv7-a,然后到ARM去下载对应的ARMv7-a的manual即可知道

另外,在Linux系统运行之后也可输入:

cat /proc/cpuinfo

看到其版本以及支持的指令集。

crosstool-ng中交叉编译前缀的命名规则

arch

即系统架构,常见的有很多种,比如arm,x86,mips等等

vendor

生成厂家,提供商,表示谁提供的,即谁制作出来这个交叉编译器的

vendor的值,貌似是可以自己随便填写的,还有写成编译交叉编译器的作者的自己的名字的

更加通用的做法,好像是:

  • 把vendor写成,CPU的值,比如我之前针对cortex-a8的去配置crosstool-ng的时候,就写了 cortex_a8
  • 或者写成CPU的厂家的名字
  • 或者是开发板的名字

kernel

你用此交叉编译器,编译出来的程序,所运行的目标系统。而对应的环境或系统,主要有两种:

  • linux
    • 比如用交叉编译器编译一个helloworld程序,然后下载到嵌入式开发中的嵌入式Linux中运行,就属于用此交叉编译器,编译出来的程序运行于带OS即嵌入式Linux系统环境
    • arm-cortex_a8-linux-gnueabi中的cortex_a8,就属于CPU的名字
  • bare-metal
    • 编译一个Uboot,或者是其他一个小程序。运行在无嵌入式Linux的时候
    • 比如:m68k-unknown-uclinux-uclibc中的uclinux,就是指的是编译出来的程序,是运行于没有MMU的uclinux下

system

主要表示交叉编译器所选择的库函数和目标系统,最常见的一些值有:gnu,gnueabi,uclibc,gnueabi等等

system中的gnu

  • gnu == gnu libc == glibc。即gnu就是表示用的是glibc的意思。

  • glibc = GNU C Library

    是GNU项(GNU Project)目,所实现的 C语言标准库(C standard library)。

system中的eabi

与此相对应的是oabi

  1. 什么是ABI
    • ABI,application binary interface (ABI),应用程序二进制接口。
    • ABI目的是使得程序的二进制(级别)的兼容
  2. 什么是OABI 和 EABI
    • OABI中的O,表示“Old”,“Lagacy”,旧的,过时的
    • EABI中的E,表示“Embedded”,是一种新的ABI。EABI有时候也叫做GNU EABI。
    • OABI和EABI都是专门针对ARM的CPU来说的
  3. EABI的好处
    • 支持软件浮点和硬件实现浮点功能混用
    • 软件浮点的情况下,EABI的软件浮点的效率要比OABI高很多

system中的uclibc

uclibc,是c库中的一种。crosstool-ng中,目前支持三种:glibc,eglibc,uclibc

  1. glibc

    glibc = GNU C Library。是GNU项(GNU Project)目,所实现的 C语言标准库(C standard library)。

  2. uclibc

    uClibc 是一个小型的C语言标准库,主要用于嵌入式。

    其最开始设计用于uClinux(注:uClinux不支持MMU),因此比较适用于微处理器中。

    对应的,此处的u意思是μ,Micro,微小的意思。

  3. EGLIBC

    Embedded GLIBC,glibc的原创作组织FSF所(新)推出的,glibc的一种变体,目的在于将glibc用于嵌入式系统。Eglibc的最主要特点就是可配置,这样对于嵌入式系统中,你所不需要的模块,比如NIS,locale等,就可以裁剪掉,不把其编译到库中,使得降低生成的库的大小了。

可以简单的理解为:

glibc,uClibc,eglibc都是C语言函数库:

  • uClibc是嵌入式系统中用的(不支持MMU),glibc是桌面系统用的
  • eglibc也是嵌入式系统中用的(资源占用少),是glibc的嵌入式版本,和glibc在源码和二进制上兼容。

总结

  • gnu等价于:glibc+oabi
  • gnueabi等价于:glibc+eabi
  • uclibc等价于:uclibc+oabi(待确认)

举例:交叉编译器中的system的值

  • arm-cortex_a8-linux-gnueabi中的gnueabi,即glibc+eabi
  • mips-ar2315-linux-gnu中的gnu,即glibc+oabi
  • x86_64-unknown-mingw32中的mingw32,用的是Windows下的mingw32的库

交叉编译中的build、host和target

根据GNU惯例,软件构建中涉及到三个平台。

  • 构建平台:编译工具执行的平台
  • 主机平台:编译出来的程序将在其上运行的平台
  • 目标平台:只有在构建编译器时,这才是编译器生成程序运行的平台

当你在为自己的机器构建代码时,这叫原生构建,构建的平台和主机平台是一样的。这种情况下,目标平台没有定义。

当你在为不同的平台构建代码时,这叫做交叉构建,即构建平台与主机平台不同。在这种情况下,目标平台是没有定义的。

很少需要使用目标平台。只有当你在构建编译器的时候才有意义。

例如,当你在Linux机器上构建一个能在Windows上运行的GCC编译器,为Android生成代码。

这里:

  • build: 构建的是你的Linux电脑
  • host:主机是Windows电脑
  • target:目标是Android。

在使用crosstool-NG 给 cortex-a8 编译工具链时,出现了如下打印:

[EXTRA]    Building a toolchain for:                                                                                    
[EXTRA]      build  = x86_64-pc-linux-gnu             
[EXTRA]      host   = x86_64-pc-linux-gnu
[EXTRA]      target = arm-cortex_a8-linux-gnueabihf     
  • crosstool-NG 得到 uboot 的情况
    • 执行 crosstool-NG 这个程序的就是 build,也就是我的电脑;
    • 构建出来的是交叉编译工具链 arm-linux-gcc,这些工具链程序要运行的环境就是 host 主机,也是我的电脑;
    • 在host上用工具链编译的arm程序(如uboot),要运行的环境就是 target,也就是arm-cortex_a8-linux-gnueabihf
  • 如果我直接从网上下载了 arm-linux-gcc 这个程序,编译出 uboot,那么
    • build:就是我的PC
    • host:就是 arm-cortex_a8-linux-gnueabihf
    • target:没有定义

uclibc,eglibc,glibc,Musl-libc之间的区别和联系

glibc

Glibc glibc = GNU C Library 是GNU项(GNU Project)目,所实现的 C语言标准库(C standard library)。 目前,常见的桌面和服务器中的GNU/Linux类的系统中,都是用的这套C语言标准库。 其实现了常见的C库的函数,支持很多种系统平台,其功能很全,函数很多,但是代码太多,编译出来的函数库的大小也很大,即资源占用也很多。

uClibc

一个小型的C语言标准库,主要用于嵌入式。 其最开始设计用于uClinux(注:uClinux不支持MMU),因此比较适用于微处理器中。 对应的,此处的u意思是μ,Micro,微小的意思。

uClibc的特点:

  • uClibc比glibc要小很多
  • uClibc是独立的,为了应用于嵌入式系统中,完全重新实现出来的
  • 和glibc在源码结构和二进制上,都不兼容。

eGlibc

EGLIBC = Embedded GLIBC。是glibc的原创作组织FSF所推出的glibc的一种变体,目的在于将glibc用于嵌入式系统。相应最大的改动就在于,把更多的库函数,改为可配置的。这样如果你的嵌入式系统中不需要某些函数,就可以裁剪掉,不把该函数编译到你的eglibc库中,使得最终生成的eglibc库的大小变小,最终符合你的嵌入式系统的要求

Musl-libc

C语言标准库Musl-libc项目发布了1.0版。Musl是一个轻量级的C标准库,设计作为GNU C library (glibc)、 uClibc或Android Bionic的替代用于嵌入式操作系统和移动设备。它遵循POSIX 2008规格和 C99 标准,采用MIT许可证授权,使用Musl的Linux发行版和项目包括sabotage,bootstrap-linux,LightCube OS等等

Linux 线程模型:LinuxThreads 和 NPTL

线程与进程

线程 将应用程序划分成一个或多个同时运行的任务。线程与传统的多任务进程 之间的区别在于:线程共享的是单个进程的状态信息,并会直接共享内存和其他资源。同一个进程中线程之间的上下文切换通常要比进程之间的上下文切换速度更快。因此,多线程程序的优点就是它可以比多进程应用程序的执行速度更快。另外,使用线程我们可以实现并行处理。这些相对于基于进程的方法所具有的优点推动了 LinuxThreads 的实现。

NPTL 的由来

当 Linux 最初开发时,在内核中并不能真正支持线程。LinuxThreads 项目是通过 clone() 系统调用将进程作为可调度的实体。这个调用创建了调用进程(calling process)的一个拷贝,这个拷贝与调用进程共享相同的地址空间。但是这种方法有一些缺点,尤其是在信号处理、调度和进程间同步原语方面都存在问题。另外,这个线程模型也不符合 POSIX 的要求。

在改进 LinuxThreads 的过程中,Red Hat 的一些开发人员开展了 NPTL 项目。NPTL,或称为 Native POSIX Thread Library,是 Linux 线程的一个新实现,它克服了 LinuxThreads 的缺点,同时也符合 POSIX 的需求。NPTL 线程库所引入的一个实现特性是对 ABI(应用程序二进制接口)的支持。这帮助实现了与 LinuxThreads 的向后兼容性。

LD_ASSUME_KERNEL 环境变量

ABI 的引入使得系统可以同时支持 NPTL 和 LinuxThreads 模型。基本上来说,这是通过 ld (一个动态链接器/加载器)来进行处理的,它会决定动态链接到哪个运行时线程库上

举例来说,下面是 WebSphere® Application Server 对这个变量所使用的一些通用设置;您可以根据自己的需要进行适当的设置:

  • LD_ASSUME_KERNEL=2.4.19:这会覆盖 NPTL 的实现。这种实现通常都表示使用标准的 LinuxThreads 模型,并启用浮动堆栈的特性。
  • LD_ASSUME_KERNEL=2.2.5:这会覆盖 NPTL 的实现。这种实现通常都表示使用 LinuxThreads 模型,同时使用固定堆栈大小。

我们可以使用下面的命令来设置这个变量:

export LD_ASSUME_KERNEL=2.4.19

注意,对于任何 LD_ASSUME_KERNEL 设置的支持都取决于目前所支持的线程库的 ABI 版本。例如,如果线程库并不支持 2.2.5 版本的 ABI,那么用户就不能将 LD_ASSUME_KERNEL 设置为 2.2.5。通常,NPTL 需要 2.4.20,而 LinuxThreads 则需要 2.4.1。

如果您正运行的是一个启用了 NPTL 的 Linux 发行版,但是应用程序却是基于 LinuxThreads 模型来设计的,那么所有这些设置通常都可以使用。

大部分现代 Linux 发行版都预装了 LinuxThreads 和 NPTL,因此它们提供了一种机制来在二者之间进行切换。要查看您的系统上正在使用的是哪个线程库,请运行下面的命令:

# getconf GNU_LIBPTHREAD_VERSION
NPTL 2.23

在使用 LinuxThreads 构建库时,需要使用 -D_REENTRANT 编译时标志。这使得库线程是安全的。

最后,也许是最重要的事情,请记住 LinuxThreads 项目的创建者已经不再积极更新它了,他们认为 NPTL 会取代 LinuxThreads。