野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 12499|回复: 0

STM32使用Arm Compiler v6工具链编译程序

[复制链接]
发表于 2018-3-21 04:22:31 | 显示全部楼层 |阅读模式
本帖最后由 smallcsduck 于 2018-3-21 04:24 编辑

现在主流的Cortex-M开发环境和中间件代码都是基于GNU和Arm Compiler v5工具链的写的。其实ArmCompiler v6工具链已经出来很久了。对比ArmCompiler v5工具链,Arm Compiler v6做了很多改进。这个文章就来研究下怎么快捷的把ArmCompiler v5的代码迁移到Arm Compiler v6上。为什么要用Arm Compiler v6的工具链呢?Keil网站上有一张图解释了这个问题。 图片1.png

        毕竟是ARM的官方工具链,对构架理解比较深,优化的好一点吧。
        先介绍下Arm Compiler v6编译器。
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

        2、在C/C++选项卡里添加一个定义__CNUC__
图片3.png

[size=1em]
        然后点编译就可以了。没有任何错误和警告,顺利通过编译。
        这个添加的定义导致编译时候的同时引用了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

        前面的添加转换规则对于纯C程序肯定是完全够用了。但是碰到有内链ARM汇编的代码怎么办呢?没办法。只有按照GNU的格式改吧。
        不过这个时候你可以找一下有没有GNU版本的源码直接用GNU工具链的源码就可以了。
        比如FreeRTOS源码里面很关键的两个文件:port.c和portmacro.h。这两个文件里面都有大量的内链汇编。不同构架不同编译器的代码是不一样的。要用Arm Compiler 6工具链编译,你直接用GNU工具链版本的代码就可以了。另外STM32CubeMX是用了CMSIS-RTOS的接口。所以要改一下cmsis_os.c文件。
图片5.png



        最后,对于预编译的库怎么选择呢?比如emwin,针对不同的工具链提供了不同的库版本。但是没有提供Arm Compiler 6工具链的版本,那你直接用GNU的版本的预编译库就行了。



转载请注明出处http://smallcsduck.blog.163.com






回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-27 08:38 , Processed in 0.042470 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表