本帖最後由 smallcsduck 于 2018-3-21 04:09 編輯
現在主流的Cortex-M開發環境和中間件代碼都是基于GNU和ArmCompilerv5工具鍊的寫的。其實ArmCompilerv6工具鍊已經出來很久了。對比ArmCompilerv5工具鍊,ArmCompilerv6做了很多改進。這個文章就來研究下怎麼快捷的把ArmCompilerv5的代碼遷移到ArmCompilerv6上。為什麼要用ArmCompilerv6的工具鍊呢?Keil網站上有一張圖解釋了這個問題。

圖檔1.png (21.79 KB, 下載下傳次數: 12)
2018-3-21 03:59 上傳
畢竟是ARM的官方工具鍊,對構架了解比較深,優化的好一點吧。
先介紹下ArmCompilerv6編譯器。
Arm Compiler 6是一個基于LLVM的工具鍊,那LLVM是什麼呢?簡單來說LLVM是把文法分析和機器碼生成分開成兩個獨立部分。這樣移植編譯器到新構架就很容易了,你隻要修改機器碼生成部分,文法分析不用改。GCC的編譯器這兩部分是混在一起的。LLVM與GCC比較優點很多。比如錯誤資訊詳細啊,編譯快啊等等。感興趣的可以自行查一下。
一般來講LLVM的文法分析部分是從GCC繼承過來的。是以嗎,文法規則和GCC是差不多的。說了這麼多其實就像告訴你一件事,Arm Compiler 6的C和彙編的文法和GCC是差不多的。(是不是完全相同?我沒看到在文檔裡有寫,也沒有驗證,腦補算是一樣的。)
現有的很多中間件,像HAL庫、FREERTOS都沒有為Arm Compiler 6做過适配的版本。但是都有GNU工具鍊的适配代碼。那是不是可以直接用Arm Compiler 6編譯GNU工具鍊的代碼呢?那肯定是不行的。因為Arm Compiler 6和GNU工具鍊還是有不同的。
首先是連結器不同,Arm Compiler 6用的是和Arm Compiler 5一樣的armlink連結器,和GNU工具鍊的LD是不一樣的,連結腳本也是不一樣的。
此外Arm Compiler 6和GNU編工具鍊用的運作時庫是不一樣的。Arm Compiler 6的運作時庫除了提供标準C庫的那些功能,還添加了Semihosting模式,支援Scatter-loading和初始化HEAP、STACK的代碼。GNU的運作時庫是沒有上面三個功能的,需要自己用彙編寫(這一點是我腦補的)。
另外,Arm Compiler 6裡面有兩種彙編語言的編譯器,一種是使用GNU彙編格式的armclang,一種是使用ARM彙編格式的armasm。也就是說以前Arm Compiler 5的彙編啟動檔案還是可以用的。但是C的内聯彙編必須使用GNU内聯格式。
下面實際使用Arm Compiler 6工具鍊編譯一下使用HAL庫的程式。
看過上面說的,要把GUN工具鍊的項目或者老的Arm Compiler 5項目遷移到Arm Compiler 6工具鍊需要修改的地方就很明顯了。Arm Compiler 6幫助文檔裡專門有一個從Arm Compiler 5往Arm Compiler 6遷移的文檔。可以參考。
把Arm Compiler 5的項目往Arm Compiler 6遷移很簡單。用STM32CubeMX建立一個MDK項目。預設是Arm Compiler 5的編譯器。直接用Arm Compiler 6編譯肯定很多錯誤。成功遷移其實隻需要簡單的兩步。
1、你打開一個MDK項目。然後在Target頁籤裡選擇Arm Compiler 6。

圖檔2.png (27.47 KB, 下載下傳次數: 7)
2018-3-21 03:59 上傳
2、在C/C++頁籤裡添加一個定義__CNUC__

圖檔3.png (18.88 KB, 下載下傳次數: 9)
2018-3-21 03:59 上傳
然後點編譯就可以了。沒有任何錯誤和警告,順利通過編譯。
這個添加的定義導緻編譯時候的同時引用了CMSIS的GNU實作接口(cmsis_gcc.h)和Arm Compiler 6的實作接口(cmsis_armcc_V6.h),可能會出現問題。那我們嚴謹一點,不搞這種投機取巧的辦法。
Arm Compiler 6和Arm Compiler 5的C語言差別主要在擴充的C語言屬性關鍵字上。就是__weak,__packed這類關鍵字。那我們預處理定義裡面自己添加轉換規則就行了。使用-D這個選項。比如-D__weak="__attribute__((weak))" -D__packed="__attribute__((__packed__))" -D__NOINLINE="__attribute__ ( (noinline) )"
根據編譯的時候出現的錯誤,按照遷移手冊上說明,定義一個預編譯的轉換規則就行。

圖檔4.png (34.47 KB, 下載下傳次數: 10)
2018-3-21 03:59 上傳
前面的添加轉換規則對于純C程式肯定是完全夠用了。但是碰到有内鍊ARM彙編的代碼怎麼辦呢?沒辦法。隻有按照GNU的格式改吧。
不過這個時候你可以找一下有沒有GNU版本的源碼直接用GNU工具鍊的源碼就可以了。
比如FreeRTOS源碼裡面很關鍵的兩個檔案:port.c和portmacro.h。這兩個檔案裡面都有大量的内鍊彙編。不同構架不同編譯器的代碼是不一樣的。要用Arm Compiler 6工具鍊編譯,你直接用GNU工具鍊版本的代碼就可以了。另外STM32CubeMX是用了CMSIS-RTOS的接口。是以要改一下cmsis_os.c檔案。
[size=1em]

圖檔5.png (30.79 KB, 下載下傳次數: 10)
2018-3-21 03:59 上傳
最後,對于預編譯的庫怎麼選擇呢?比如emwin,針對不同的工具鍊提供了不同的庫版本。但是沒有提供Arm Compiler 6工具鍊的版本,那你直接用GNU的版本的預編譯庫就行了。一點小小的研究,如果有錯誤的地方,請回複指出。