一、前言在之前的文章中,我写了cmake改造嵌入式编程的心得体会。点此摆脱MDK,使用cmake改造嵌入式软件开发体验。使用IDE配置并运行cmake项目,给了我很大的鼓励(手动滑稽),今天分享一下嵌入式开发中最重要的环节,固件发布,毕竟程序写的再牛逼,固件也出不来,怎么办老板卖钱?二.常用做法首先给大家讲解一下大家制作嵌入式发布程序的大致流程:程序员在MDK中编译固件后,会在工程目录的build文件夹中生成编译好的hex文件,如下图:然后程序员会把固件复制到一个新的文件夹,重命名(因为mdk中生成的固件名称是固定的),一般写产品名称,版本号,然后会加上一些特殊的定义(比如什么至尊版,增强版,普通版等等区分同一个产品的不同价位或者功能),然后写一个changlist或者版本记录,然后把版本记录复制到文件夹中,然后压缩发给测试人员或生产负责人。2.高级方法1.0高级方法是写一个脚本,比如python脚本或者bat(shell)脚本,在脚本中执行一些copy或者一些系统命令,比如nrf52832带sdk的程序需要将sdk合并到最终的Hex文件中.例如:这种方法比手动修改更高级,我们称之为高级1.0,但是这种方法有一个缺点,编译固件时无法根据参数自定义固件的名称,但是有一种方法,build文件夹下有一个.dep文件,可以用python脚本解析里面的具体字符,例如:比如我需要知道在编译固件的时候是否定义了宏TIANYI,我可以这样写:这样,就可以为某个编译参数生成具有特定名称的固件,也算是一种改进。如果你使用MDK,你可以使用这个方法。3.进阶方法2.0进阶方法2.0是进阶方法1.0的升级版,前提是你需要搭建cmake编译环境,闲话少说,法宝:这段代码是cmake中添加的编译期间定义的语句,结合结合之前的cmake环境搭建教程,应该不难理解combined语句的字面意思,首先我们定义这样的编译参数,然后我们得到所有的编译参数,组成一个名为defs的数组(数组类型在cmake语法,这里不需要理解这个数组是如何存储的)。在cmake中添加一个target,叫merge,名字随便取:这段代码可以理解为:如果我需要生成一个mergetarget,就可以了调用以下cmd命令行语句。这条语句的作用是使用python启动一个脚本。启动脚本时,会带上相应的参数。这个参数就是我们提取出来的defs,然后在python脚本中打印出参数。是的,会是这样的:看,我们刚才定义的宏定义在python文件中已经获取到了,但是有一点不太好,比如我们的cmake文件中SOFT_VER=809,同样显示在python,这不利于我们提取真实的数据,没关系,python这么高级的语言,这可不是小事,让他:如上图,我们花几分钟(专业人士请不要不羡慕)写出解析函数,形成字典(dict,python的一种数据结构):字典是键值对的数据结构,可以理解为不以数字为下标的数组,但是python的类型非常灵活。不懂的同学可以研究python接下来的事情太简单了,我们只需要分别取出字典的key和value即可。对于一些参数,如果没有值,我们就不需要他的值。如果比较复杂,需要打开.dep文件,逐行找到对应的宏。是不是更简单高效(不用读文件)你以为就这样结束了,错了,那我们要合并Firmware,然后把所有相关文件压缩成一个压缩包单独存放,你只需要单击一个按钮。比如我的项目,除了生成hex之外,还生成了一个ota升级的固件包,同时编译好的源码hex也要保存下来,方便问题的追溯。请注意:是的,就是这么短短的几行语句。在不一定没有错误的步骤之前,您需要花几分钟时间。我们使用几行脚本语句来实现它。接下来就是运行脚本了,运行方法:打开cmd命令行,输入:`cmake--build.build--targetmerge`等待电脑帮你打包。如果想简单点,qtcreater,clion,包括mdk都有外部工具可以创建。创建完成后点击运行就ok了:这个是clion,这个是qtcreater,这个是mdk----------19-12-10update-----------4.MDK进阶版最近发现MDK也可以实现和clion或者qtcreater一样的进阶方法。分享如下。本质上,它仍然使用python脚本。Python真的可以做很多事情。配置如图:很简单,就是调用python执行merge.py脚本,那么如何实现编译时定义的各种定义至于参数,一种方法是读取上面提到的.dep文件,这种方法最简单,效率也最高。另外,附上高级用法:1)。获取宏定义的进阶方法——编译mdk时,有一个选项misc_ctrl,如图,在这里添加一行:--viadefines.opt然后在工程目录下创建一个defines.opt文件,打开用文本编辑器,填入一个宏定义如-DSOFTVERSION=101-DUSE_UART,例如:那个文件的作用是什么?用过MAKEFILE的童鞋们可能已经体会到了,因为makefile中有这样的语法。这样写这个文件的效果和编译时指定的宏定义是一样的。比如同学们可以做实验,如果用这个文件编译,在程序中定义-D后就可以读取变量,那么既然有文件就好办了,如果用python解析文件,它会形成一个定义字典,比如:还是熟悉的Regular,还是熟悉的py,换汤不换药,这里有个re.sub函数,这个函数就是替换'""这样的字符,因为语法opt文件,直接定义某个字符串会导致程序无法正确识别。必须用''将""中的内容括起来,才能让程序识别为字符串。下面的事情就清楚了。和进阶版3.0一样,固件包也是一样的。愿意学习的学生只要研究2)。高级获取宏定义的第二种方法需要解析xml文件。我们都知道每个MDK项目都是由一个.uvprojx文件管理的(mdk4就是.uvproj)。我们尝试用文本编辑看看里面是什么:咦,这不就是一个xml文件吗?让我们看看里面有什么:哦,咦,怎么这么眼熟?原来我们在编辑器上宏定义的东西都在Here,看这里:不懂的同学可以把宏定义多改几下再编译或者退出mdk重新打开看看影响。嗯,接下来就不是py穿梭了:这段代码也很简单,无非就是打开xml文件,然后读取tag、attr和text。对XML文件不熟悉的同学百度一下就知道了。并不比json难多少。使用python我们可以很容易的获取到我们定义的宏定义,接下来的事情就不用多说了,但是值得一提的是,如果这个方法中定义的宏中包含字符串,则需要进行处理,比如:PRODUCT="S350N",不要像optfiles那样用单引号把它包起来,但是如果要在程序中使用的话,应该是这样的:不难理解。具体原因我就不说了。同学们可以根据我的葫芦画葫芦。以上是更新内容。最近发现MDk还好,还是比较灵活的。下篇文章会涉及到MDK的一些高级操作。请评委们注意。5.总结目前,关于固件生成的批处理,简单的研究到此结束。如果同学们有什么需要,可以一起讨论。文章难免有错误。欢迎指正。
