项目中遇到需要将代码中定义的软件版本号通过Keil编译,生成包含版本信息的可执行文件(.bin、.hex)文件,通常做法利用Keil编译器在编译结束后可调用bat脚本,因此考虑编写可执行脚本。
#define SOFTWARE_VERSION "1.0.1"
bat脚本从含有版本信息源文件中识别关键字,获取版本字符串,参考资料:KEIL 开发者的福音,这下不用再到处找输出文件了,还能定制文件名,一切都自动搞定!
参考代码:gitee仓库
const uint8_T SoftVersion[8] = {83, 87, 86, 58, 49, 46, 48, 49};
基于第1中情况,需要在脚本中识别存储版本信息字符串,并获取数组中的内容,再将十进制ASCII码转换为字符,脚本实现如下:
@echo off
@REM AUTHOR: Kunn
@REM VERSION: V1.0.0
setlocal enabledelayedexpansion
@REM 请根据实际情况修改以下变量,注意如果使用相对路径,需要以KEIL的工程文件路径为基准,而非本脚本所在路径
@REM KEIL 设置中的输出文件名(Keil中Output设置)
set EXEC_NAME=Name of Executable
@REM KEIL 设置中的输出文件路径
set OBJ_PATH=.\Objects
@REM 输出文件路径
set OUTPUT_PATH=.\Output
@REM 包含版本字符串文件的路径
set VERSION_FILE_PATH=E:\QAES_CODE\BCU_Kunn\Config\ProjectConfig.c
@REM fromelf.exe 的路径(KEIL安装目录)
set FROMELF_PATH=D:\Keil_v5\ARM\ARMCC\bin
@REM 版本字符串的格式
REM set VERSION_PATTERN="#define SOFTWARE_VERSION"
set VERSION_PATTERN= "const uint8_T SoftwreVersion"
@REM 获取日期【这里的日期格式为 YYYY-MM-HH hh:mm:ss,不同时区或配置下格式可能不同,请自行调整】
set YEAR=%DATE:~2,2%
set MONTH=%DATE:~5,2%
set DAY=%DATE:~8,2%
set HOUR=%TIME:~0,2%
set MINUTE=%TIME:~3,2%
set SECOND=%TIME:~6,2%
set CURRENT_DATE=%YEAR%%MONTH%%DAY%_%HOUR%%MINUTE%%SECOND%
@REM echo "Current date: %CURRENT_DATE%"
set "targetArrayName=SoftwreVersion"
:: 查找包含数组定义的行,并提取数组内容
for /f "usebackq tokens=*" %%a in (`findstr "%targetArrayName%" %VERSION_FILE_PATH%`) do (
set "arrayDefinition=%%a"
)
:: 从数组定义中提取数组内容
for /f "tokens=2 delims={}" %%b in ("!arrayDefinition!") do (
set "arrayContent=%%b"
echo %%b
)
REM pause
:: 使用certutil将十进制数组转换为文本
for %%c in (%arrayContent%) do (
set /a "char=%%c"
CALL :CONV_ASCII_TO_CHAR %%c
)
GOTO :END
:CONV_ASCII_TO_CHAR
REM make conversion from ASCII value to character.
REM CHARA_SET: This is a set of characters
SET CHARA_SET= ^^^!^"#$^%%^&'()*+,-./0123456789^:;^^^<=^^^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^^^_`abcdefghijklmnopqrstuvwxyz{^|}~
REM BASE: Base character ' '(SP), others character ASCII offset calculation will base on it.
SET BASE=0x20
SET /A OFFSET=%1-BASE
IF %OFFSET% GEQ 0 IF %OFFSET% LSS 96 (
SET "CHAR=!CHARA_SET:~%OFFSET%,1!"
REM ECHO Converted Character: !CHAR!
set "result=!result!!CHAR!"
) ELSE (
GOTO :BUILDWITHERROR
)
GOTO :EOF
:END
:BUILDWITHERROR
:: 输出结果
echo Software Version: %result%
REM REM endlocal
REM pause
REM set output_file_name=%EXEC_NAME%
if not exist %OUTPUT_PATH% mkdir %OUTPUT_PATH%
echo "Clean old files..."
for /f "delims=" %%A in ('dir /b %OUTPUT_PATH%') do del %OUTPUT_PATH%\%%A"
REM set output_file_name=%output_file_name%_V%result%_%CURRENT_DATE%
REM set output_file_name=%output_file_name%-%result%
set output_file_name=%result%
@REM GET BIN
echo "Output bin file: %OUTPUT_PATH%\%output_file_name%.bin"
%FROMELF_PATH%\fromelf --bin %OBJ_PATH%\%EXEC_NAME%.axf --output %OUTPUT_PATH%\%output_file_name%.bin
@REM GET HEX
echo "Output hex file: %OUTPUT_PATH%\%output_file_name%.hex"
copy %OBJ_PATH%\%EXEC_NAME%.hex %OUTPUT_PATH%\%output_file_name%.hex
pause
exit
@echo off
setlocal enabledelayedexpansion
:: ASCII码
set "asciiCode=67"
:: 使用set /a将ASCII码转换为字符
set /a "char=!asciiCode!"
:: 输出结果
echo Converted Character: !char!
endlocal
:: 使用certutil将十进制数组转换为文本
for %%c in (%arrayContent%) do (
set /a "char=%%c"
CALL :CONV_ASCII_TO_CHAR %%c
)
GOTO :END
:CONV_ASCII_TO_CHAR
REM make conversion from ASCII value to character.
REM CHARA_SET: This is a set of characters
SET CHARA_SET= ^^^!^"#$^%%^&'()*+,-./0123456789^:;^^^<=^^^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^^^_`abcdefghijklmnopqrstuvwxyz{^|}~
REM BASE: Base character ' '(SP), others character ASCII offset calculation will base on it.
SET BASE=0x20
SET /A OFFSET=%1-BASE
IF %OFFSET% GEQ 0 IF %OFFSET% LSS 96 (
SET "CHAR=!CHARA_SET:~%OFFSET%,1!"
REM ECHO Converted Character: !CHAR!
set "result=!result!!CHAR!"
) ELSE (
GOTO :BUILDWITHERROR
)
GOTO :EOF
:END
:BUILDWITHERROR
实现关键:ASCII码转字符串类似查表的方式,计算ASCII码到0x20差值,然后在字符串中取响应位置字符。