c++ - 在老式嵌入式 c/c++ 代码上启用现代代码分析工具
问题描述
如何在老式嵌入式 c/c++ 源代码上使用现代代码分析工具,例如SourceTrail,最初用于 Hi-Tech C、PIC C、IAR Workbench 等编译器,用于许多微控制器,不仅限于 PIC、PIC16、和 Microchip 的 PIC18 系列。
为了支持微型微控制器的有限架构,嵌入式编译器的供应商不得不提出对 c/c++ 语言的扩展,这些扩展已经(或尚未)在 c 语言规范中。
这会导致微控制器特定的头文件包含以下内容:
// Register: ANSELA
extern volatile unsigned char ANSELA @ 0xF38;
#ifndef _LIB_BUILD
asm("ANSELA equ 0F38h");
#endif
typedef union {
struct {
unsigned ANSB0 :1;
unsigned ANSB1 :1;
unsigned ANSB2 :1;
unsigned ANSB3 :1;
unsigned ANSB4 :1;
unsigned ANSB5 :1;
};
} ANSELBbits_t;
extern volatile ANSELBbits_t ANSELBbits @ 0xF39;
extern volatile unsigned short long TBLPTR @ 0xFF6;
extern volatile __bit ABDEN1 @ (((unsigned) &BAUDCON1)*8) + 0;
和代码文件包括这样的东西:
void interrupt high_priority InterruptVectorHigh(void)
{
}
void interrupt low_priority InterruptVectorLow(void)
{
}
用现代工具支持这个源代码的最简单方法是什么,同时确保源代码仍然可以与原始编译器一起使用?
编辑:
下面给出了答案。
解决方案
下面的修复将使任何支持 C18 或 C2x 规范的编译器都能理解 c 代码。我(还)没有机会用 C++ 进行测试,所以它们可能不完全符合任何 C++ 规范。
感谢@Antti Haapala、@Clifford 和@anastaciu 等人 在这里和这里回答了我的相关问题并启用了这个更完整的答案。
short long
类型_
首先,24 位short long
类型是个问题,因为在 c 规范中不存在等价物,而且该类型的两个字不能用#define
. 起初,我使用 Perl 将字符串简单地修改short long
为long
所有特定于供应商的头文件,如下所示:
perl -pi -e "s/(short long)/long/g" .h
注意,对于 Windows 上的 Microchip MPLAB CX8 编译器,头文件位于以下文件夹和子文件夹中:c:\Program Files (x86)\Microchip\xc8\v1.33\include
但后来我意识到该short
类型永远不会单独使用,所以我决定简单地short
使用#define short
. 请注意,这会影响任何使用short
,所以我在这个答案中留下了这两种方法。
用@定义的寄存器位和字节地址
@-signs 是一个特定的问题,因为它们无法使用 重新定义#define
,所以 perl 再次进行救援,这次使用两次传递来解决两种不同的语法:
perl -pi -e "s/@\s*([0-9a-fA-FxX]+)/AT($1)/g" .h
perl -pi -e "s/[@] ?+([^;]*)/AT($1)/g" .h
这些本质上包装了@
in之后的任何内容AT()
,允许正常的定义对其进行操作。
额外的关键字
最后一点是在编译器供应商提供的每个头文件中插入一个宏头文件。我最终得到了以下宏标头:
// Hack to allow SourceTrail to be used on this source
#if defined __XC8
#define AT(address) @ address
#else
#define AT(address)
#define __bit _Bool
#define asm(assembly)
#define interrupt
#define short
#define high_priority
#define low_priority
#endif
可以看出,除了 MPLAB XC8 编译器使用头文件时,任何非标准的内容都会被简单地删除。唯一的例外是__bit
类型,它被重新定义为_Bool
类型 - 它似乎工作。
作为在 Windows 上运行的批处理脚本的完整修复
当我在 Windows 上运行所有这些时,Perl 单行程序并不像在 Linux 上那样真正工作,所以为了处理每个头文件,我不得不将 Perl 命令包装在一个批处理 for 循环中,这很慢。为了弥补这一点,我将所有内容合并到一个名为 的批处理中fix.cmd
,该批处理位于包含文件夹中(请参见上面的路径):
:: Fix to allow SourceTrail to analyze MPLAB CX8 source code.
@echo off
setlocal enabledelayedexpansion
:: Run in the folder where the script exists.
pushd "%~dp0"
echo:Fixing MPLAB global include files to be used by SourceTrail and other analysis tools.
:: Loop each directory recrusively
set DirCounter=0
set FileCounter=0
for /r %%d in (.) do (
set /A DirCounter=DirCounter+1
pushd %%d
echo | set /p=Processing:
cd
for %%f in (*.h) do (
set /A FileCounter=FileCounter+1
set /A ModValue=FileCounter%%25
if !ModValue!==0 ( echo | set /p=* )
call :ProcessFile %%f
)
popd
echo *
)
echo:Processed %FileCounter% files in %DirCounter% folders.
echo Done
exit /b 0
:ProcessFile
:: filename is in %1
:: Remove short from short long. (Done with a define instead)
:: perl -pi -e "s/(short long)/long/g" %1
:: Replace the simple @ lines with AT().
perl -pi -e "s/@\s*([0-9a-fA-FxX]+)/AT($1)/g" %1
:: Exchange @ and wrap in parenthesis for any substring starting with @ and ending with ; in each header file.
perl -pi -e "s/[@] ?+([^;]*)/AT($1)/g" %1
:: Insert defines before first line in each header files:
perl -pi -e "print \"// Hack to allow SourceTrail to be used on this source\n#if defined __XC8\n #define AT(address) @ address\n#else\n #define AT(address)\n #define __bit _Bool\n #define asm(assembly)\n #define interrupt\n #define short\n#define high_priority\n #define low_priority\n#endif\n\n\" if $. == 1" %1
::Exit subroutine
exit /b
要执行修改,请打开提升的提示符,cd 到包含文件,然后执行fix.cmd
先决条件
Perl 必须安装在 Windows 计算机上。我使用StrawberryPerl
编辑:主要是固定的错别字。澄清了如何处理有两种选择short long
推荐阅读
- python - LabelEncoder 将列中的每个值更改为“LabelEncoder()”
- python - 将每列乘以该列旁边的列并创建单列
- c# - 除了背景图像之外,CSS代码在mvc中不起作用
- c# - 典型的分层架构——项目结构
- shell - 通过 SSH / Cygwin 从 mac rsync 到 Windows 10
- android - 未找到 Gradle DSL 方法:'kapt()'
- r - R:如何在 ggplot 字幕中将 2019-04-29 显示为 2019 年 5 月 29 日?
- macos - 模拟器无法在 Mac OS 10.11.16 中启动,需要 Mac OS 10.12 或更高版本
- selenium - 选择/单击单选按钮后,在“goo.gl/RVdKM9”处,状态仍然为假
- azure - 如何使用 Azure FaceAPI 通过 faceId 或 thumbnailId 获取性别和年龄