测量翻译为 C/C++ 的自定义编程语言文件的测试覆盖率?

发布于 2025-01-13 10:07:03 字数 799 浏览 2 评论 0原文

我有领域特定语言 (DSL) 的代码。这种语言中的文件被翻译成 C 源代码文件,然后由常用的编译器工具链 (GCC) 编译成二进制文件:

DSL file --> C file --> Object file --> binary file

我想测量用这种 DSL 编写的代码的测试覆盖率。该语言缺乏用于测量测试覆盖率的本机工具支持。不过,我可以使用传统的 GCC 工具(例如 gcov)和编译器的 --coverage 标志(或 Clang 等效项)来检测生成的二进制文件。然后可以使用覆盖信息对中间 C 表示进行注释。

DSL file --> C file --> Instrumented object file --> instrumented binary file --> coverage database
                ↕                                                                     |
         annotated C file <-----------------------------------------------------------+

问题是,中间 C 代码没有精确映射到其 DSL 输入:符号可能被重命名、方法可能会移动、添加和删除行等。

在心里来回映射源代码行是相当困难的。

有没有办法追溯收集到的覆盖范围信息,并将其与原始 DSL 代码关联起来?

I have code in a domain-specific language (DSL). Files in this language are translated into C source code files, which are then compiled into binaries by a usual compiler toolchain (GCC):

DSL file --> C file --> Object file --> binary file

I want to measure test coverage for code written in this DSL. The language lacks native tooling support for measuring test coverage. However, I can use traditional GCC tools such as gcov and compiler's --coverage flags (or Clang equivalents) to instrument the generated binaries. The intermediate C-representation can then be annotated with coverage information.

DSL file --> C file --> Instrumented object file --> instrumented binary file --> coverage database
                ↕                                                                     |
         annotated C file <-----------------------------------------------------------+

The problem is, the intermediate C-code does not precisely map to its DSL input: symbols may be renamed, methods moved around, lines added and removed etc.

It is quite hard to mentally map the source code lines back and forth.

Is there a way to trace back collected coverage information to associate it with the original DSL code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

知你几分 2025-01-20 10:07:03

事实证明,gcovr(我假设它包装的 gcov 也能做到这一点)理解#line预处理器指令。该指令通知后面的代码行应被视为来自不同名称的源文件并放置在不同的行号处。

因此,只要我的 DSL 到 C 转换器能够使用 #line 注释生成的代码,如下所示,覆盖率工具就能够将覆盖率数据库与原始 DSL 代码关联起来:

#line 3248 "foo-controller-dsl.c"
/* get_allowed_deadline */
static uint64 _dsl_M_get_allowed_deadline(foo_controller_t *_dev, obj_t *cpu)
#line 179 "/src/foo-controller/foo-controller.dsl"
{
    #line 180 "/src/foo-controller/foo-controller.dsl"
    uint64 v618_baz_freq  = _dsl_M_ctr_storage__get_ref_freq(_dev);
    #line 181 "/src/foo-controller/foo-controller.dsl"
    double v618_threshold_seconds  = _dsl_M_get_threshold_in_seconds(_dev, cpu);
    #line 182 "/src/foo-controller/foo-controller.dsl"
    double v618_threshold_baz_units  = v618_threshold_seconds * (double )v618_baz_freq;
    #line 184 "/src/foo-controller/foo-controller.dsl"
    double v618_baz_counter  = _dsl_M_ctr_storage__get_ctr(_dev);
    #line 185 "/src/foo-controller/foo-controller.dsl"
    double v618_allowed_deadline  = v618_baz_counter + v618_threshold_baz_units;
    #line 187 "/src/foo-controller/foo-controller.dsl"
    return (uint64 )((int64 )v618_allowed_deadline);
    #line 188 "/src/foo-controller/foo-controller.dsl"
}

It turns out that gcovr (and I assume gcov which it wraps does it as well) understands #line preprocessor directives. This directive informs that code lines following it should be treated as if they came from a differently named source file and were placed at different line number.

So as long as my DSL-to-C translator is capable to annotate the generated code with #lines as shown below, the coverage tools are capable of associating the coverage database with the original DSL code:

#line 3248 "foo-controller-dsl.c"
/* get_allowed_deadline */
static uint64 _dsl_M_get_allowed_deadline(foo_controller_t *_dev, obj_t *cpu)
#line 179 "/src/foo-controller/foo-controller.dsl"
{
    #line 180 "/src/foo-controller/foo-controller.dsl"
    uint64 v618_baz_freq  = _dsl_M_ctr_storage__get_ref_freq(_dev);
    #line 181 "/src/foo-controller/foo-controller.dsl"
    double v618_threshold_seconds  = _dsl_M_get_threshold_in_seconds(_dev, cpu);
    #line 182 "/src/foo-controller/foo-controller.dsl"
    double v618_threshold_baz_units  = v618_threshold_seconds * (double )v618_baz_freq;
    #line 184 "/src/foo-controller/foo-controller.dsl"
    double v618_baz_counter  = _dsl_M_ctr_storage__get_ctr(_dev);
    #line 185 "/src/foo-controller/foo-controller.dsl"
    double v618_allowed_deadline  = v618_baz_counter + v618_threshold_baz_units;
    #line 187 "/src/foo-controller/foo-controller.dsl"
    return (uint64 )((int64 )v618_allowed_deadline);
    #line 188 "/src/foo-controller/foo-controller.dsl"
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文