从 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文件,然后修改結構體封裝與對齊宏代碼為:
程序中使用了__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可能并不會內聯)
不兼容的語言擴展總結如下:
| __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 __packed x struct | __attribute__((packed)) struct x attribute((packed)) | __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的查找功能來查找上述關鍵字,然后做遷移處理。
不兼容的屬性擴展:
| __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)
讀后有收獲,資助博主養娃 - 千金難買知識,但可以買好多奶粉 (〃‘▽’〃)
總結
以上是生活随笔為你收集整理的从 Arm Compiler 5 迁移到 Arm Compiler 6的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GE可能会出售其工业软件业务的股份
- 下一篇: Design compiler综合教程