Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
gcov
关于RTT使用gcc gcov进行覆盖率测试的问题
发布于 2023-03-26 16:00:13 浏览:1172
订阅该版
[tocm] 由于公司要求所有机载代码必须完成单元测试、覆盖率测试,单元测试使用直接借用了[RTT的UTEST框架](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/utest/utest "RTT的UTEST框架"),覆盖率是想采用gcc的gcov来完成,但是遇到的问题。 由于嵌入式下和linux环境下gcov有些区别,因为嵌入式环境下无法自己生成.gcda文件,需要在系统退出的时候调用_gcov_exit()函数,将相关的覆盖率信息写入到文件系统里面。 首先是学习了[海南大学-刘伟仓库代码之后](https://gitee.com/jswyll_com/gcov "海南大学-刘伟仓库代码之后"),了解到已经有其它[前辈完成了这部分工作](https://github.com/nasa-jpl/embedded-gcov "前辈完成了这部分工作"),embedded-gcov接入到rtt中,我将embedded-gcov移植到qemu-vexpress-a9后,[并将代码发布到了gitee上](https://gitee.com/latercomer/rtt-gcov "并将代码发布到了gitee上")。 **遇到的问题是:如果使用rtt studio自带的gcc 5.4.1工具链,可以通过qemu.bat正常启用编译之后的rtthread.bin,但是如果使用env 1.3.5自带的gcc 10.3.1无法通过qemu.bat启动rtthread.bin程序,会卡死不动。** **RTT的版本是V4.1.1,具体操作过程如下:** ## 0、将embedded-gcov代码拷贝到qemu-vexpress-a9/application 切换到$rt-thread/bsp/qemu-vexpress-a9目录,在env中执行scons --dist拷贝一个完整的bsp,然后将embedded-gcov代码复制到application目录。目前还不能直接编译,需要按照后面的步骤修改。 ![2023-03-26_21-00-48.png](https://oss-club.rt-thread.org/uploads/20230326/2d079fe71791b2a002260efb14f3c6a8.png.webp) ![2023-03-26_20-52-32.png](https://oss-club.rt-thread.org/uploads/20230326/c05930eca6dfc962bb7b5baffcc29d58.png.webp) ## 1、在rtconfig.py中增加覆盖率相关编译选项 使用gcc/g++作为主要的编译器,如果需要产生覆盖率数据需要在Makefile或者Scons文件中做下面的编译链接设置:编译的时候,增加 -fprofile-arcs -ftest-coverage 或者 –coverage,链接的时候,增加 -fprofile-arcs 或者 –lgcov,因此在rtconfig.py的编译选项中增加-fprofile-arcs -ftest-coverage ```c if PLATFORM == 'gcc': # toolchains PREFIX = 'arm-none-eabi-' CC = PREFIX + 'gcc' CXX = PREFIX + 'g++' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' TARGET_EXT = 'elf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' STRIP = PREFIX + 'strip' #这里增加了-fprofile-arcs -ftest-coverage编译选项,该选项会传递个LFAGS和CXXFLAGS DEVICE = ' -march=armv7-a -marm -msoft-float -fprofile-arcs -ftest-coverage' CFLAGS = DEVICE + ' -Wall -Werror' AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ -I.' LINK_SCRIPT = 'link.lds' LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors' +\ ' -T %s' % LINK_SCRIPT ``` ## 2、修改gcov_public.h和gcov_public.c文件中宏定义和初始化向量表 ```c #ifdef GCOV_OPT_PROVIDE_CALL_CONSTRUCTORS /* start and end of constructor section defined in link file */ /* you have to provide appropriate linker file code to define these, * if your compiler/runtime environment does not automatically. * An example linker file segment: .ctors : { __ctor_list = . ; *(SORT(.ctors.*)) *(.ctors) __ctor_end = . ; . = ALIGN(16); } > ram */ extern void *__ctors_start__; // RTT的初始化向量表是__ctors_start__,因此这里需要修改下 extern void *__ctors_end__; #endif // GCOV_OPT_PROVIDE_CALL_CONSTRUCTORS ``` ```c /* Function to print a string without newline. * Not used if you don't define either GCOV_OPT_PRINT_STATUS * or GCOV_OPT_OUTPUT_SERIAL_HEXDUMP. * If you do, you need to set this as appropriate for your system. * You might need to add header files to gcc_public.c */ #ifndef GCOV_OPT_PROVIDE_PRINTF_IMITATION int rt_kprintf(const char *fmt, ...); #define gcov_printf rt_kprintf // 将打印函数替换为rt_kprintf #endif ``` ```c void __gcov_call_constructors(void) { void **ctor; /* Reinitialize static variables. * In case of unusual situations, where your code re-executes * this function without your code actually restarting, * so that static variables would otherwise * be left as is, not reinitialized. * * This does not clear line counters that might also * remain in such a situation, call __gcov_clear() if * you need to clear the counters. * * If not actually restarting, and if using malloc, * and if you do not call __gcov_exit between calls * to this function to free the memory, * you will have memory leaks. */ gcov_headGcov = NULL; #ifndef GCOV_OPT_USE_MALLOC gcov_GcovIndex = 0; #endif ctor = &__ctors_start__; // 同理这里也需要修改为rtt初始化向量表收尾地址 while (ctor != &__ctors_end__) { void (*func)(void); func = (void (*)(void))(*(uint32_t *)ctor); func(); ctor++; } } #endif // GCOV_OPT_PROVIDE_CALL_CONSTRUCTORS ``` ## 3、在main中调用_gcov_call_constructors和_gcov_exit函数,正常情况会在sd.bin中生成gcov_output.bin文件 ```c int main(void) { __gcov_call_constructors(); rt_kprintf("code1_function: %d\n", 5); rt_kprintf("code1_function: %d\n", 11); rt_kprintf("code2_function: %d\n", 23); rt_kprintf("code2_function: %d\n", 44); __gcov_exit(); printf("Hello RT-Thread!\n"); return 0; ``` ## 4、使用rtt studio自带的gcc 5.4.1进行编译,并运行qemu.bat,正常启动了 先启动C:\RT-ThreadStudio\platform\env_released\env\env.exe,并将RTT_EXEC_PATH设置为5.4.1版本的路径,然后编译并运行qemu.bat ```bash cd /d d:/0.workshop/qemu-vexpress-a9 set RTT_CC=gcc # rtt studio目前5.4.1,6.3.1,10.2.1三个版本的gcc,设置RTT_EXEC_PATH路径为5.4.1,此时Newlib version:2.4.0 set RTT_EXEC_PATH=C:/RT-ThreadStudio/repo/Extract/ToolChain_Support_Packages/ARM/GNU_Tools_for_ARM_Embedded_Processors/5.4.1/bin # 显示gcc版本 %RTT_EXEC_PATH%\arm-none-eabi-gcc --version #开始编译工程 scons -j12 #将qemu添加到path环境变量 set PATH=C:/RT-ThreadStudio/repo/Extract/Debugger_Support_Packages/RealThread/QEMU/4.2.0.4;%PATH% # 显示qemu版本 qemu-system-arm --version #启动rtthread.bin程序 qemu.bat ``` 终端显示如下,可以看到,_gcov_call_constructors和_gcov_exit函数正常运行了。 ![2023-03-26_21-16-18.png](https://oss-club.rt-thread.org/uploads/20230326/27e53e944b944918ca20a80b4a82c9fb.png) ``` $ qemu.bat WARNING: Image format was not specified for 'sd.bin' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. Specify the 'raw' format explicitly to remove the restrictions. \ | / - RT - Thread Operating System / | \ 4.1.1 build Mar 26 2023 16:26:42 2006 - 2022 Copyright by RT-Thread team lwIP-2.0.3 initialized! [I/sal.skt] Socket Abstraction Layer initialize success. [I/SDIO] SD card capacity 65536 KB. [I/SDIO] switching card to high speed failed! [I/FileSystem] file system initialization done! rt_hw_us_delay() doesn't support for this board.Please consider implementing rt_hw_us_delay() in another file. rt_hw_us_delay() doesn't support for this board.Please consider implementing rt_hw_us_delay() in another file. rt_hw_us_delay() doesn't support for this board.Please consider implementing rt_hw_us_delay() in another file. 0:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\applications\mnt.gcda 1:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\applications\main.gcda 2:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\applications\gcov_gcc.gcda 3:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\applications\gcov_public.gcda 4:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\board.gcda 5:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\secondary_cpu.gcda 6:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\drv_timer.gcda 7:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\serial.gcda 8:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\drv_smc911x.gcda 9:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\drivers\drv_sdio.gcda 10:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\kernel\src\signal.gcda 11:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\kernel\src\cpu.gcda 12:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\kernel\src\object.gcda 13:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\kernel\src\scheduler.gcda 14:__gcov_init called for D:\0.workshop\qemu-vexpress-a9/build\kernel\src\mempool.gcda ``` **使用7zip压缩工具打开sd.bin文件**,看到里面已生成了gcov_output.bin文件,只要将这个文件解压出来,并使用相关工具就可以生成覆盖率报告。 ![2023-03-26_16-33-24.png](https://oss-club.rt-thread.org/uploads/20230326/1e1d7c95233e6e4ba0bb7b1c40beec81.png) ## 5、使用gcc 10.x.1进行编译,并运行qemu.bat,则卡死在启动页面 先启动C:\RT-ThreadStudio\platform\env_released\env\env.exe,并将RTT_EXEC_PATH设置为10.2.1版本的路径,然后编译并运行qemu.bat ```bash cd /d d:/0.workshop/qemu-vexpress-a9 set RTT_CC=gcc # rtt studio目前5.4.1,6.3.1,10.2.1三个版本的gcc,设置RTT_EXEC_PATH路径为10.2.1,此时Newlib version:3.3.0 set RTT_EXEC_PATH=C:/RT-ThreadStudio/repo/Extract/ToolChain_Support_Packages/ARM/GNU_Tools_for_ARM_Embedded_Processors/10.2.1/bin # 显示gcc版本 %RTT_EXEC_PATH%\arm-none-eabi-gcc --version # 开始编译工程 scons -j12 # 将qemu添加到path环境变量 set PATH=C:/RT-ThreadStudio/repo/Extract/Debugger_Support_Packages/RealThread/QEMU/4.2.0.4;%PATH% # 显示qemu版本 qemu-system-arm --version # 启动rtthread.bin程序 qemu.bat ``` 当然也可以使用env-1.3.5的终端C:\env-windows-v1.3.5\env.exe,直接编译,env-1.3.5只集成了gcc 10.3.1,qemu是v7.x ```c cd /d d:/0.workshop/qemu-vexpress-a9 # 显示gcc版本 %RTT_EXEC_PATH%\arm-none-eabi-gcc --version # env-1.3.5默认自带的gcc就是10.3.1,因此不需要设置RTT_EXEC_PATH,直接编译 scons -j12 # 使用env-1.3.5自带的qemu,版本要比rtt studio的高一些,好像v7.1.0 set PATH=C:\env-windows-v1.3.5\tools\qemu\qemu32;%PATH% # 显示qemu版本 qemu-system-arm --version # 启动rtthread.bin程序 qemu.bat ``` 运行结束后,终端就卡死在启动界面 ![2023-03-26_16-51-13.png](https://oss-club.rt-thread.org/uploads/20230326/51cbc8c302536b4d32670cf76ec9ea9c.png) so,请教下,各位大神该如何解决呢,由于我们的机载代码有c++14的特性,因此我们采用的是env-1.3.5自带的10.3.1编译器,gcc 5.4.1是无法编译的。 谢谢各位大神指教。
查看更多
聚散无由
2023-03-26
https://jswyll.com/
我是海南大学刘伟本人,已向你的代码仓库提交了pull request:
,请查收。 你的问题在于: 1. 将全部源文件文件都添加了覆盖率测试选项,这是有问题的,启动代码、库文件等等都不应该添加覆盖率选项,否则调用__gcov_call_constructors时也会调用那些文件的__gcov_init; 2. 链接选项里没有添加覆盖率选项 正确的使用步骤为: ## 单元测试 & 代码覆盖率 ### 相关目录结构 ```sh 工程主目录 ├── applications/ │ ├── src/ │ │ ├── SConscript # 需要添加覆盖率测试参数 │ │ ├── jswyll_packet.c # 应用代码 │ │ └── jswyll_packet.h │ ├── test/ │ │ ├── gcov/ # 代码覆盖率收集 │ │ ├── unity/ # 单元测试库,参见https://github.com/ThrowTheSwitch/Unity │ │ ├── test_all.c # 测试总入口 │ │ ├── test_all.h │ │ ├── test_jswyll_packet.c # 测试jswyll_packet │ │ ├── test_jswyll_packet.h │ │ ├── unity_config.h # 单元测试配置 │ │ └── write_gcda.py # 脚本,用于将打印的gcda的Hex数据写入对应的文件 │ ├── main.c # 应用主入口 ├── build/ │ ├── lcov/ │ │ ├── index.html # 代码覆盖率输出结果首页 ├── rtconfig.py # 需要添加覆盖率测试参数 ``` ### 首次使用 1. 下载Git;下载[lcov](https://github.com/linux-test-project/lcov/releases "Releases · linux-test-project/lcov") 版本v1.15及以上,下载、解压后将lcov文件夹下的bin/文件夹添加到PATH环境变量(重启电脑) 2. 新建文件夹,用于编写应用代码(被测试代码,例如:`applications/src`) 3. 从[applications/SConscript](applications/SConscript "applications/SConscript")将编译脚本到第1步的路径下,并将第8行修改为: ```python group = DefineGroup('文件夹名', src, depend = [''], CPPPATH = CPPPATH, LOCAL_CFLAGS=' --coverage') ``` > 其中`--coverage`等价于`-fprofile-arcs -ftest-coverage`这表示将这个文件夹的源码添加覆盖率测试(插桩)。 4. 修改[rtconfig.py](rtconfig.py "rtconfig.py")的LFLAGS,`LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors --coverage' + ' -T %s' % LINK_SCRIPT`,使链接时将相关的代码也使用覆盖率测试。 5. 在除了第1步被测试以外的文件夹下编写测试代码,调用被测试代码。 ```c __gcov_call_constructors(); test_xxx(); __gcov_exit(); ``` 6. 编译并运行代码,将生成的gcda文件的内容放在输出的提示路径上 7. 在工程主目录右键,选择`Git Bash Here`,输入 ```sh lcov -c -d . --rc lcov_branch_coverage=1 -o build/test.coverage --gcov-tool 编译器路径/bin/arm-none-eabi-gcov && genhtml --branch-coverage build/test.coverage -o build/lcov ``` > **注意:**编译器的路径应和编译代码时的版本一致。将`编译器路径/bin/`添加到系统环境变量(然后重启电脑),则上述命令可以省去`编译器路径/bin/` 8. 用浏览器打开`build/lcov/index.html`,查看被测试代码的覆盖结果 ### 后续使用 修改被测试代码或测试代码后,重复上述步骤6\~8。
7
个回答
默认排序
按发布时间排序
lchnu
2023-03-26
Witness, Understand, Skill
谢谢分享!刘伟是我们团队的,小伙子很不错。哈哈,世界很小。
aozima
2023-03-26
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
谢谢分享👍 建议可以分开来,先确定并解决:使用新版工具链,不启用gcov时,是否也启动不了。
RTT_逍遥
认证专家
2023-03-26
https://github.com/supperthomas
谢谢分享
bernard
2023-03-27
这家伙很懒,什么也没写!
海南大学 李创老师团队及刘伟小伙伴 超赞👍
peter112233
2023-07-07
这家伙很懒,什么也没写!
请问下公司有sonar,有和sonar对接的资料吗?
bugcatcher
2024-05-24
这家伙很懒,什么也没写!
请问一下,如果要测试操作系统代码自身的覆盖率,需要怎样配置
撰写答案
登录
注册新账号
关注者
0
被浏览
1.2k
关于作者
latercomer
这家伙很懒,什么也没写!
提问
9
回答
21
被采纳
2
关注TA
发私信
相关问题
1
如何在内核里跑gcov?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
开源共生 商业共赢 | RT-Thread 2024开发者大会议程正式发布!
2
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
3
RT-Thread EtherKit开源以太网硬件正式发布
4
如何在master上的BSP中添加配置yml文件
5
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
19
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
6
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
5
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部