首页 > 解决方案 > 通过在编译时替换静态符号来测试嵌入式代码

问题描述

背景

我正在为嵌入式 Cortex M4 TI-RTOS SYS/BIOS 目标构建 C 应用程序,但是这个问题应该适用于将单个二进制文件加载到某个微处理器上的所有嵌入式目标。

我想要的是

我想在目标上做一些原位回归测试,我只是用一些测试函数替换单个函数。例如,GetAdcMeasurement() 函数将从只读数组返回预定义的值,而不是进行实际测量并返回该值。

这当然可以用一堆#ifndefs 来完成,但我宁愿尽可能保持生产代码不变。

我的尝试

我认为实现这一点的一种方法是在链接器阶段有重复的符号定义,然后让链接器优先考虑来自测试套件的定义(给定一些#define)。

我已经研究过使用 LD_PRELOAD,但这似乎并不适用于这里(因为我只使用静态对象)。

细节

我正在使用 TI Code Composer,在 Sitara AM57xx 平台上使用 TI-RTOS 和 SYS/BIOS,为 M4 远程处理器(表示为 IPU1)进行编译。这是编译器和链接器的路径

/opt/ti/ccsv7/tools/compiler/ti-cgt-arm_16.9.6.LTS/bin/armcl

标签: ccompilationlinkerarm

解决方案


另一种方法(除了 Paul Ogilvie 的方法)是让您的模拟标题也创建一个定义,它将在预处理阶段替换原始函数符号。

即,如果您的模拟标题如下所示:

// mock.h

#ifdef MOCKING_ENABLED

  adcdata_t GetAdcMeasurement_mocked(void);
  stuff_t   GetSomeStuff_mocked(void);

  #define GetAdcMeasurement GetAdcMeasurement_mocked
  #define GetSomeStuff GetSomeStuff_mocked

#endif

然后,无论何时包含该文件,预处理器都会在它到达编译器之前替换调用:

#include "mock.h"

void SomeOtherFunc(void)
{
    // preprocessor will change this symbol into 'GetAdcMeasurement_mocked'
    adcdata_t data = GetAdcMeasurement();
}

这种方法可能会使不知情的代码读者感到困惑,因为他们不一定会意识到您完全调用了不同的函数。尽管如此,我发现这种方法对生产代码的影响最小(显然除了添加包含)。


推荐阅读