从 Arm Compiler 5 迁移到 Arm Compiler 6
在开始之前,建议先备份你的工程代码。
迁移条件
 要使用 ARM Compiler 6,建议MDK的版本至少为:
MDK版本5.23或更高版本
 MDK版本5.23提供两个编译器,分别是 ARM Compiler 5.06 和 ARM Compiler 6.6。
软件包也需要支持 ARM Compiler 6,以下是支持 ARM Compiler 6 的最低软件包版本:
Keil MDK-Middleware包: 版本7.4.0及以上
 Keil ARM Compiler Support 包: 版本1.3.0及以上
 ARM CMSIS 包: 版本5.0.1及以上
 切换编译器
 使用MDK打开工程。
选择 Project - Options for Target from the menu。
点击 Target 选项卡,找到 ARM Compiler: 下拉列表。
设置ARM编译器为 Version 6 。
点击 OK 键确认更改。
切换后的ARM Compiler 6所有设置都为默认值。
设置警告级别
 ARM Compiler 6 提供的警告级别比 ARM Compiler 5 多,如果你习惯 ARM Compiler 5 的警告级别,选择AC5-like Wamings。
可以通过在参数前面加上-Wno-来禁用特定诊断组的警告。
例如,通过选项-Wno-missing-noreturn禁用了–Wmissing-noreturn。
 在迁移的第一步中,建议将级别切换为“无警告”。 这将使您可以专注于错误消息。
解决所有错误信息后,选择AC5-like Wamings,设置-Wno-invalid-source-encoding选项:禁用源代码编码检测,因为LCD和打印信息有中文,编译器认为这些是无效编码。
如果想测试下代码是否规范,可以选择All wamings。
设置优化级别
 选择-Os babanced级别,平衡代码大小和性能。
 如果想代码执行速度快,可以选择-O2、-O3、-Ofast级别,优化性能(速度),优化依次提升,但生成的代码大小可能会变大。
 如果想减少代码大小,可以选择-Os babanced、-Oz image size级别,代码大小优化依次提升。
 比如我的工程,使用-Oz image size级别编译出的code大小为103026、使用-Os babanced级别编译出的code大小为115848字节、使用-O3级别编译出的code大小为160536。差别很大。
-O0级别没有做任何优化。注意ARM Compiler 5的-O0实际上是有优化的,所以ARM Compiler 6的-O1级别与ARM Compiler 5的-O0级别最为相似,都可以获取良好的调试体验,在调试阶段可以选用。
不兼容的语言扩展
 主要是代码中的__align(x)、__packed、__weak等编译器扩展语言。解决方法是使用CMSIS定义的相关宏。
替换CMSIS头文件,这里使用的是5.6.0版本的CMSIS。
 如果安装了较新的Keil,可以在路径.\Keil_v5\ARM\PACK\ARM\CMSIS目录中找到合适的CMSIS版本。
 将.\Keil_v5\ARM\PACK\ARM\CMSIS\5.6.0\CMSIS\Core\Include内的文件替换到工程code_cm3.h所在的文件夹。
修改lwip协议栈的cc.h文件,因为lwip使用到了编译器的扩展语言,比如取消结构体的对齐优化、指定变量对齐方式等,这些扩展语言 ARM Compiler 5 和 ARM Compiler 6 并不相同。
 在cc.h文件中引用CMSIS提供的cmsis_compiler.h文件,然后修改结构体封装与对齐宏代码为:
/* Arm Compiler 4/5 */
 #if   defined ( __CC_ARM )
     #define PACK_STRUCT_BEGIN __packed
     #define PACK_STRUCT_STRUCT
     #define PACK_STRUCT_END
     #define PACK_STRUCT_FIELD(fld) fld
     #define ALIGNED(n)  __ALIGNED(n)
  /* Arm Compiler above 6.10.1 (armclang) */
 #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
     #define PACK_STRUCT_BEGIN
     #define PACK_STRUCT_STRUCT __PACKED
     #define PACK_STRUCT_END
     #define PACK_STRUCT_FIELD(fld) fld
     #define ALIGNED(n)  __ALIGNED(n)
/* GNU Compiler */
 #elif defined ( __GNUC__ )
     #define PACK_STRUCT_BEGIN
     #define PACK_STRUCT_STRUCT __PACKED
     #define PACK_STRUCT_END
     #define PACK_STRUCT_FIELD(fld) fld
     #define ALIGNED(n)  __ALIGNED(n)
     
 #else
     #error "Unsupported compiler"
 #endif
 程序中使用了__packed、__align(n)、__inline、__weak的地方分别用CMSIS提供的宏__PACKED、__ALIGNED(n)、__INLINE、__WEAK代替。
