C 如何模拟HeaderFile中的函数?
我在做什么: 我正在使用cmocka为大型嵌入式项目运行单元测试。 嵌入式项目是使用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-
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 )
);
}
其中asportFORCE_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 }'