为什么要改造
最近看了一些资料,关于工程和项目方面的,其中一方面是关于持续集成和持续部署方面的,觉得有必要学习一下并运用到实际中,无奈编译那部分无法搞定,因为我们做单片机的基本上都是用MDK做为开发工具,不得不说,MDK开发嵌入式确实挺好,各种板子的配置,debug方面很出色,内存占用也很小,但是有几点不喜欢:
- 绑定了专属编译器,编译脚本固定,输出目标的可操作地方少,具体的编译细节弄不清楚
- 作为编辑器相关功能太差了,有时候连代码智能提示都没有,搞的开发的效率很低没因为很多变量名长了加上有大小写下划线不容易记住,偏偏又提示不出来
- 项目管理方面的功能不够
改造之后的效果
改造之后就可以脱离MDK来进行程序的编写,编译以及运行,不仅可以学习到整个工程编译过程(怎么从源码变成elf文件再变成hex和bin文件)的还可以实现持续集成相关任务,通过cmd或者linux终端即可实现程序的编译,下载.
不过每次都到命令行敲指令毕竟很麻烦,咱们更多的还是使用图形化的IDE界面,可以通过点击按钮就实现程序编译下载等等,我比较喜欢Clion和Qtcreater两款IDE,但是Clion占用内存比Qtcreater大而且需要收费(也可以破解和买tb激活码,但是毕竟盗版了),加上从业以来一直喜欢用qtcreater,最终选择了qtvreater,但是最终的效果是一样的,大家弄懂了其中原理也可以改造到自己喜欢的编辑器里去,比如vs code,sublime等等,不列举了
准备工作
开始之前需要了解的知识储备大致如下,不必深究细节,理解为主,老鸟自动忽略即可
1.编译工具链(gcc llvm armcc armclang)
2.编译的四步骤(预处理,汇编,编译,链接)
3.什么叫elf文件(可执行文件)
4.elf和hex,bin文件什么关系(固件)
5.make(makefile)和cmake有什么关系
如果对于以上几个概念没有什么基础,大家去百度上搜索相关资料,这里我就不多做介绍,真要说起来,一匹布那么长......
安装make工具
windows平台上下载mingw-make工具并添加到系统路径下(cmd调出make指令不会提示未找到指令),linux平台直接就能用,具体的安装方法上网搜索之,这里就不浪费篇幅,以windows为例,达到以下效果即可:
安装cmake
cmake的安装也很简单,上网搜索就可以了,安装后添加系统路径,cmd能找到指令就行了,如下图所示:
安装Qtcreater或者Clion
这两个ide是否安装全凭喜好,不习惯或者有别的顺手的家伙也可以不装,通过命令行敲命令的方式可以可以的.具体的安装过程这里也不赘述ide的安装过程,总之安装好了之后桌面上会出现图标,点击打开即可,新安装的clion可能会提示激活,没关系我们免费用30天,30天到期之后是破解还是买激活码各童鞋自己选择即可.
开始改造之旅
接下来就是真正动手的环节了,大体步骤:重头戏--编辑cmake文件,导入cmake生成makefile,编译,下载等等,具体的工程是使用我现在用的芯片nrf52832,sdk12.3,编译链选择的是armclang,个童鞋也可以用gcc来编译.
cmake文件和工具链选择
cmake使用一个叫做CMakeLists.txt的文件进行编译管理,这个名字大多数情况下是固定的,因为很多IDE依靠这个名称进行cmake识别
1.使用armclang或者armgcc需要的文章的cmake文件分为两个,一个是tollchain.cmake,一个就是CMakeLists.txt,这两个文件的作用不太一样,一个是定义编译工具, 一个就是具体的编译规则
2.使用MDK自带的armcc工具链只需要一个文件就是CMakeLists.txt,注意,cmake3.5在版本在3.5版本之后才增加了armcc的支持,目前cmake最新版本是3.15,建议大家都用最新版本或者次新版本(防止先版本有bug)
本文属于抛砖引玉型文章,因为大多数的工程还是用的armcc编译链来进行编译的,这里先按照从易到难先从armcc的方式给大家理解一下cmakelists文件的编写.关于armclang因为有许多的芯片库sdk在armclang下会出问题(定义的__GUN__但是又不能使用.ld文件,会造成很多麻烦,当然有解决办法,比较复杂)
cmake文件的组成部分
1.定义cmake版本以及工程名称
cmake_minimum_required(VERSION 3.12) ##支持的cmake最低版本
project("S350N_M8" C) ##定义项目名称和源码语言(新)
enable_language(ASM) ##启用汇编语言
2.定义编译,链接工具
用于给makefile文件指定交叉编译工具,简单来说就是让makefile知道用什么工具去干活,很重要,那么工具链在哪呢,我们打开文件管理器定位到mdk的安装目录,如下图所示目录:
set(TOLLCHAIN_PATH "D:/keil_v5/armcc/bin") ##先设置一个同意的路径,用set语法相当于编程语言的定义一个字符串
set(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/armcc.exe") ##设置c语言编译链,c++为CMAKE_CXX_COMPILER
set(CMAKE_ASM_COMPILER "${TOOLCHAIN_PATH}/armasm.exe") ##设置汇编编译工具
set(CMAKE_C_LINK_EXECUTABLE "${TOOLCHAIN_PATH}/armlinke.exe") ##设置链接工具
3添加工程源文件和头文件/路径
设置完编译链之后就可以添加代码源文件了,这个有好几个方法,大家也可以自己百度一下cmake的语法或者找一个教程来实践一下,拿我自己的文件举例说明一下:
##file语法,前一个参数是固定的 后面一个参数自己定义
##添加文件的时候注意 相对路径和绝对路径
file(GLOB_RECURSE C_FILES
src/*.c
src/*.h
src/drivers/*.c
src/drivers/*.h
src/sm9/*.h
rtt_src/rtconfig.h
rtt_src/board.c
)
##比如我使用的rtthread的相关文件不想挤在一起,还可以这样
file(GLOB_RECURSE KENEL_FILES
${RTTHREAD_SDK}/src/*.c
${RTTHREAD_SDK}/libcpu/arm/cortex-m4/context_rvds.s
${RTTHREAD_SDK}/libcpu/arm/cortex-m4/cpuport.c
)
##cmake语法比较灵活,空格还有换行这些比较随意,相比之下makefile就死板很多,经常出现修改之后makefile文件就报错了
##然后就可以把文件归属为源码
set(SOURCE_FILES ${C_FILES} ${KENEL_FILES}) ##上面file定义了标识符,有几个写几个就行了,灵活配置
##接下来就是包含头文件路径,比如某些库函数这些,直接设置头文件就行,因为我们一般不会去改他,包含就行
include_directories(
${TOOLCHAIN_DIR}/include
## rtthread kenel include
${RTTHREAD_SDK}/include
src
src/drivers
src/interface
src/sm9
rtt_src
./RTE/_nrf52832_xxaa
${SDK_ROOT}/components/softdevice/common
${SDK_ROOT}/components/libraries/strerror
${SDK_ROOT}/components/drivers_nrf/comp
)
4.定义编译,链接参数
编译链接参数同样很重要,影响到编译的文件的生成,比如说,设置这个有个捷径,我们可以直接从mdk里面拷贝,这里以图片展示比如下面的图片:
c/c++编译选项
注意链接选项这里有一个分散加载文件,路径不要搞错了,一般是从mdk工程里面直接拷过来就行,愿意研究这个文件的可以自己研究
然后cmake里面还有一个语法可以定义编译选项:
5.编译其他选项
link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/path/to/xxx.lib") #加载静态库
#添加可执行文件,依赖上面定义的sourcefile 如果是编译成静态库用add_library()函数,可自行研究
add_executable(${TARGETS} ${SOURCE_FILES} )
至此,就可以用cmake生成makefile文件然后生成elf文件,生成elf文件之后用fromelf文件转换成hex文件就行了,在fromelf的目录用cmd打开,就得到下面这个指令使用说明:
当然,不可能每次都手动去敲命令来进行转换,cmake已经替我们想到了:
set(ELF_FILE ${TARGETS}.elf)
set(HEX_FILE ${TARGETS}.hex)
set(APP_FILE app_${TARGETS}.hex)
set(BIN_FILE ${TARGETS}.bin)
set(elfPath D:/Keil_v5/ARM/ARMCC/bin/fromelf.exe)
add_custom_command(TARGET ${TARGETS} POST_BUILD
COMMAND ${elfPath} --i32 --output=${APP_FILE} ${TARGETS}.exe
)
关于这个指令,网上有很多解释,能单独成一篇文章了,这里只是简单展示用法,在目标(TARGET )创建之后(POST_BUILD)调用这些指令(COMMAND)具体用法读者自行理解吧
同时,很多同学在使用mdk的时候会用过用户自定义指令,比如:
不用担心,cmake也有,还是上面那个指令,在hex生成那里自己添就行了,而且MDK只有两条,我们用cmake想写多少就写多少
运行cmake编译固件
至此我们的cmake就编写完成了,下面就是在cmakelists.txt文件的目录运行指令生成目标,比如:cmake --build .--target all
可以运行指令后看一看生成的文件
此文完,后续介绍Qtcreater和clion相操作与设置.