简介:ARMCompiler_506_Windows_x86_b960 是 ARM 公司推出的 ARM Compiler 5.06(build 960)Windows x86 安装包,面向从事 ARM 架构嵌入式开发的工程师与 Keil MDK 用户,用于解决 C 源码向 32 位 ARM 机器码高效转换的编译需求。包内共 3 个文件,以 msi 安装程序、exe 引导安装器与 html 版本说明为主,压缩包约 80.52MB,安装后即可获得 armcc 编译器及配套组件。该版本通过 ANSI C 标准验证,支持代码大小与运行速度优化,并兼容 Thumb、Thumb-2 等指令子集,可与 Keil 工具链配合完成编辑、构建与调试。版本说明文档记录了本版的更新、改进与已知问题,便于开发者评估升级影响、规避潜在坑点。目前已有 3601 人学习下载,适合需要稳定 ARMCC 编译环境、复现旧工程或进行嵌入式教学实验的读者参考使用。
1. 一个老编译器安装包,为什么还有人到处找
如果你在维护十年前的 ARM 工控板、车机模块或者某颗 Cortex-M 老料,Keil 工程一打开就报cannot open source input file "core_cm3.h",或者链接阶段甩出一句L6218E: Undefined symbol,八成不是代码写错了,而是编译器版本对不上。ARMCC 5.06(960) 这个 msi 安装包,就是 ARM Compiler 5 系列里被大量老工程锁死的那一版——它自带 armcc、armasm、armlink、fromelf 一整套工具链,能直接挂进 Keil MDK 的 ARMCC 目录,也能在命令行里独立跑。这份资源解决的不是“新项目选型”,而是“老工程怎么原样编过”。适合手里压着存量 ARM 项目、需要复现历史构建结果的嵌入式从业者,新手照着装也能跑通第一个 hello world。
2. 先搞清楚 ARMCC 5.06 在工具链里的位置:它到底编什么、不编什么
2.1 ARM Compiler 5 与 ARMCC 的对应关系
很多人把“ARMCC”和“ARM Compiler”混着叫,实际在 ARM 的版本谱系里,ARM Compiler 5 这一代对外暴露的 C/C++ 编译器可执行文件就叫armcc.exe,汇编器是armasm.exe,链接器是armlink.exe,再加上fromelf.exe做镜像转换、armar.exe打包静态库。5.06 是这一代里比较靠后的维护版本,build 960 属于该分支的补丁号。它面向的是 ARMv7-M / ARMv7-A 这类老架构,Cortex-M3/M4 是它的主战场,Cortex-M7 早期工程也大量用它。它不编 ARMv8-M 的新指令,也不支持 C11 之后的一堆特性,所以拿它去编新芯片的启动文件,翻车是必然的。
判断你手里的工程该不该用它,最直接的办法是看 Keil 工程文件里的编译器标记。用文本编辑器打开.uvprojx,搜pCCUsed,如果值是5060000::V5.06 update 6 (build 960)这类字符串,说明工程就是按这一版锁定的。再看TargetOption里的Device和Cpu字段,确认内核型号。这两处对上了,装 5.06 才有意义;对不上,先别急着装,换版本比硬凑省事。
2.2 安装包结构与它落盘后长什么样
这个 msi 是 Windows x86 的安装包,装完之后典型目录结构是这样的(不同安装路径前缀会变,但层级一致):
| 路径 | 内容 | 用途 |
|---|---|---|
bin/ | armcc.exe、armasm.exe、armlink.exe、fromelf.exe、armar.exe | 命令行直接调用的工具 |
bin/armcc相关 dll | 编译器前端依赖 | 缺了会报加载失败 |
include/ | 标准 C 库头文件、CMSIS 相关头 | 编译时-I指向这里 |
lib/ | 运行时库、启动代码库 | 链接阶段自动或手动引用 |
sw/ | 示例与辅助文件 | 一般不用动 |
装完先别急着挂 Keil,先在命令行验证工具链本身是活的。打开 cmd,进到bin目录:
cd "C:\Keil_v5\ARM\ARMCC\bin" armcc --version armlink --version正常输出会带ARM Compiler 5.06 update 6 (build 960)字样。如果armcc --version报“不是内部或外部命令”,说明 PATH 没配或者安装没写注册表;如果报缺 dll,多半是安装包解压不完整或者被杀软拦了文件。这一步过了,再谈挂 Keil。
2.3 为什么老工程非要锁这一版而不是升级到 AC6
ARM Compiler 6 基于 Clang/LLVM,语法更现代、优化更强,但它对老代码的兼容性是有代价的。血泪经验集中在几类:一是内联汇编写法,AC5 的__asm块语法在 AC6 下要改成 GNU 风格或 intrinsics;二是分散加载文件(scatter file)里的一些老语法 AC6 不再认;三是某些厂商的启动文件、库文件是拿 AC5 编出来的.lib,AC6 链接时 ABI 对不上直接报错。存量项目动辄几十万行,为了升编译器去改内联汇编,投入产出比极低。所以现实做法是:新项目用 AC6,老项目把 5.06 单独装一份,工程里指定编译器路径,两套并存互不干扰。
这里有个容易忽略的点:Keil MDK 从某个版本起默认只带 AC6,AC5 需要单独装。装的时候不要覆盖到 AC6 的目录里,给 AC5 单独一个文件夹,比如C:\Keil_v5\ARM\ARMCC506,然后在 Keil 的Project → Manage → Project Items → Folders/Extensions里把 ARMCC 路径指过去。这样切换工程时不会互相污染。
3. 把 5.06 挂进 Keil 并跑通第一个工程:从安装到生成 axf
3.1 安装与目录规划的具体步骤
msi 双击安装,向导里会让你选安装路径。我的习惯是不要装进默认的Program Files,路径里不要有空格和中文,直接给一个短路径,比如C:\ARMCC506。原因很实际:老版本工具链对长路径和空格的处理不如新工具稳,某些脚本拼接路径时带空格会断。装完之后确认C:\ARMCC506\bin\armcc.exe存在。
接着在 Keil 里注册这套工具链。打开 Keil,Project → Manage → Project Items,切到Folders/Extensions标签页,在ARM Compiler那一栏点右侧的...,选中C:\ARMCC506\bin。Keil 会自动识别版本号,列表里应该出现V5.06 update 6 (build 960)。选中它,确定。此时工程的pCCUsed会被改写成对应标记。
提示:如果 Keil 列表里识别不到,检查
bin目录下是否有armcc.exe和配套的armcc.conf之类配置文件;有些精简安装包会缺配置文件,导致 Keil 探测失败。
3.2 工程侧的关键配置项
挂好编译器只是第一步,工程配置里还有几处必须对齐,否则编出来的东西跑不起来。打开Options for Target:
Target页:确认ARM Compiler下拉选的是刚注册的 V5.06;Code Generation里的ARM Compiler默认选项保持Use default compiler version 5。C/C++页:Include Paths里要有 CMSIS 头文件路径和你自己的外设头路径;Define里通常要写芯片型号宏,比如STM32F10X_MD(具体以你的工程为准,这里只是举例说明宏的写法)。Linker页:勾选Use Memory Layout from Target Dialog,或者指定你自己的 scatter 文件。老工程很多是手写 scatter 的,别让它被自动覆盖。Debug页:选对调试器型号,这个和编译器无关但影响下载。
配置完先做一次全编译。命令行方式更利于排查,因为 Keil 的 Build Output 窗口有时会把警告折叠。用命令行复现一次编译,能看清每一步:
cd /d C:\ARMCC506\bin armcc -c --cpu Cortex-M3 -D STM32F10X_MD -I "C:\project\inc" -I "C:\ARMCC506\include" -o "C:\project\obj\main.o" "C:\project\src\main.c"这条命令里,--cpu Cortex-M3指定目标内核,必须和芯片一致,写错会生成不匹配的指令;-D是预处理宏,等价于工程里的 Define;-I是头文件搜索路径,顺序有讲究,自己的头放前面避免被库头覆盖;-o指定输出目标文件。编过之后用armlink链接:
armlink --cpu Cortex-M3 --scatter "C:\project\project.sct" -o "C:\project\out\project.axf" "C:\project\obj\main.o" "C:\project\obj\startup.o" --libpath "C:\ARMCC506\lib"--scatter指向分散加载文件,决定代码和数据放到哪块 Flash/RAM;--libpath告诉链接器去哪找运行时库。链接成功会生成.axf,再用fromelf转 bin:
fromelf --bin --output "C:\project\out\project.bin" "C:\project\out\project.axf"--bin输出纯二进制,--output指定文件名。到这一步,一个最小可烧录镜像就出来了。命令行跑通的意义在于:当 Keil 图形界面报错信息含糊时,你能用同样的参数在命令行复现,错误信息更完整,定位更快。
3.3 验证编译结果是否真的可用
生成 axf 不等于能用。至少做两件事:一是看fromelf --text -c的输出,确认中断向量表在预期地址、入口函数地址合理;二是把 bin 烧进板子,跑一个点灯或者串口打印,确认启动文件和时钟配置没被编译器版本差异搞坏。老工程最常见的隐性问题是启动文件里的栈大小、堆大小宏在 AC5 和 AC6 下展开行为不同,编过了但一上电就 HardFault。所以第一次用 5.06 编完,务必上板验证,别只看 Build 成功。
4. 避坑与排查:5.06 装完编不过的五个高频现场
4.1 报 “cannot open source input file” 但路径明明存在
现象:编译报找不到某个头文件,可你在资源管理器里能看到它。原因通常是路径里带了空格或中文,或者-I路径用了反斜杠结尾导致拼接异常。解决:把工程和工具链都挪到无空格无中文的短路径,-I路径统一用双引号包住,末尾不加反斜杠。Keil 工程里如果 Include Paths 是相对路径,确认相对基准是工程文件所在目录而不是输出目录。
4.2 链接报 L6218E 未定义符号,符号名却像是库函数
现象:Undefined symbol __use_no_semihosting或者某个_sys_开头的符号找不到。原因:AC5 的 microlib 和标准库对底层系统调用的要求不同,工程勾了Use MicroLIB但代码里又引用了标准库的重定向函数,或者反过来。解决:在Target页确认Use MicroLIB的勾选状态和代码预期一致;如果用了 printf 重定向,确保fputc之类的实现存在且没被条件编译掉。这类问题在换编译器版本后特别容易冒出来,因为默认库选择变了。
4.3 编译通过但一上电就 HardFault
现象:Build 0 error,烧录后程序不跑,调试器停在 HardFault_Handler。原因:启动文件里的向量表偏移、栈顶地址和实际芯片的 Flash/RAM 布局不匹配,或者 scatter 文件里的加载域和执行域写错。解决:用调试器看SCB->VTOR和 SP 初值,对照芯片手册的 Flash 起始地址;检查 scatter 文件里LR_IROM1的起始地址是不是0x08000000这类正确值。AC5 对 scatter 语法的容错比 AC6 宽,但宽不代表对,写错了照样跑飞。
4.4 Keil 里切换编译器后设置被重置
现象:把工程从 AC6 切回 V5.06,发现优化等级、宏定义、Include Paths 全变了。原因:Keil 的工程文件里,不同编译器版本对应不同的配置节,切换时会加载该版本自己的默认配置,之前 AC6 下的设置不会自动迁移。解决:切换前先把关键配置截图或导出,切换后逐项核对C/C++和Linker页。更稳的做法是给老工程单独复制一份.uvprojx,专门锁 5.06,别和 AC6 工程共用。
4.5 命令行能编,Keil 图形界面编不过
现象:同样的源码,cmd 里 armcc 跑得好好的,Keil 里 Build 报错。原因:Keil 调用的环境变量、临时目录、或者它自己拼的参数和你手敲的不一样,常见于路径含空格、临时目录权限不足、杀软实时扫描锁文件。解决:看 Keil 的 Build Output 里完整命令行(Options for Target → Output → 勾选 Browse Information不一定够,可以在User页加一个打印命令行的步骤),把它复制到 cmd 里逐段比对。临时目录权限问题可以改TMP/TEMP环境变量到短路径验证。
5. 进阶:用批处理把 5.06 的构建流程固化下来
命令行跑通之后,真正省事的是把它固化成脚本,让老工程不依赖 Keil 图形界面也能一键出包。我一般会写一个build.bat,把编译、链接、转 bin 串起来,参数集中放在文件头部,换工程只改几行。核心思路是:源文件列表用通配或显式列出,编译产物统一进obj,链接产物进out,任何一步非零退出就中止。
@echo off setlocal set ARMCC_BIN=C:\ARMCC506\bin set PROJ=C:\project set CPU=Cortex-M3 set DEFS=-D STM32F10X_MD set INCS=-I "%PROJ%\inc" -I "C:\ARMCC506\include" if not exist "%PROJ%\obj" mkdir "%PROJ%\obj" if not exist "%PROJ%\out" mkdir "%PROJ%\out" for %%f in ("%PROJ%\src\*.c") do ( "%ARMCC_BIN%\armcc.exe" -c --cpu %CPU% %DEFS% %INCS% -o "%PROJ%\obj\%%~nf.o" "%%f" if errorlevel 1 goto fail ) "%ARMCC_BIN%\armlink.exe" --cpu %CPU% --scatter "%PROJ%\project.sct" -o "%PROJ%\out\project.axf" "%PROJ%\obj\*.o" --libpath "C:\ARMCC506\lib" if errorlevel 1 goto fail "%ARMCC_BIN%\fromelf.exe" --bin --output "%PROJ%\out\project.bin" "%PROJ%\out\project.axf" if errorlevel 1 goto fail echo BUILD OK goto end :fail echo BUILD FAILED exit /b 1 :end endlocal这段脚本里,for %%f遍历源文件,%%~nf取不带扩展名的文件名做目标名,避免不同目录同名源文件互相覆盖——如果你的工程有同名源文件,得改成带路径哈希的命名。errorlevel 1判断是批处理里最直接的失败捕获,比看输出文本可靠。--scatter和--libpath的路径写死在这里,换机器时改头部变量即可。
脚本化之后还有一个好处:可以做版本对比验证。把同一份源码分别用 5.06 和 AC6 编出来的 bin 做大小和符号表对比,用fromelf --text -s导出符号,看关键函数的地址和大小差异。如果某个函数在 5.06 下体积暴涨,多半是优化等级或内联策略不同,回头调-O参数就能定位。我吃过一次亏:老工程在 5.06 下-O2编出来能跑,换-O3就偶发跑飞,查了两天才发现是某个 volatile 变量被过度优化。从那以后我每次给老工程换优化等级,都强制走一遍上板冒烟测试,不再只看 Build 成功。希望这套流程能帮到你,少在版本兼容上耗时间。
本文还有配套的精品资源,点击获取