使用 googletest 测试嵌入式 C++ 代码时处理外围寄存器的重复符号

Handling duplicate symbols for peripheral registers when testing embedded C++ code using googletest

我正在使用 C++ 为 MSP430F5529 开发一个业余项目,并使用 googletest 进行测试。我是 C/C++、microcontrollers/embedded 和 googletest 的真正初学者。

MSP 上的外围设备是通过寄存器控制的,TI 提供了一个 header <msp430.h>,其中包括特定于处理器的 header、msp5529.h,在我的例子中header 为位等定义了大量常量,但它也声明了微控制器上可用的寄存器,例如 UCA1CTL1 用于设置串行通信。

例如,当我为构建编译时 <msp430.h> 包含在 UART.h 中,一切都按预期工作。但是,在测试时,我想包含一个可测试的 <msp430.h> 版本,我们可以将其称为 testable_msp430.h.

所以基本上我们有以下内容:

UART.h

#ifndef TESTING
#include <msp430.h>
#else 
#include "testable_msp430.h"
#endif

testable_msp430.h

int UCA1CTL1;

*A bunch of other declarations*

test_UART.cpp

#include UART.h

*A bunch of tests*

UART.cpp

#include UART.h

*A bunch of source*

问题是,当通过 运行 g++ -std=c++11 src/UART.cpp test/test_UART.cpp -lgtest -lgtest_main -pthread -o testOutput -DTESTING 编译测试时,我得到一个 link 错误,指出

duplicate symbol _UCA1CTL1 in:
    /var/folders/yr/mkwg3mhs1nl93l35x6t55vz80000gn/T/UART-772fab.o
    /var/folders/yr/mkwg3mhs1nl93l35x6t55vz80000gn/T/test_UART-2e1a90.o

这是有道理的,因为 UCA1CTL1UART.cpptest_UART.cpp 的编译单元中都定义了。因此,我的问题是通常如何处理内存映射寄存器以便能够测试 against/using 它们?

提前致谢!

您在 testable_msp430.h 中有 定义 而不是 声明 。而不是:

int UCA1CTL1;

你应该有:

extern int UCA1CTL1;

然后在另一个仅链接到测试或包装在 #ifndef TESTING 中或在 test_UART.cpp 中的翻译单元中,您放置 单个 测试定义 UCA1CTL1 .

几件事:

  • 使用header 守卫。 testable_msp430.h 应该像

    #ifndef TESTABLE_MSP430_H
    #define TESTABLE_MSP430_H
    /* contents */
    #endif
    
  • 不要在 header 中声明变量。如果您需要在多个文件中共享它们,header 中的所有变量都应该是 extern 并且它们应该在与 header.[= 同名的 .c 文件中分配。 15=]

  • int UCA1CTL1; 对于寄存器来说是无稽之谈。如果 linker 为您在正确的内存位置分配了这个变量,它应该是 volatile uint8_t UCA1CTL1;(假设 8 位寄存器)。如果 linker 没有 link 它位于特定的、正确的内存位置,您可以考虑使用可移植宏而不是变量:

    #define UCA1CTL1 (*(volatile uint8_t*)0x1234u)
    

    其中0x1234是寄存器的地址。这也解决了在 header 文件中分配变量时遇到的 linker 问题。

    像这样的宏是跨多个编译器获得完全可移植的寄存器映射的唯一方法。缺点是您不会在传递给调试器的文件中获得实际的 object,因此您无法像使用变量那样查看宏。

    但是,任何 half-decent 微控制器调试器都带有对所有外围设备的硬件支持,允许您从那里查看寄存器,所以只要您不打算使用垃圾质量,这就不是问题调试器。