Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何模拟HeaderFile中的函数?_C_Unit Testing_Gcc_Cmocka - Fatal编程技术网

C 如何模拟HeaderFile中的函数?

C 如何模拟HeaderFile中的函数?,c,unit-testing,gcc,cmocka,C,Unit Testing,Gcc,Cmocka,我在做什么: 我正在使用cmocka为大型嵌入式项目运行单元测试。 嵌入式项目是使用arm gcc编译器编译的。 单元测试使用普通的gcc编译,使用嵌入式代码片段和cmocka库 通常,cmocka建议使用-Wl,--wrap=functionName标志来模拟(替换)一些不需要的子函数。这个效果很好 问题: 在我的嵌入式代码中有一个头文件(foo.h),其中包含一些函数(声明为内联函数)。其中一个函数包含一些用于arm gcc编译器的汇编代码,当然,gcc无法编译这些代码 愚蠢的是,wrap-

我在做什么:

我正在使用cmocka为大型嵌入式项目运行单元测试。 嵌入式项目是使用
arm gcc编译器编译的。
单元测试使用普通的
gcc
编译,使用嵌入式代码片段和cmocka库

通常,cmocka建议使用
-Wl,--wrap=functionName
标志来模拟(替换)一些不需要的子函数。这个效果很好

问题:

在我的嵌入式代码中有一个头文件(
foo.h
),其中包含一些函数(声明为内联函数)。其中一个函数包含一些用于
arm gcc编译器的汇编代码,当然,
gcc
无法编译这些代码

愚蠢的是,
wrap
-标志似乎对放在头文件中的函数不起作用

问题:

如何在headerfile中模拟此函数

我是如何解决这个问题的:

我考虑插入一些
#idef
宏来排除前面提到的汇编程序部分。但这无法完成,因为此文件属于许可库,我不允许更改其内容

我可以将测试中的函数提取到其他文件中,这样就不需要再包含
foo.h
。但这会混淆嵌入式源代码结构

问题的确切界限

准确的代码位于第233行的portmacro.h中:

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;

    __asm volatile
    (
        "   mov %0, %1                                              \n" \
        "   msr basepri, %0                                         \n" \
        "   isb                                                     \n" \
        "   dsb                                                     \n" \
        :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
    );
}
其中as
portFORCE_INLINE
定义为:

#define portFORCE_INLINE inline __attribute__(( always_inline))
愚蠢的是,wrap标志似乎不适用于函数 它们被放置在头文件中

这不是
wrap
的错误,该函数已由编译器内联,因此链接器无法执行任何操作

如何在headerfile中模拟此函数

一个选项是使用
sed
在将有问题的代码传递给gcc之前自动修补该代码。例如改变

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
  uint32_t ulNewBASEPRI;
  ...
}

portFORCE_INLINE static void vPortRaiseBASEPRI_2( void )
{
  uint32_t ulNewBASEPRI;
  ...
}
从你的例子到

portFORCE_INLINE static void vPortRaiseBASEPRI( void );

portFORCE_INLINE static void vPortRaiseBASEPRI_2( void );

正则表达式非常松散,它依赖于这样一个事实:头中的所有定义都有
INLINE
标记,但在您的情况下可能已经足够了


您可以将上述命令嵌入到Makefile中,以在临时文件夹中生成自定义标头,然后使用
-Ipath/to/temp/folder
标志覆盖默认标头。

我没有使用cmocka,因此我不确定框架中是否已经有管理该标头的方法

但是,cmock使用一种方法,将头复制到测试构建的include层次结构中较高的位置(并且只有测试构建,发布构建甚至不会隐式地包含该位置)

然后可以编辑此标头的副本,使函数声明变为
port void vPortRaiseBASEPRI(void)。然后,当生成mock时,将为此(以及同一头中的其他函数声明)生成一个mock,就像在任何其他情况下一样。由于生成的是模拟,因此函数没有匹配的源代码定义(即
.c
文件)并不重要

请参阅上的“处理特定于编译器的内容”部分


我的类似问题以及我是如何解决的:

@LPs但如何解决?链接器无法访问源代码,在链接器运行时,函数已经内联并进行了大量优化。我不确定它与另一个答案(顺便说一句,该答案还提供了自动生成固定标题的解决方案)有什么不同。@yugr,是的,现在您已经编辑了更多解释,它非常相似。之前我以为你是在鼓吹使用
sed
来更改OP声明他无法更改的原始标题。不过,对同一想法的不同解释是:-)
cat tmp.c | sed '/inline\|INLINE/,/^}$/{ s/^\(.*\(inline\|INLINE\).*\)/\1;/; /inline\|INLINE/!d }'