【ARM 嵌入式 编译系列 2.1 -- GCC 编译参数学习】


请阅读【ARM GCC 编译专栏导读】

上篇文章:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍
下篇文章:ARM 嵌入式 C 入门及渐进 3 – GCC attribute((weak)) 弱符号使用

1.1 GCC 编译参数

上篇文章 ARM 嵌入式 编译系列 2 – GCC 编译过程介绍 已经介绍过了具体的编译流程,本篇文章主要介绍变过程中常见的一些编译参数。

接下来还是以上篇文章中的编译脚本中的内容来展,会逐个介绍脚本中的编译参数及其使用背景。

if PLATFORM == 'gcc':
    # toolchains
    PREFIX = 'arm-none-eabi-'        //指定交叉编译工具为arm-noe-eabi-
    CC = PREFIX + 'gcc'
    AS = PREFIX + 'gcc'              //用于编译
    AR = PREFIX + 'ar'               //用于lib/.a文件的处理:添加/删除/生成/解压等
    CXX = PREFIX + 'g++'
    LINK = PREFIX + 'gcc'
    TARGET_EXT = 'elf'               //用于读取elf 头信息
    SIZE = PREFIX + 'size'
    OBJDUMP = PREFIX + 'objdump'     //用于对elf文件进行反汇编等操作
    OBJCPY = PREFIX + 'objcopy'      //主要用于将elf文文件copy为binary文件
    
    TOOLS_PATH = TOP_ROOT + '/tools/misc'   //指定编译工具所在的路径
    GENIMG = TOOLS_PATH + '/gen_rtos_img.sh' //指定mkimage工具所在的脚本

    DEVICE = ' -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard   \
    				-ffunction-sections -fdata-sections'     //设定编译参数
    CFLAGS = DEVICE + ' -Dgcc'
    AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb '
    LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,
                             -u,Reset_Handler -T board/link.lds' \
    CPATH = ''
    LPATH = ''
    if BUILD == 'debug':
        CFLAGS += ' -O0 -gdwarf-2 -g'
        AFLAGS += ' -gdwarf-2' // 调试信息的存放格式按照 dwarf2标准来
    else:
        CFLAGS += ' -O2'
    CXXFLAGS = CFLAGS
    CFLAGS += ' -std=gnu99' //指定支持的C标准
    CFLAGS += ' -Werror'  // 将将警告升级为错误

上面编译脚本主要分为以下介个部分:

  • 设置交叉编译工具链,这里使用的编译工具套件是 arm-noe-eabi-
  • CFLAGS 编译参数设置;
  • LFLAGS 编译参数设置;
  • AFLAGS 编译参数设置;
  • CXXFLGAS 编译参数设置。

1.1.1 GCC arm-noe-eabi- 介绍

arm-none-eabi-是一个通常用于嵌入式ARM开发的工具链前缀,其中:

  • arm 表示这个工具链是为ARM架构设计的;
  • none 表示这个工具链不是为特定的操作系统设计的;
  • eabi 表示这个工具链支持"Embedded Application Binary Interface",这是ARM为嵌入式应用定义的一种二进制接口标准。

这个工具链通常包括GCC、GDB、Binutils等工具,每个工具的名称通常都会带有 arm-none-eabi-这个前缀,例如 arm-none-eabi-gccarm-none-eabi-gdbarm-none-eabi-as等。

下面是一个使用 arm-none-eabi-gcc 编译ARM程序的例子:

arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard \
 					-ffunction-sections -fdata-sections  -o output source.c