注意__packed和__attribute__((packed))的使用区别:
ARM Compiler 5 使用__packed:
typedef __packed struct
 {
     char x;           
     int y;
 } X; 
 ARM Compiler 6 使用__attribute__((packed)):
typedef struct __attribute__((packed))
 {
     char x;                   
     int y;
 } X; 
 如果使用ARM Compiler 5 时习惯使用typedef __packed struct {}X; 句法,推荐改为CMSIS提供的宏句法:typedef __PACKED_STRUCT {}X;
当使用ARM Compiler 5 时会自动扩展为:typedef __packed struct {}X;
当使用ARM Compiler 6 时会自动扩展为:typedef struct __attribute__((packed)) {}X;
如果使用内联函数建议按照以下格式:
__STATIC_INLINE func_name(arg)
 {
     //函数体
 }
 防止ARM Compiler 6在-O0、-O1级别设置下,链接时出现未定义符号的错误。(在这种优化级别下__INLINE可能并不会内联)
不兼容的语言扩展总结如下:
ARM Compiler 5     ARM Compiler 6                                    CMSIS(推荐)
 __align(x)                __attribute__((aligned(x)))                     __ALIGNED(x)
 __alignof__             __alignof__            
 __ALIGNOF__        __alignof__    
 __asm                     见汇编迁移    __ASM
 __const                    __attribute__((const))    
 __forceinline            __attribute__((always_inline))    
 __global_reg            不支持    
 __inline                    __inline__ 此功能使用取决于语言模式    __INLINE
                                                                                                  __STATIC_INLINE
 __int64                    没有对等选项.使用 long long    int64_t
 __irq                        __attribute__((interrupt))                            Cortex-M ISR不需要此关键字
 __packed                __attribute__((packed))                                __PACKED
 __packed x struct    struct x attribute((packed))                           __PACKED_STRUCT x
 __pure                    __attribute__((const))    
 __smc                    不支持,使用内联汇编或等效程序    
 __softfp                    __attribute__((pcs(“aapcs”)))    
 __svc                        不支持,使用内联汇编或等效程序    
 __svc_indirect            不支持,使用内联汇编或等效程序    
 __thread                    __thread    
 __value_in_regs            __attribute__((value_in_regs))    
 __weak                    __attribute__((weak))                                    __WEAK
 __writeonly            不支持    
 提示:可以使用uVision IDE的查找功能来查找上述关键字,然后做迁移处理。
不兼容的属性扩展:
Arm Compiler 5 属性                    Arm Compiler 6 属性                            描述
 __attribute__((at(address)))            __attribute__((section(".ARM.__at_address")))    Arm Compiler 6 中的 armlink 仍然支持以 .ARM.__at_address 的形式放置段
 __attribute__((at(address), zero_init))    __attribute__((section(".bss.ARM.__at_address")))    Arm Compiler 6 中的 armlink 支持以 .bss.ARM.__at_address 的形式放置零初始化段。 .bss 前缀区分大小写,并且必须全部小写。
 __attribute__((section(name), zero_init))    __attribute__((section(".bss.name")))    name 是你选择的名字。 .bss 前缀区分大小写,并且必须全部小写。
 __attribute__((zero_init))    不支持
 默认将零初始化变量放在.bss 段。    如果变量具有初始值设定项,则 Arm Compiler 5 会生成错误。 否则,它将零初始化变量放在 .bss段。
点击这里查看迁移详细例程。
内嵌汇编
 ARM Compiler 6 完全改变了处理汇编代码的策略。
汇编语法现在兼容GNU风格而不是ARM风格。 汇编也是由C编译器完成, 无需单独的汇编器。
FreeRTOS的移植层由..\FreeRTOS\Source\portable\RVDS\ARM_CM3目录下的port.c和portmacro.h文件改为..\FreeRTOS\Source\portable\GCC\ARM_CM3目录下的port.c和portmacro.h文件。
这是因为这两个文件会涉及内嵌汇编。
自定义的内嵌汇编函数。
ARM Compiler 5:
__asm  uint32_t __get_flash_base(void) 
 {
    IMPORT |Image$$ER_IROM1$$RO$$Base|;
     
     ldr r0,=|Image$$ER_IROM1$$RO$$Base|;
     bx lr;
 }
 ARM Compiler 6:(看了下帮助手册,也可以不使用汇编)
uint32_t get_flash_base(void)
 {
     extern uint32_t Image$$ER_IROM1$$RO$$Base;
     
     return (uint32_t)&Image$$ER_IROM1$$RO$$Base;
 }
 语法更严格
 比如某个函数之前要对外开放,.c和.h中定义和声明都相同。后来在.c文件中将该函数定义为本地函数,使用static修饰,但.h中忘记删除也没有做相应修改。这种情况下,ARM Compiler 5 不会报错,ARM Compiler 6 会报错:
