天天看點

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

本帖最後由 smallcsduck 于 2018-3-21 04:09 編輯

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

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

圖檔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。

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

圖檔2.png (27.47 KB, 下載下傳次數: 7)

2018-3-21 03:59 上傳

2、在C/C++頁籤裡添加一個定義__CNUC__

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

圖檔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) )"

根據編譯的時候出現的錯誤,按照遷移手冊上說明,定義一個預編譯的轉換規則就行。

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

圖檔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]

arm -linux -gcc 的編譯,STM32使用Arm Compiler v6工具鍊編譯程式

圖檔5.png (30.79 KB, 下載下傳次數: 10)

2018-3-21 03:59 上傳

最後,對于預編譯的庫怎麼選擇呢?比如emwin,針對不同的工具鍊提供了不同的庫版本。但是沒有提供Arm Compiler 6工具鍊的版本,那你直接用GNU的版本的預編譯庫就行了。一點小小的研究,如果有錯誤的地方,請回複指出。