Windows (mingw-w64-i686) hosted cross toolchains AArch32 bare-metal target (arm-none-eabi) https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads 使用 arm-none-eabi-gcc 交叉编译链只能编译 ARM 架构的裸机系统（包括 ARM Linux 的 boot、kernel，不适用编译 Linux 应用 Application） 有关浮点数： 查看 gcc 的默认 define： $ ./arm-none-eabi-gcc -x c - -E -dM </dev/null|grep SOFT #define __SOFTFP__ 1 -mfloat-abi=name Specifies which floating-point ABI to use. Permissible values are: ‘soft’,‘softfp’ and ‘hard’. ABI，application binary interface (ABI)，应用程序 二进制接口。 softfp 与 hard 都使用硬件 FPU 指令，但使用软件接口。hard 则使用硬件接口。所以 soft 与 softfp 兼容，他们与 hard 不兼容。 当 -mfloat-abi=soft 时 会定义 #define __SOFTFP__ 1 当为 softfp 或 hard 时，不会定义 __SOFTFP__ 而 __VFP_FP__ 总是定义的（#define __VFP_FP__ 1），即使 -mfloat-abi=soft 时。 源码头文件有这样的定义： #elif defined ( __GNUC__ ) #if defined (__VFP_FP__) && !defined(__SOFTFP__) #if (__FPU_PRESENT == 1) #define __FPU_USED 1 #else #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #define __FPU_USED 0 #endif #else #define __FPU_USED 0 #endif 也就是说，在定义了 softfp 或 hard 时，当 __FPU_PRESENT 为 1 时，会定义 #define __FPU_USED 1，也就是要启用 FPU。__FPU_PRESENT 需要用户自己定义。 当使用 hard 或者 softfp 时，必须同时指定 FPU： -mfpu= option supports the following FPU types: vfp, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16, neon, neon-fp16, vfpv4, vfpv4-d16, fpv4-sp-d16, neon-vfpv4, fp-armv8, neon-fp-armv8, and crypto-neon-fp-armv8. cortex-m4 选择：fpv4-sp-d16
这里介绍使用 ipkg 安装的方法。ipkg bootstrap 的安装脚本在这里选择： http://ipkg.nslu2-linux.org/optware-ng/bootstrap/ 由于我的 NAS 是 X86 CPU 架构的，所以选择了 buildroot-x86_64-bootstrap.sh。 [...]
MDK 自带的编译器是 ARMCC 或 ARMCLANG（Arm Compiler 6），有时需要使用 GCC 编译器（例如需要使用 GCC 编译的静态库）。当然，用 GCC 不一定非要用 MDK IDE。 先去 ARM 官网下载 GNU 工具链（Arm GNU Toolchain） Arm GNU Toolchain is a community supported pre-built GNU compiler toolchain for Arm based CPUs. Arm GNU Toolchain releases consists of cross toolchains for the following host operating systems: GNU/Linux Available for x86_64 and AArch64 host architectures Available for bare-metal and Linux targets Windows Available for x86 host architecture only (compatible with x86_64) Available for bare-metal and Linux targets macOS Available for x86_64 host architecture only Available for bare-metal targets only [...]
交叉编译器 gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi 的区别
命名规则 交叉编译工具链的命名规则为：arch-vendor-os-(gnu)eabi arch - 体系架构，如 ARM，MIPS vendor - 工具链提供商 os - 目标操作系统 eabi - 嵌入式应用二进制接口（Embedded Application Binary Interface） 根据对操作系统的支持与否，ARM GCC 可分为支持和不支持操作系统，如： arm-none-eabi：这个是没有操作系统的，自然不可能支持那些跟操作系统关系密切的函数，比如 fork。它使用的是 newlib 这个专用于嵌入式系统的 C 库。 arm-none-linux-eabi：用于 Linux 的，使用 Glibc 命名实例 1. arm-none-eabi-gcc （ARM architecture，no vendor，not target an operating system，complies with the ARM EABI） 用于编译 ARM 架构的裸机系统（包括 ARM Linux 的 boot、kernel，不适用编译 Linux 应用 Application），一般适合 ARM7、Cortex-M 和 Cortex-R 内核的芯片使用，所以不支持那些跟操作系统关系密切的函数，比如 fork，他使用的是 newlib 这个专用于嵌入式系统的 C 库。 2. arm-none-linux-gnueabi-gcc (ARM architecture, no vendor, creates binaries that run on the Linux operating system, and uses the GNU EABI) 主要用于基于 ARM 架构的 Linux 系统，可用于编译 ARM 架构的 u-boot、Linux 内核、Linux 应用等。arm-none-linux-gnueabi 基于GCC，使用 Glibc 库，经过 Codesourcery 公司优化过推出的编译器。arm-none-linux-gnueabi-xxx 交叉编译工具的浮点运算非常优秀。一般 ARM9、ARM11、Cortex-A 内核，带有 Linux 操作系统的会用到。 3. arm-eabi-gcc Android ARM 编译器。 4. armcc ARM 公司推出的编译工具，功能和 arm-none-eabi 类似，可以编译裸机程序（u-boot、kernel），但是不能编译 Linux 应用程序。armcc 一般和 ARM 开发工具一起，Keil MDK、ADS、RVDS 和 DS-5 中的编译器都是 armcc，所以 armcc 编译器都是收费的。 5. arm-none-uclinuxeabi-gcc 和 arm-none-symbianelf-gcc arm-none-uclinuxeabi 用于 uCLinux，使用 Glibc。 arm-none-symbianelf 用于 Symbian，没用过，不知道 C 库是什么 。 ABI 和 EABI ABI：二进制应用程序接口（Application Binary Interface (ABI) for the ARM Architecture）。在计算机中，应用二进制接口描述了应用程序（或者其他类型）和操作系统之间或其他应用程序的低级接口。 EABI：嵌入式 ABI。嵌入式应用二进制接口指定了文件格式、数据类型、寄存器使用、堆积组织优化和在一个嵌入式软件中的参数的标准约定。开发者使用自己的汇编语言也可以使用 EABI 作为与兼容的编译器生成的汇编语言的接口。 两者主要区别是，ABI 是计算机上的，EABI 是嵌入式平台上（如 ARM，MIPS 等）。 arm-linux-gnueabi-gcc 与 arm-linux-gnueabihf-gcc 两个交叉编译器分别适用于 armel 和 armhf 两个不同的架构，armel 和 armhf 这两种架构在对待浮点运算采取了不同的策略（有 FPU 的 ARM 才能支持这两种浮点运算策略）。 其实这两个交叉编译器只不过是 gcc 的选项 -mfloat-abi 的默认值不同。gcc 的选项 -mfloat-abi 有三种值 soft、softfp、hard（其中后两者都要求 ARM 里有 FPU 浮点运算单元，soft 与后两者是兼容的，但 softfp 和 hard 两种模式互不兼容）： soft： 不用 FPU 进行浮点计算，即使有 FPU 浮点运算单元也不用，而是使用软件模式。 softfp： armel 架构（对应的编译器为 arm-linux-gnueabi-gcc）采用的默认值，用 FPU 计算，但是传参数用普通寄存器传，这样中断的时候，只需要保存普通寄存器，中断负荷小，但是参数需要转换成浮点的再计算。 hard： armhf 架构（对应的编译器 arm-linux-gnueabihf-gcc）采用的默认值，用 FPU 计算，传参数也用 FPU 中的浮点寄存器传，省去了转换，性能最好，但是中断负荷高。 把以下测试使用的 C 文件内容保存成 mfloat.c： #include <stdio.h> int main(void) { double a, b, c; a = 23.543; b = 323.234; c = b / a; printf("the 13/2 = %f\n", c); printf("hello world !\n"); return 0; } 1、使用 arm-linux-gnueabihf-gcc 编译，使用 -v 选项以获取更详细的信息： # arm-linux-gnueabihf-gcc mfloat.c -v ... COLLECT_GCC_OPTIONS='-v' '-mfloat-abi=hard' '-mtls-dialect=gnu' '-mthumb' '-mlibarch=armv7-a+fp' '-march=armv7-a+fp' '-dumpdir' 'a.' 可看出使用了 hard 硬件浮点模式。 2、使用 arm-linux-gnueabi-gcc 编译： # arm-linux-gnueabi-gcc -v mfloat.c -mfloat-abi=softfp ... COLLECT_GCC_OPTIONS='-v' '-mfloat-abi=softfp' '-mtls-dialect=gnu' '-marm' '-mlibarch=armv5t' '-march=armv5t' '-dumpdir' 'a.' 可看出使用 softfp 模式。 我测试用的 GCC 版本是 11.4.0，arm-linux-gnueabihf-gcc 只支持 -mfloat-abi=hard，而 arm-linux-gnueabi-gcc 则支持 -mfloat-abi=soft 与 -mfloat-abi=softfp 两种模式。
交叉编译 交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序，比如在 PC 平台（X86 CPU）上编译出能运行在以 ARM 为内核的 CPU 平台上的程序，编译得到的程序在 X86 CPU 平台上是不能运行的，必须放到 ARM CPU 平台上才能运行，虽然两个平台用的都是 Linux 系统。 交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境，交叉编译工具链主要由 binutils、gcc 和 glibc 三个部分组成。有时出于减小 libc 库大小的考虑，也可以用别的 c 库来代替 glibc，例如 uClibc、dietlibc 和 newlib。建立交叉编译工具链是一个相当复杂的过程，如果不想自己经历复杂繁琐的编译过程，网上有一些编译好的可用的交叉编译工具链可以下载，但就以 学习为目的来说读者有必要学习自己制作一个交叉编译工具链（目前来看，对于初学者没有太大必要自己交叉编译一个工具链）。 分类和说明 从授权上，分为免费授权版和付费授权版。 免费版目前有三大主流工具商提供，第一是 GNU（提供源码，自行编译制作），第二是 Codesourcery，第三是 Linora。 arm-none-linux-gnueabi-gcc：是 Codesourcery 公司（目前已经被 Mentor 收购）基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARM（32位）系统中所有环节的代码，包括裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 arm-linux-gnueabihf-gcc：是由 Linaro 公司基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARM（32位）系统中所有环节的代码，包括裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 aarch64-linux-gnu-gcc：是由 Linaro 公司基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARMv8 64 位目标中的裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 arm-none-elf-gcc：是 Codesourcery 公司（目前已经被 Mentor 收购）基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译ARM MCU（32位）芯片，如 ARM7、ARM9、Cortex-M/R 芯片程序。 arm-none-eabi-gcc：是 GNU 推出的的ARM交叉编译工具。可用于交叉编译 ARM MCU（32位）芯片，如 ARM7、ARM9、Cortex-M/R 芯片程序。 收费版有 ARM 原厂提供的 armcc、IAR 提供的编译器等等，因为这些价格都比较昂贵，不适合学习用户使用，所以不做讲述。
使用高版本的 GCC 编译的程序在低版本 glibc 的机器上运行的时候会提示： libc.so.6: version 'GLIBC_2.14' not found 之类的错误，这是因为 GCC 所连接的 glibc 版本高于目标系统的 glibc 的版本。查看 libc.so.6 所支持的版本的方法： strings /lib/libc.so.6 | grep GLIBC_。 解决这一问题要么升级系统的 libc，要么使程序使用自己的一套 libc 。如果选择后者，需要在连接的时候指定库的优先搜索位置。并且还要指定 ld-linux.so 的位置，否则会提示段错误 Segmentation fault。 QMAKE_LINK += -Wl,-rpath=./lib:/usr/local/bs230/lib -Wl,-dynamic-linker=/usr/local/bs230/lib/ld-linux.so.3 注意：使用相对路径时所相对的是执行者所在的位置（pwd） 比如在 /home 调用 /usr/local/bs230/bsinfo 会在查找 /home/lib 文件夾，而不是 /usr/local/bs230/lib