恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
ARM Compiler 5.06 安装切换与 AC5/AC6 迁移避坑指南
首页
资讯中心
/
ARM Compiler 5.06 安装切换与 AC5/AC6 迁移避坑指南
ARM Compiler 5.06 安装切换与 AC5/AC6 迁移避坑指南
发布时间:2026/10/16 10:12:53
简介面向嵌入式硬件开发者ARM Compiler 5.06 官方工具链资源提供了在 Keil MDK 5.37 中单独配置并使用该经典编译器版本所需的完整文件适用 Cortex-A/R/M 内核及 ARMv4 到 ARMv8-A 指令集帮助开发者高效构建嵌入式软件。压缩包共 3 个文件以 Windows 安装程序exe、MSI 安装包和 HTML 格式的发行说明为主整体约 80.94MB便于安装前了解版本更新细节并保留安装与配置所需的组件。目前已有 15915 人学习在嵌入式开发社区中受到广泛关注适合具有一定 ARM 基础并希望提升编译效率的开发者参考使用。借助这套资料开发者可获得包含 armcc、armasm、armlink 在内的完整编译器工具链利用改进的代码优化、调试支持和数学库生成更小更快的机器码同时理顺其在 Keil MDK 5.37 中的集成方式提升代码质量与工程效能。1. 从 KEIL 报错说起为什么还要找 ARM Compiler 5.06用 KEIL 打开一个下载来的老工程编译按钮按下去直接红一片报错说compiler not found或者AC5 is not installed。如果你手头是新装的 MDK默认只有 AC6这时候八成会愣住都 2025 年了怎么还要装一个 2018 年的老编译器答案是老芯片厂家的 SDK、老项目的启动文件、某些只在 AC5 下能编译过的内嵌汇编代码AC6 就是不吃。ARM Compiler 5.06 是 AC5 家族最后的稳定版本也是无数老工程的后悔药。这篇笔记围绕 ARM Compiler 5.06 的安装、切换、编译和踩坑全过程展开适合刚接手老项目的嵌入式开发者也适合准备把 AC5 工程往 AC6 迁移、需要先摸清两边差异的熟手。2. AC5 与 AC6 的本质差异搞清楚再动工程2.1 AC5 是什么AC6 又是什么ARM Compiler 5.06 是 ARM 官方推出的第五代编译器工具链的最终版本官方代号 armcc发布于 2018 年前后。后面 ARM 转向了基于 LLVM 的第六代编译器 armclang也就是 AC6。两者编译器的前端、优化器、代码生成器完全两套不是简单地升级版本号。AC5 的核心战场是 Cortex-M0/M0/M3/M4/M7 这类老一代 MCU以及 ARM7/ARM9/ARM11 这些更老的架构。绝大多数芯片厂商的老固件库、标准外设库都是基于 AC5 编译验证过的。比如早期的标准外设库代码里大量使用__asm内嵌汇编AC6 直接不认这个关键字必须改成asm或重构工程量不小。AC6 的正式名称是 armclang基于 LLVM 架构对 C99/C11 支持完善编译速度更快优化效果在某些场景下比 AC5 好不少。但它有个老工程非常头疼的特点——对语法检查更严格AC5 能容忍的很多写法AC6 直接报 warning 或者 error。比如 AC5 里隐式函数声明只给警告AC6 直接 error。这一点在迁移老代码时是最容易翻车的。2.2 功能差异对比表对比项ARM Compiler 5.06 (AC5)ARM Compiler 6 (AC6)编译器核心armcc (ARM 自研)armclang (LLVM)支持标准仅部分 C99C90 为主完整 C99/C11部分 C17内嵌汇编支持__asm不支持__asm需改用asm优化选项-O0/-O1/-O2/-O3/-Os/-Oz-O0/-O1/-O2/-O3/-Os/-Oz编译警告宽松很多问题只给 warning严格很多 warning 升级为 error输出文件.axf/.o/.d.axf/.o/.d支持架构ARMv4 到 ARMv7 全系列ARMv6-M 到 ARMv8-M支持更完整老固件库兼容性好差异大常需改代码AC5 对老架构的支持跨度非常大从 ARMv4 到 ARMv7-A/R 都有对应的编译 target。这意味着很多古董级芯片的工程只有 AC5 才能编译通过。AC6 主要是 Cortex-M 系列和 Cortex-A 系列老 ARM7TDMI 之类的基本不受支持。2.3 为什么 5.06 是最后的版本编译工具链和普通软件不一样没有常更常新的逻辑。AC5 从 5.01 一路迭代到 5.06期间补了大量针对 Keil MDK 和 CMSIS 的适配。5.06 后面还出了几个 update 版本u1 到 u7每个 update 修一批 bug。很多工程目录里写死的是ARM_Compiler_5.06u7如果你只装了裸的 5.06 不带 update编译时可能出现某些内建宏不一致的情况。老版本编译器停更不是因为它不行而是 ARM 认为 AC6 已经足够成熟。但对嵌入式老工程的维护场景来说AC5 的稳定性和兼容性恰好是它最大的价值。很多芯片原厂的 BSP 包在发布时就是用 AC5 编译验证的你换了 AC6 之后即使能编过也可能会因为优化差异导致运行行为不一致。3. 安装与编译器切换实操路径、版本、配置一次到位3.1 先确认当前 MDK 的编译器状态打开 Keil MDK菜单栏选Project→Manage→Project Items然后切到Folders/Extensions标签页看Default File Path和ARM Compiler下拉框当前选中的是什么。这一步非常关键因为 MDK 允许同时安装多个编译器版本通过下拉框选择具体用哪个。常见的情况是你装了 MDK 5.x默认只有 AC6。AC5 需要单独安装。安装方式有两种一是从 ARM 官网下载ARM Compiler 5.06 update的安装包路径一般会指向C:\Keil_v5\ARM\ARM_Compiler_5.06u7二是通过 MDK 的 Pack Installer 搜索ARM Compiler相关 pack 在线安装。先来看一个快速验证当前编译器版本的命令行操作。打开 KEIL 安装目录下的命令行工具或者直接在 Windows CMD 里切到编译器目录cd C:\Keil_v5\ARM\ARM_Compiler_5.06u7\bin armcc --version执行完会看到类似如下的输出Product: ARM Compiler 5.06 update 7 (build 57) Component: ARM/Compilers/5.06u7这里有个很容易踩的坑如果你只安装了裸的 5.06 没有 update输出会是5.06 (build 756)这会导致工程的芯片支持包或启动文件在编译时出现版本判断失败。因为很多老工程的.uvprojx文件里写死了编译器版本号MDK 打开工程时发现版本不匹配会直接切换回默认编译器而不是报错——然后你编译时看到一堆莫名其妙的语法错误其实是编译器版本不对。3.2 手动切换工程编译器版本安装好 AC5 之后打开工程进入Project→Manage→Project Items→Folders/Extensions在ARM Compiler下拉框里选择Use default toolchain version或直接指定已安装的具体版本。这里我一般会选择指定版本写清楚是ARM_COMPILER_5.06u7避免 MDK 帮我们选了不想要的默认值。接着在Options for Target→Target标签页确认Code Generation里的ARM Compiler显示的是compiler version 5.06。这一步不核对的话后面编译时会出现一种经典问题.s启动文件里用了一些老汇编语法AC6 的汇编器直接报错但错误提示非常不明确。工程切换完成后建议先执行一次Project→Clean Target再重新Build Target。因为 AC5 和 AC6 的中间产物格式不完全兼容.o文件混用会出现 link 阶段找不到符号或者重复定义的问题。尤其是有多个子工程或库工程的情况下必须把之前 AC6 编译的.o文件全部清掉。某一次我把 A 芯片的库工程从 AC6 切到 AC5忘了 clean硬生生报了一个半小时的错最后还是靠Clean Target解决。3.3 命令行调用与 Makefile 集成如果你不是用 KEIL GUI 而是用 CI 或 Makefile 来编译AC5 支持命令行完整编译。典型的命令行调用如下C:\Keil_v5\ARM\ARM_Compiler_5.06u7\bin\armcc --cpu Cortex-M3 -c -D__EVAL -I.\RTT -I.\App -o .\build\main.o .\App\main.c各参数含义说明--cpu Cortex-M3指定目标芯片内核架构这里以 Cortex-M3 为例-c仅编译不链接生成.o文件-D__EVAL定义宏告诉代码当前处于评估板环境很多 SDK 里会根据这个宏切换引脚配置-I.\RTT和-I.\App指定头文件搜索路径注意 AC5 对路径大小写不敏感但 AC6 严格区分-o .\build\main.o指定输出文件路径最后是待编译的源文件AC5 的命令行参数风格和 GCC 非常不一样它自己的--help列表非常长但日常项目里最常用的就--cpu、-c、-D、-I、-O这几个。如果在 Makefile 中混用了 GCC 风格的参数比如-mcpuAC5 会直接提示无法识别的选项编译中断。3.4 头文件搜索路径的兼容性坑AC5 对头文件搜索路径的处理逻辑和 AC6 有差异。AC5 默认会先搜索当前源文件所在目录然后再按-I指定的顺序搜索。而 AC6 的行为更接近 GCC不自动包含源文件所在目录必须显式指定-I.。这意味着从 AC5 迁移到 AC6 时大量#include bsp_uart.h这类和源文件同目录的头文件会突然失效。反过来从 AC6 切回 AC5 一般没问题因为 AC5 自动搜索当前目录等于多了一层保险。解决这个问题我在工程里统一采用绝对路径或者相对项目根目录的路径并保证每个模块的-I都写得清清楚楚。比如#include drivers/bsp_uart.h而不是#include bsp_uart.h这样可以确保两个编译器下头文件都能正确找到避免迁移时大面积翻车。4. 实际编译流程从打开工程到生成镜像的完整走查4.1 用 AC5 编译一个典型 Cortex-M 工程一个典型的基于标准外设库的工程编译流程分为编译汇编启动文件、编译 C 源文件、链接三个大步骤。我们先看启动文件编译AC5 自带的汇编器是armasm它和 GNU 的as语法兼容性一般。老的启动文件比如某芯片标准库自带的startup_stm32f10x_hd.s是为 armasm 写的必须用 AC5 编译。使用 KEIL GUI 时不需要手动执行编译命令MDK 会根据工程配置自动调用对应的工具。但如果你想知道每一阶段具体执行了什么可以打开Options for Target→Listing勾选Assembly Listing然后在 Build Output 窗口里看完整命令行日志。一个典型的编译输出片段如下armcc --cpu Cortex-M3 -D__EVAL -DUSE_STDPERIPH_DRIVER -I.\FWLib\inc -I.\User -o .\Build\main.o .\User\main.c armasm --cpu Cortex-M3 -o .\Build\startup_stm32f10x_hd.o .\Startup\startup_stm32f10x_hd.s armlink --scatter .\Project.icf --entry Reset_Handler -o .\Build\Project.axf .\Build\*.o这三条命令分别对应用户代码编译、启动汇编文件编译、链接生成镜像。armlink的加载脚本scatter 文件是整个链接阶段的核心它决定了代码段、数据段、堆栈段的地址布局。4.2 编译错误排查的通用思路AC5 的编译错误信息格式是source_file.c:line: error: #xxx: message text。这里的#xxx是错误编号比如#20是未定义标识符#65是语法错误。排查时不要只看错误描述行建议把完整上下文贴出来因为 AC5 有时候报错位置和实际出问题位置相差几行。常见的一种情况是宏定义冲突。某个工程头文件里定义了#define GPIO_Pin_0 ((uint16_t)0x0001)但编译时出现error: #20: identifier GPIO_Pin_0 is undefined第一时间不是去查头文件是否包含而是去查Options for Target→C/C→Preprocessor Symbols里的宏定义。因为工程配置中如果定义了USE_STDPERIPH_DRIVER但宏定义路径写错会导致整个外设库的声明失效。另外建议把--no_unaligned_access这个编译选项记下来。Cortex-M0 和 M0 不支持非对齐访问老代码里如果出现uint32_t *p (uint32_t *)(ptr 1)这种写法AC5 默认会生成非对齐访问的代码在 M0 上运行会触发硬件错误。加上--no_unaligned_access会让编译器生成保守的字节访问代码避免运行期翻车代价是代码体积略有增加。4.3 查看编译产物验证结果编译成功后MDK 默认输出.axf文件这是 ARM 的 ELF 格式镜像。通过.map映射文件可以检查各段的内存布局。我一般重点看三块内容Execution Region的起始地址和大小确认是否超出芯片的 Flash/RAM最大栈使用量AC5 会在 map 文件末尾给出Stack used的估算峰值是否有未使用的 section 被优化掉防止某些中断向量表被编译器丢弃查看 map 文件的常用工具是 fromelf命令行如下fromelf --text -c -s C:\Keil_v5\ARM\ARM_Compiler_5.06u7\bin\fromelf .\Build\Project.axf以下是一条实际查看反汇编的命令示例fromelf --text -c -o .\Build\Project.dis .\Build\Project.axf反汇编文件.dis里能直接看到每条 C 语句对应的汇编指令当怀疑优化器把代码改出问题时打开这个文件对照是最快的排查手段。5. 避坑指南AC5 编译器的七个高频问题与排查记录5.1 编译器版本显示不一致现象MDK 工程配置里选的是 AC5编译日志却显示 armclang 的调用路径编译报错内容也是 AC6 风格的。原因工程是旧版 MDK 创建的.uvprojx文件里记录的编译器 UUID 和当前安装的版本不匹配MDK 自动回退到默认编译器。解决手动在Project→Manage→Project Items→Folders/Extensions中强制选择目标编译器版本然后 Clean 后重编。5.2__asm关键字报错或行为异常现象编译通过但运行结果不对进到内嵌汇编部分时程序跑飞。原因AC5 的内嵌汇编语法要求用__asm而不是asm且汇编代码块内的注释符号必须用/* */而不是//因为 armcc 的前端会先按 C 语法解析。解决检查所有内嵌汇编代码统一改为__asm { MOV R0, #0 /* 这里只能用块注释 */ }如果是从 AC6 工程反向迁移到 AC5还需要注意asm关键字改成__asm后原本在 clang 里合法的寄存器约束写法在 AC5 里可能不支持。5.3 头文件路径大小写导致找不到文件现象在 Windows 下编译没问题把工程拷到 Linux 服务器用命令行编译报找不到头文件。原因AC5 命令行工具在 Windows 下对路径大小写不敏感但在类 Unix 环境下严格区分大小写。解决统一将工程头文件引用改为和实际文件名完全一致的大小写并在.h文件内部也检查所有#include语句。这一条在 CI 环境下最坑本地编得好好的一上服务器就翻车。5.4 GCC 风格代码在 AC5 下不兼容现象从某些开源项目拿来的代码编译时报大量error: #18: expected a )。原因AC5 并不支持 GCC 的一些扩展语法比如__attribute__((packed))的写法在 AC5 里部分支持但不支持__attribute__((aligned(4)))的变量级修饰。解决对于结构体对齐问题改用#pragma pack或者在目标文件中用条件编译区分#if defined(__ARMCC_VERSION) #pragma pack(push, 1) #else #pragma pack(push, 1) #endif__ARMCC_VERSION这个宏在 AC5 和 AC6 中都存在只是值不同条件编译可以同时兼容两套编译器。5.5 浮点 ABI 不一致导致链接失败现象编译单个.c文件顺利通过链接时报错说 undefined symbol__aeabi_f2d或类似浮点相关符号。原因工程中不同源文件用了不同的浮点 ABI 选项比如一个文件编译时启用了硬件浮点--fpuFPv5另一个文件用的是软件浮点--fpuNone导致链接时函数调用约定不一致。解决在Options for Target→Target→Floating Point Hardware里统一全工程的浮点选项并以实际芯片型号为准。Cortex-M4F 选单精度Cortex-M7F 选双精度M0/M0 选Not used。5.6 编译时间异常慢现象全量编译耗时是 AC6 编译同一工程的三倍以上。原因AC5 的优化器比 AC6 慢是正常的尤其在开启-O3时某些大函数的编译时间会呈指数级增长。解决把编译优化等级降低到-O1或-Os如果只是调试阶段用-O0。另外可以检查是否同时生成了 Browse Information 文件在Options for Target→Output里关闭Browse Information也能明显加速编译。5.7 优化导致变量丢失现象Debug 模式下变量值异常或者某个外设寄存器的值怎么都不对。原因AC5 在-O2以上会根据数据流分析优化掉那些看起来没用的赋值。解决对外设寄存器的操作必须使用 volatile 指针推荐直接用芯片头文件里的__IO宏定义。特殊情况必须保留某个变量时可以这样volatile uint32_t keep_this_value 0;6. 新旧迁移的技巧AC5 工程如何平滑过渡到 AC66.1 迁移前的工程体检清单从 AC5 迁到 AC6先对现有工程做一个静态扫描方法如下grep -r __asm --include*.c --include*.h ./ grep -r #pragma pack --include*.c --include*.h ./ grep -r __attribute__ --include*.c --include*.h ./这三条命令分别找出内嵌汇编代码、pragma pack 用法和 attribute 修饰。这三类是 AC5 和 AC6 差异最大的地方。扫描结果出来后逐个文件评估改动量改动量太大就放弃迁移留在 AC5 继续维护改动量小才值得动手。6.2 分文件迁移与条件编译不建议一次性把整个工程切到 AC6我常用的做法是按模块迁移。先把不涉及底层汇编和复杂指针操作的模块切过去比如协议栈、算法库、用户业务逻辑这些代码通常 ANSI C 风格AC6 也能顺利编译。底层寄存器操作、启动文件和芯片 SDK 相关代码暂时留在 AC5。在头文件里做版本分支#if defined(__ARMCC_VERSION) (__ARMCC_VERSION 6000000) /* AC5 下的实现 */ #else /* AC6 下的实现 */ #endif__ARMCC_VERSION在 AC5 下的值是类似5060067AC6 下是6000000以上十位数。这种方法可以维持一个共用代码库同时兼容新旧两种编译环境。6.3 优化选项的换算关系AC5 的-O3和 AC6 的-O3不是一回事。AC5 的-O3可能会生成体积更大的代码来换取速度AC6 的-O3则比较均衡。迁移后建议先以-O0编译验证功能再逐级提升优化选项不要直接沿用 AC5 的参数配置。这里我踩过一次坑某个协议栈在 AC5-O2下运行稳定迁移到 AC6-O2后出现随机死机排查后发现是 AC6 对某个未初始化结构体的优化行为和 AC5 不一致改掉未初始化字段后恢复正常。6.4 最终落地检查流程迁移完成后强制走一套检查流程确认编译零错误零警告用fromelf比较迁移前后生成的 map 文件中的函数地址和大小在目标板上跑完整的自测用例检查.map文件中栈使用量AC6 的栈估算方式和 AC5 略有不同检查中断延时AC6 对中断服务函数的优化可能改变现场保存方式从那以后我每次拿到老工程都强制走一遍确认芯片型号、确认编译器版本、确认启动文件、确认预定义宏的前置检查顺序再把工程切到目标编译器上编译。返回顶部本文还有配套的精品资源点击获取