上周帮同事处理一个环境迁移问题他把开发环境从 MDK 5.30 升到 5.37结果一打开老工程直接编译报错弹出来的提示特别干脆Target uses ARM-Compiler Arm Compiler 5 which is not available。第一次看到这个错误的人很容易慌以为工程文件坏了或者某个路径设置丢了。其实根本不是工程的问题而是 MDK 5.37 默认不再安装 ARMCC V5 编译器老工程里还明确写着用 V5 编译自然就罢工了。这篇文章就来解决这个问题完整讲清楚为什么升级会报错、ARMCC V5 和 AC6 到底差在哪、怎么从官方渠道把 V5 装回来、怎么把工程切回老编译器以及升级过程中必然会遇到的fromelf路径、启动文件、CMSIS 等一堆坑。如果你正在维护老芯片项目、旧代码库或者刚从 5.36 以下版本升上来这篇文章应该能帮你少绕一大圈弯路。1. 为什么MDK 5.37升级后编译就崩了1.1 5.37改掉的默认编译器先明确一个背景知识MDK 自带两套编译器体系一套是老牌的 ARMCC V5另一套是基于 Clang/LLVM 的 armclang也就是 AC6。在 MDK 5.36 及以前的安装包里两套编译器通常都预置好装完就能用。但从 5.37 开始Arm 官方调整了策略安装包默认只带 AC6ARMCC V5 不再预装。官方这样做的理由也合理AC5 已经进入维护模式官方不会再给它加新特性而新芯片、新 CMSIS 版本、新中间库基本都是按 AC6 适配的。但对于大量存量工程——尤其是前几年基于 STM32F1/F4、NXP、GD32、华大、极海这类芯片开发的固件——工程文件里写死的还是 AC5。MDK 升级后打开这类工程系统一看“工程要求 V5但我这边没有 V5”就直接报出开头那个错误。还有一个很容易忽略的点即使你强行用 AC6 打开老工程也不代表能顺利编译。AC6 对语法检查严格得多老工程里很多“能跑就行”的写法在 AC5 下可能只是警告到 AC6 下直接变成致命错误。所以如果你的工作重心在老项目维护上把 V5 装回来反而是最省事的路径。1.2 ARMCC V5与AC6到底差在哪很多朋友对 AC5 和 AC6 的差异没有直观感受总觉得“编译器嘛换哪个不是编译”。实际上两者差距非常大绝对不是换个按钮那么简单。我列个对照表你扫一眼就明白为什么老工程离不开 AC5对比维度ARMCC V5AC5armclangAC6编译核心ARMCC ClassicClang/LLVM默认 C 标准C90/C99 为主C11/C14更严格内联汇编写法__asm { ... }块结构asm(...)字符串形式分散加载文件老式 scatter 语法新式 scatter 语法老芯片启动文件startup_xxx.sarmcc 版需要 armclang 版启动文件对老库的兼容性很好往往需要重新适配编译优化中规中矩更激进但新代码才明显地址绝对定位__attribute__((at(addr)))可用该语法被移除需要用 section 方式关键就在启动文件、分散加载文件和内联汇编这三块。老工程里的startup_stm32f10x_hd.s这类汇编文件很多语法是 AC5 风格放到 AC6 下直接报汇编错误而分散加载文件里的描述符写法两个编译器也有细微差异。这些都不是“重新编译一次”就能解决的要真的迁移到 AC6往往得动启动文件、链接脚本、部分 C 代码工作量相当可观。1.3 升级后常见的报错现象除了开头那个“Target uses ARM-Compiler”提示你升级后还可能撞上下面这些报错先有个印象后面大部分都能在文章对应章节找到解法*** error: createprocess failed, command: c:\keil_v5\arm\armcc\bin\fromelf...多半是路径不对或编译器没装。fatal error: A1167E: Invalid line start一般是启动文件或汇编代码在 AC6 下不兼容。L6218E: Undefined symbol启动文件或某些底层符号没匹配上。armclang.exe: error: unsupported option工程配置里带了 AC5 才认识的编译选项。cannot open source input file core_cm3.h芯片 Pack 或 CMSIS 路径没配好。这些报错有一个共同特征表面上都是“编译不过”但根子都在于编译器体系切换带来的连锁反应。理解了第一层原理后面操作起来心里就有底了。2. 动手前准备确认环境与准备资源2.1 先检查你的MDK是不是真的缺V5在下载任何东西之前先花两分钟确认一下你的 MDK 当前状态。打开任意一个工程或者直接新建一个空工程进入菜单Project - Options for Target - Target在页面右下角找到ARM Compiler下拉框。如果下拉框里只有Use default compiler version 6或者类似compiler 6.x的选项说明 V5 编译器确实没有安装。如果列表里已经能看到V5.06 update 7 (build 960)那就直接跳到第三章做工程配置即可不需要再下载。更直接的办法是打开 MDK 安装目录看一眼默认路径类似C:\Keil_v5\ARM\在这里找有没有ARMCC文件夹。如果ARMCC\bin下面能看到armcc.exe说明编译器已经在系统里了。注意一点MDK 允许安装到任意盘符如果你的开发环境装在 D 盘或其他自定义位置以下所有路径都要相应替换。我自己就见过不少人把 MDK 装在 D 盘然后照着网上的教程硬套C:\Keil_v5结果怎么改都不对。2.2 官方渠道下载ARMCC V5编译器如果你确认缺 V5 编译器下面两种下载安装方式任选一种即可。方式一是通过 Keil 官网的 Legacy Support 下载。打开 Keil 官方下载页面在 MDK v5 相关区域找Legacy Support字样的安装包。这个安装包的目的就是给新版 MDK 补装老版本支持组件其中就包括 ARMCC V5 编译器。下载时注意版本对应关系比如 MDK 5.37 就对应 5.37 版本的 Legacy Support 包不要下错成其他 MDK 版本否则可能出现兼容性问题。方式二是通过 Pack Installer 安装。打开 MDK 的 Pack Installer工具栏上的绿色打包图标或者菜单Project - Manage - Pack Installer在 Packs 页签里搜索ARM_Compiler找到ARM::ARM_Compiler这个包点击 Install 即可。不过根据我实测不同 MDK 小版本的 Pack Installer 对这个包的展示逻辑不完全一致有的版本搜得到有的版本界面里不显示所以如果你在 Pack Installer 里找不到它不用纠结直接走官网下载 Legacy Support 的方式最稳妥。这里我多说一句网上有很多“注册机”和所谓的“激活工具”建议一概不要碰原因很现实。一来这是侵权使用存在法律风险二来这些破解工具经常被挂马或篡改搞不好就把编译环境干出后门。Keil 官方本来就有免费评估版 License代码容量限制 32KB对绝大多数学习和验证场景足够用学生还可以去申请教育许可。顺手把环境做正版化后面少很多麻烦。2.3 安装完成后怎么验证安装包运行起来之后路径选择默认即可它会自动探测到现有 MDK 安装目录并完成集成。安装过程可能出现杀毒软件提示armcc 是正规编译工具属于正常误报放行即可。装完不要急着关电脑先做两步验证第一去C:\Keil_v5\ARM\下面看有没有ARMCC目录并确认ARMCC\bin\armcc.exe存在。第二回到刚才的Options for Target - Target点开ARM Compiler下拉框这时应该能看到V5.06 update 7 (build 960)这个选项了。有这一项说明 V5 编译器已经成功接入 MDK。如果你想进一步确认编译器可执行可以在命令行里切到C:\Keil_v5\ARM\ARMCC\bin目录执行armcc.exe --vsn正常情况下会打印出编译器版本号能看到Product: ARM Compiler 5.06之类的字样。3. 把工程切回ARMCC V5并解决从fromelf到链接的报错3.1 工程目标配置中的编译器切换验证通过之后下一个动作就是把具体工程指到 V5 编译器。打开你的老工程进入Options for Target - Target在ARM Compiler下拉框里选择V5.06 update 7 (build 960)点击 OK。回到编译器界面直接编译大部分情况下就能恢复老工程原有的编译行为。如果你同时打开多个工程或者一个工作区里挂着好几个 Target注意每个 Target 是独立记忆编译器选项的。比如工程里有Debug和Release两个 Target那就要分别检查确认不要改了一个以为全部生效。切换之前最好把工程备份一下或者至少把当前 Options 配置截图存一份。虽然切换编译器本身不会动源码但如果你之前误操作把工程配置改乱过备份能让你随时退回原状。我处理过太多“切换完编译不过”的求助最后发现是 Options 里其他页签选项也被顺手改掉了。3.2 编译环境路径修正fromelf的经典报错编译器切回 V5 之后下一个高频报错就是本文开头热词里提到的那个*** error: createprocess failed, command: c:\keil_v5\arm\armcc\bin\fromelf...。这个报错本质上是工程配置里After Build或Before Build步骤调用了fromelf.exe但路径与当前环境不匹配。老版本 MDK 的 fromelf 路径往往写在C:\Keil_v5\ARM\BIN40\fromelf.exe而新装 V5 之后正确的路径变成了C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe。工程里如果写死了旧路径构建系统执行时找不到文件自然就报 createprocess failed。解决办法很直接进入Options for Target - User页签查看After Build/Rebuild一栏的调用命令。如果里面写的是类似下面这样的内容请修改路径部分C:\Keil_v5\ARM\BIN40\fromelf.exe --bin --output.\Output\Project.bin .\Output\Project.axf改成C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin --output.\Output\Project.bin .\Output\Project.axf这里有两个容易踩的细节。第一路径中不要出现中文和空格否则fromelf和命令行解析经常出问题。第二如果你把编译器切回 V5就不要用ARMCLANG\bin\fromelf.exe而是用ARMCC\bin\fromelf.exe两者虽然都叫 fromelf但匹配的编译产物格式不完全一样混用可能生成不了预期的 bin 文件。还有一种情况是工程里根本没有在 User 页签配置 fromelf而是使用fromelf --text -c ...做反汇编输出这类命令同样要检查路径。改完之后重新 Build 一次确认不再报 createprocess failed再去检查输出目录里有没有正常生成 bin 文件。3.3 启动文件、CMSIS和库的兼容问题编译器选项和 fromelf 都搞定之后老工程通常就能编译过了。但如果你的工程同时涉及芯片 Pack 更新或者 CMSIS 选型变化还会遇到下一层兼容问题主要集中在启动文件和底层库。先看启动文件。老工程的启动文件一般是startup_stm32f10x_hd.s、startup_stm32f4xx.s这类文件这些汇编文件在不同编译器版本下会有细微语法差异。如果你原本的工程在旧 MDK 里一直用 AC5 编译那启动文件也是 AC5 风格切回 V5 之后就能正常编译。如果这个工程之前是用 AC6 或者 GCC 工具链创建的启动文件可能是对应编译器的版本切回 V5 后可能报汇编指令不认识或者符号定义冲突。这时候需要找到同芯片对应 ARMCC 版本的启动文件进行替换一般芯片厂商提供的标准库里面都会带多个编译器版本。再看 CMSIS 路径。新版 MDK 安装完芯片支持包后CMSIS 组件版本可能被自动更新。老代码里如果直接引用了老版本 CMSIS 才有的头文件或者 API可能在编译时出现cannot open source input file core_cm3.h这类错误。解决办法是进入Project - Manage - Run-Time Environment确认需要的 CMSIS 组件已经勾选或者把芯片 Pack 的版本切回与工程开发时一致的版本。如果你不想折腾 Pack 版本也可以直接把老 CMSIS 内核头文件路径手动加进C/C页签的 Include Paths 中。最后是库的匹配问题。有些工程链接了预编译的静态库比如某些老版本协议栈、加密库或者 DSP 库。这类预编译库往往是针对特定编译器生成的AC5 编译出来的库放到 AC6 下链接可能直接报一堆 undefined symbol。反过来也一样。这种问题没有捷径要么找对应编译器的库版本要么放弃预编译库改用源码编译要么把工程整体切回原编译器版本。这也是老项目保留 AC5 的最重要理由之一。3.4 重新编译后的常见错误速查表为方便你对照排错我把这一路最常见的错误整理成速查表你可以直接当工具表用报错信息原因分析解决方案Target uses ARM-Compiler Arm Compiler 5 which is not available工程指定 V5但系统没有安装 V5安装 Legacy Support 或 ARM_Compiler 包createprocess failed, command: ...fromelf...User 页签里的 fromelf 路径写死或错误修改为C:\Keil_v5\ARM\ARMCC\bin\fromelf.exeL6218E: Undefined symbol启动文件、库与编译器不匹配替换为对应编译器的启动文件/库或补充宏定义fatal error: A1167E: Invalid line start汇编文件里存在 AC5/AC6 不兼容语法切换回匹配的编译器或替换汇编文件armclang.exe: error: unsupported option工程配置里带了 AC5 专属编译选项切回 V5或删除不兼容的编译选项cannot open source input file core_cm3.hCMSIS 路径缺失或 Pack 组件未勾选安装对应芯片 Pack勾选 RTE 组件或手动添加路径warning: #1-D: last line of file ends without a newline老工程文件格式问题在文件末尾加一个换行一般不影响功能这些错误本身不难解决难的是定位到底是哪一层出了问题。我的排查习惯是先看最前面的几个错误特别是有error: L...或者error: A...开头的这些对应链接阶段和汇编阶段能直接给你定位到文件。C 语言编译阶段报的error: #...则多半是语法和头文件问题。按错误号分类梳理效率会高很多。4. 升级后新坑与实用技巧4.1 如果非要留在AC6怎么适配老代码有些朋友可能因为新需求必须用 AC6这时候就要面对老代码适配问题。我简单梳理几个最常见也最头疼的点。第一个是内联汇编。AC5 里常见的写法是块结构__asm { NOP; MOV R0, R1; }AC6 下这种写法基本编译不过要改成字符串形式__asm(NOP); __asm(MOV R0, R1);如果代码里大量使用内联汇编做底层操作这部分改写工作量不小。第二个是绝对地址定位。老工程做寄存器映射、Bootloader 跳转、存储分区时经常用__attribute__((at(0x08000000)))这类写法。AC6 已经不支持at属性推荐用__attribute__((section(.ARM.__at_0x08000000)))配合分散加载文件来定位。如果只有一两个变量用了这个语法改起来还轻松如果散落几百处那才是真正的大工程。第三个是编译选项。老工程里常见的--c99、--gnu、--apcsinterwork等选项在 AC6 下全部不认识。AC6 的选项风格是-stdc99、-fgnu这类 Clang 风格。进入Options for Target - C/C页签检查 Miscellaneous Controls 字段把 AC5 专属选项清掉否则就会看到unsupported option直接阻断编译。说句实在话如果你只是维护存量固件没有新平台或者新工具链的硬性要求老老实实留在 V5 反而更稳。AC6 的优势要在新代码、新架构里才体现得出来硬迁老工程往往是为迁移而迁移收益不高。4.2 多版本编译器并存的管理技巧MDK 本身支持 V5 和 AC6 并存这也是为什么很多人装了 5.37 之后会在 ARM 目录下同时看到ARMCC和ARMCLANG两个文件夹。两者互不干扰每个工程在Options for Target - Target里独立选择完全可以做到“老工程用 V5新工程用 AC6”。这里有个管理技巧给工程文件命名或者目录结构上做区分比如在工程名后面加_AC5或_AC6后缀避免团队里其他成员打开工程时搞混编译器配置。另外在版本管理工具里工程文件.uvprojx里已经记录了编译器版本比如uAC6和uAC5字段提交代码时留意这个字段的变更能减少多人协作时的配置冲突。顺带说一个很多人问过的调试问题在 MDK 的 Debug 模式里Watch 窗口看不到结构体成员完整内容添加变量后只能看到地址点不开树形结构。这通常不是工具问题而是优化等级太高导致局部变量被优化掉了。把编译优化等级从-O2调到-O0或者使用 Debug 配置重新编译Watch 窗口里结构体变量就能正常展开成员了。如果需要看地址指向的结构体内容在 Watch 窗口输入*(MyStructType*)0x20000010这类转换表达式即可。4.3 许可证和常见坑ARMCC V5 编译器本身不消耗额外许可证。只要你的 MDK 主程序有有效 License安装好 V5 之后就能正常使用。如果你用的是评估版 License代码容量限制是 32KB编译时会输出 License 相关提示但只要代码没超限V5 和 AC6 都能用。强调一点千万不要去用网上流传的注册机。我见过不止一个同事因为用了注册机导致系统被安装恶意程序后面重装系统才解决。Keil 的评估 License 在官网就能申请流程也不复杂完全够学习和一般的项目验证。公司项目需要超过 32KB 的代码量让公司采购正式 License这笔钱花得值省下来的时间成本远超 License 费用。另外还有一个小坑安装 Legacy Support 包时有些杀毒软件可能把armcc.exe当作可疑文件误杀导致 V5 安装完后 armcc 文件被隔离编译时疯狂报错。如果你的环境有这种状况需要到杀毒软件的隔离区里恢复文件并把它加入白名单。做完之后再跑一遍armcc.exe --vsn确认编译器可用。4.4 升级前后的版本匹配问题最后再提一个很多人忽略的版本匹配问题。Legacy Support 下载页面里通常列出了支持哪些 MDK 版本有的 Legacy 包只适配特定大版本如果你拿一个为 5.36 准备的 Legacy Support 包去装 5.37虽然安装过程可能不报错但会出现 ARMCC 接入后依然无法在编译器下拉框看到 V5 的情况或者编译时出现莫名的内部错误。所以在官网下载时留意页面上的版本对应说明。如果你用的是 MDK 5.37就找明确标注支持 5.37 的 Legacy 包。哪怕你手头存了旧版 Legacy 安装包也优先去官网确认一下是否有更新的版本避免文件不匹配带来的隐性坑。我个人在实际操作中的体会是这类环境升级问题九成以上都是“版本不匹配”和“路径不匹配”造成的。遇到编译报错先别慌按“编译器是否安装 - 编译器是否可用 - 工程配置是否正确 - 启动文件和库是否匹配 - 路径是否写死”这个顺序排查基本都能在一小时内搞定。MDK 5.37 ARMCC V5 的组合在老芯片项目上依旧很稳编译产物和 5.36 时代几乎没差别。希望这篇文章能帮你少走弯路也欢迎有类似经历的同行分享各自的环境迁移经验。