在这个命令中:

  • -mcpu=cortex-m7告诉编译器目标CPU是Cortex-M7,,-mcpu选项只是指定了CPU的类型,但并没有指定指令集。如果你需要指定指令集,可以使用-march选项(用于指定指令集架构)和-mthumb-marm选项(用于在ARM和Thumb指令集之间选择)。
  • -mthumb告诉编译器生成Thumb指令(ARM架构有两种指令集:ARM和Thumb);
  • -mfpu=fpv5-d16 见:ARM 浮点计算单元 FPU (FPA,VFP,NEON)介绍
  • -mfloat-abi=hard 见:ARM 浮点计算单元 FPU (FPA,VFP,NEON)介绍
  • -ffunction-sections :这个选项会让GCC为每个函数生成一个独立的段(section)。这样做的好处是,在链接时,如果某个函数没有被使用(即没有被其他代码引用),链接器可以将其丢弃,从而减小最终生成的可执行文件或库文件的大小。这在嵌入式系统编程中特别有用,因为嵌入式系统的存储空间通常比较有限。
  • -fdata-sections:这个选项会让GCC为每个数据对象(如全局变量)生成一个独立的段(section)。这样做的好处同样是在链接时,如果某个数据对象没有被使用,链接器可以将其丢弃。

需要注意的是,如果你使用了-fdata-sections 和 -ffunction-sections 这两个选项,那么在链接时,你需要使用链接器的–gc-sections选项,告诉链接器进行未使用的段的丢弃。

1.1.1.1 ARM 和 Thumb 指令集区别

ARM和Thumb是ARM处理器支持的两种指令集。它们之间的主要区别在于指令的大小和复杂性:

  • ARM指令集:ARM指令集中的指令是32位的,它提供了大量的寻址模式和操作类型,因此可以编写出非常复杂和高效的代码。但是,由于指令的大小是32位,所以它需要更多的存储空间和更大的代码缓存。

  • Thumb指令集:Thumb指令集中的指令是16位的,它的设计目标是实现代码的高密度,即在同样大小的存储空间中可以存储更多的代码。但是,由于指令的大小只有16位,因此Thumb指令集的寻址模式和操作类型都比ARM指令集少。这意味着,相同的任务,使用Thumb指令集可能需要更多的指令来完成

从ARMv7开始,ARM处理器引入了Thumb-2技术,这是ARM和Thumb的混合指令集,它在实现高代码密度的同时,也提供了与ARM指令集相当的性能。

在编写代码或者配置编译器时,可以根据需要选择使用ARM指令集或者Thumb指令集。例如,如果存储空间非常紧张,可能会优先选择Thumb指令集;而如果对性能有较高要求,可能会选择ARM指令集。

1.1.2 GCC CFLAGS 介绍

在使用GCC编译ARM架构的程序时,使用CFLAGS环境变量来指定编译器选项。这些选项可以控制优化级别、调试信息、警告级别等。

例如,你可以如下设置 CFLAGS(上面一节中的内容也属于CFLAGS):

CFLAGS="-O2 -g -Wall -Werror -std=gnu99 -Dgcc"

在这个例子中:

  • -O2:这是一个优化级别选项。O2表示使用二级优化,这是GCC默认的优化级别,会提供很好的性能,同时不会牺牲太多的编译时间和可调试性;还可以选择 -O3 -O0

  • -g:这个选项会让GCC生成调试信息。这样,即使你的程序被优化,你仍然可以使用gdb等调试器来调试它。

  • -Wall:这个选项会让GCC生成所有的警告信息。使用这个选项可以帮助你发现代码中的潜在问题。

  • -Werror:这个选项会将所有的警告转变为错误。也就是说,如果编译器遇到任何警告,它都会停止编译过程。这个选项可以帮助你确保代码中没有任何可能的问题,因为所有的警告都必须被解决。

  • -std=gnu99:这个选项指定了C语言的标准版本。gnu99代表GNU版本的C99标准。C99标准引入了许多新的语言特性,如内联函数、变长数组、新的数据类型等。gnu99指定了一些额外的GNU特性,如asmtypeof等。

  • -D:这是一个预处理器选项,用于定义宏。例如,-Dgcc会定义一个名为gcc的宏,其值为1。你可以在源代码中使用#ifdef gcc#if defined(gcc)或者#if gcc来检查这个宏是否被定义。