../file_name.c(10): error: static declaration of 'func_name' follows non-static declaration
如下代码:
for(i=0; i<0x7E-0x20; i++)
 ARM Compiler 5 不会报错,ARM Compiler 6 会报错:
../file_name.c(332): error: invalid suffix '-0x20' on integer constant
需要将代码改为:
for(i=0; i<0x7E - 0x20; i++)
 优化问题
 以下代码在 ARM Compiler 5 中,正常执行,但在 ARM Compiler 6 中,只要不是-O0级别,整个函数因为空循环问题,都被优化掉。也就是延时没有起作用。
void delay_us (uint32_t ul_time)
 {
     ul_time *= 30; 
     while(--ul_time != 0);
 }
 这个函数不会修改自己范围之外的资源,所以编译器认为这段是无副作用(no side-effect)的代码,可以通俗的理解为没什么作用的代码。对于这样的代码,编译器有可能会优化掉他们。
有副作用的函数的特点:
修改了全局变量
 修改了参数引用的变量
 调用其它有副作用的函数
 操作了 volatile 修饰的变量
 内嵌了汇编或 __NOP()指令
 所以当升级到 ARM Compiler 6 出现使用软延时的外设不工作,比如软件IIC出错、软件SPI出错、LCD黑屏等问题,可以检查是否有类似的代码。
需要改成:
void delay_us (uint32_t ul_time)
 {
     ul_time *= 30; 
     while(--ul_time != 0)
         __nop();
 }
 Keil编译器保证__nop()必定会插入一个NOP指令,在这里可以阻止编译器优化。当然,延时的初始值也要做相应的调整。
或者改成:
void delay_us (volatile uint32_t ul_time)
 {
     ul_time *= 30; 
     while(--ul_time != 0);
 }
 通过关键字 volatile 来禁止编译器优化。
编译时间和大小
 -O0:Program Size: Code=200360 RO-data=20576 RW-data=96 ZI-data=76316
 Build Time Elapsed: 00:00:25
-O1:Program Size: Code=119328 RO-data=16824 RW-data=96 ZI-data=76300
 Build Time Elapsed: 00:00:25
-O2:Program Size: Code=153340 RO-data=17100 RW-data=96 ZI-data=76300
 Build Time Elapsed: 00:00:26
-O3:Program Size: Code=162292 RO-data=17040 RW-data=96 ZI-data=76308
 Build Time Elapsed: 00:00:27
-Ofast:Program Size: Code=161896 RO-data=17040 RW-data=96 ZI-data=76308
 Build Time Elapsed: 00:00:26
-Os balanced:Program Size: Code=115628 RO-data=17048 RW-data=96 ZI-data=76300
 Build Time Elapsed: 00:00:28
-Oz image size:Program Size: Code=103784 RO-data=17020 RW-data=96 ZI-data=76308
 Build Time Elapsed: 00:00:25
-Oz image size LTO:Program Size: Code=85888 RO-data=17064 RW-data=40 ZI-data=75960
 Build Time Elapsed: 00:00:32
与Compiler 5 对比(我的程序-可能不具有一般性):
-O2:Program Size: Code=94232 RO-data=16736 RW-data=540 ZI-data=75640
 Build Time Elapsed: 00:00:16
 参考文档
 《Arm® Compiler Migration and Compatibility Guide》(内容详细)
 《Migrate ARM Compiler 5 to ARM Compiler 6》 (AN298)
  
MDK5.37安装ARM_Compiler_5
 最后一个AC5编译器,从MDK5.37开始,不再默认安装,需要独立安装
ARMCompiler_506_Windows_x86_b960.zip (80.94MB)
 否则使用AC5编译代码报错如下:

 Build started: Project: Project
 *** Target 'STM3210C_EVAL' uses ARM-Compiler 'Default Compiler Version 5' which is not available.
 *** Please review the installed ARM Compiler Versions:
    'Manage Project Items - Folders/Extensions' to manage ARM Compiler Versions.
    'Options for Target - Target' to select an ARM Compiler Version for the target.
 *** Build aborted.
 Build Time Elapsed:  00:00:00
 解决办法
 1、AC5安装时配置为路径
 C:\Keil_v5\ARM\ARM_Compiler_5.06u7
2、安装完成后在keil中配置
 Project --> Manage --> Project Items --> Folders/Extensions --> Click the … button --> Add another Arm Compiler Version to List --> 选择上面配置的AC5安装路径
3、选择ARM编译器为AC5的版本

 参考文献
Manage Arm Compiler Versions
转自:https://blog.csdn.net/zhzht19861011/article/details/109803651