上面编译参数设置好后,可以使用GCC来编译你的程序,如:

arm-none-eabi-gcc ${CFLAGS} -o output source.c

这将会编译source.c并生成一个可执行文件output,并使用你在CFLAGS中指定的编译器选项。

注意,arm-none-eabi-gcc是用于编译ARM架构代码的GCC版本,你需要确保你的系统中已经安装了它。你也需要根据你的实际情况调整CFLAGS的设置。

1.1.3 GCC LDFLAGS 介绍

在使用GCC编译ARM架构的程序时,可以使用LDFLAGS环境变量来指定链接器选项。这些选项可以控制链接器的行为,如指定要链接的库、库的搜索路径、生成 Map 文件等。

如下设置 LDFLAGS

export LDFLAGS="-lm -L/my/lib/path  -Wl,--gc-sections,-Map=rtthread.map,-cref,-u, \
					Reset_Handler -T board/link.lds"

在这个例子中:

  • -lm:这个选项告诉链接器链接数学库(libm)。在你的程序中,如果使用到了数学函数,如sqrt、sin等,需要链接数学库;

  • -L/my/lib/path:这个选项用于指定库的搜索路径。链接器会在这个路径中查找需要的库。你需要根据你的实际情况指定这个路径;

  • –gc-sections:见 1.1.1 接介绍;

  • -Wl,-Map,output.map:这个选项会生成一个Map文件 output.map,其中包含了链接后的程序的内存布局信息。这对于调试和分析程序很有帮助。关于map 文件详细信息见:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍

  • -cref:这个选项会告诉链接器生成一个交叉引用表,这个表列出了哪些符号定义在哪里,哪些地方使用了这些符号。这个信息对于调试和分析程序非常有帮助。生成的交叉引用表会在链接器的输出中显示;

  • -u symbol:这个选项会告诉链接器,无论symbol是否被使用,都将其从库中链接到最终的可执行文件中。这对于强制链接未被直接引用的符号非常有用。-u Reset_Handler告诉链接器,无论Reset_Handler是否被使用,都将其从库中链接到最终的可执行文件中;

  • -T选项可以用来指定自定义的链接脚本,在链接过程中,链接器需要一个链接脚本来控制输出文件的内存布局。链接脚本定义了输出文件中节(section)的顺序和位置,以及如何将输入文件的节映射到输出文件的节。可以在链接脚本中定义内存区域,指定各个节的位置和顺序,定义全局符号等。

然后,你可以使用GCC来编译你的程序,如:

arm-none-eabi-gcc ${CFLAGS} ${LDFLAGS} -o output source.c

这将会编译 source.c并生成一个可执行文件output,并使用你在CFLAGSLDFLAGS中指定的编译器和链接器选项。

注意,arm-none-eabi-gcc是用于编译ARM架构代码的GCC版本,你需要确保你的系统中已经安装了它。你也需要根据你的实际情况调整 LDFLAGS 的设置。

1.1.4 CXXFLAGS 介绍

上文编译脚本中没有怎么用到CXXFLAGS,这里只是简单介绍下。
CXXFLAGS:这个变量用于C++编译器。当你使用G++或类似的工具编译C++程序时,会使用这个变量中的选项。

在编译过程中,如果C和C++源文件混合在一起,那么C文件会使用CFLAGS,C++文件会使用CXXFLAGS。因此,你可以为C和C++编译器指定不同的选项,例如,你可能想要在编译C++代码时启用某些只有C++编译器支持的选项。

注意,虽然许多选项在C和C++编译器之间是通用的,但也有一些选项只对其中一个有效。所以你应根据需要为CFLAGS和CXXFLAGS选择合适的选项。

上篇文章:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍
下篇文章:ARM 嵌入式 C 入门及渐进 3 – GCC attribute((weak)) 弱符号使用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

主公CodingCos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值