库代码覆盖率

静态/共享库和DLL的代码覆盖率

在链接操作过程中,如果使用CoverageScanner编译共享库,则CoverageScanner将包括共享库的所有工具指令。CoverageBrowser在一个视图中显示完整应用程序(可执行文件及其库)的代码覆盖率。

注意:要分析库的代码覆盖率,必须编译主应用程序,并通过在命令行中添加--cs-exclude-file-abs-regex=.*等来排除其源代码,例如。

插件/手动加载的共享库的代码覆盖率

动态加载的库也可以进行工具化,但需要处理主应用程序或插件代码中执行报告的生成。

从主应用程序直接生成代码覆盖率信息

可以使用CoverageScanner API的注册/注销机制来处理主应用程序中的插件。在加载库后调用__coveragescanner_register_library(),在卸载之前调用__coveragescanner_unregister_library()

示例

*
    #include <stdio.h>
    #include <stdlib.h>
    #include <dlfcn.h>

    int
    main(int argc, char **argv)
    {
       void *handle;
       double (*cosine)(double);
       char *error;

       handle = dlopen("libm.so", RTLD_LAZY);
    #ifdef __COVERAGESCANNER__
       __coveragescanner_register_library("libm.so");
    #endif
       if (!handle) {
           fprintf(stderr, "%s\n", dlerror());
           exit(EXIT_FAILURE);
       }

       dlerror();    /* Clear any existing error */

       /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
          would seem more natural, but the C99 standard leaves
          casting from "void *" to a function pointer undefined.
          The assignment used below is the POSIX.1-2003 (Technical
          Corrigendum 1) workaround; see the Rationale for the
          POSIX specification of dlsym(). */

       *(void **) (&cosine) = dlsym(handle, "cos");

       if ((error = dlerror()) != NULL)  {
           fprintf(stderr, "%s\n", error);
           exit(EXIT_FAILURE);
       }

       printf("%f\n", (*cosine)(2.0));
    #ifdef __COVERAGESCANNER__
       __coveragescanner_unregister_library("libm.so");
    #endif
       dlclose(handle);
       exit(EXIT_SUCCESS);
    }

注意:可以在未进行工具化的库上调用__coveragescanner_register_library()__coveragescanner_unregister_library()

从插件直接生成代码覆盖率信息

CoverageScanner无法在链接阶段处理插件的工具化(即手动加载的共享库)。在这种情况下,库必须初始化并存储执行。因此,共享库需要在初始化时通过调用__coveragescanner_filename()设置执行文件名称,并在卸载时通过调用__coveragescanner_save()保存工具化。

使用Microsoft Visual Studio生成的插件代码覆盖率

当使用Microsoft® Visual Studio®生成的DLL初始化和终止时,会调用DllMain()函数。当reason字段等于DLL_PROCESS_ATTACH时,应调用函数__coveragescanner_filename()。当reason等于DLL_PROCESS_DETACH时,应在退出时调用函数__coveragescanner_save()以保存测量值。

示例

*
    extern "C"
    BOOL WINAPI DllMain(HINSTANCE hInstance,
                        DWORD dwReason,
                        LPVOID /*lpReserved*/)
    {
      switch( dwReason )
      {
        case DLL_PROCESS_ATTACH:
    #ifdef __COVERAGESCANNER__
        /* Initialization of the CoverageScanner library.        */
        /* Replace "mylib" with your filename without extension  */
        __coveragescanner_filename("mylib");
    #endif
          ...
        break;
        case DLL_PROCESS_DETACH:
          ...
    #ifdef __COVERAGESCANNER__
        /* Saves the execution report */
        __coveragescanner_save();
    #endif
        break;
      }
      return TRUE;
    }

使用GNU gcc生成的插件代码覆盖率

GNU编译器提供了两个属性,允许您在库加载或卸载时执行函数。

  • __attribute__ ((constructor)) my_init(void);:此属性指定当库加载时调用的函数。在库的自定义初始化函数中调用函数__coveragescanner_filename()
  • __attribute__ ((destructor)) my_fini(void);:此属性指定当库卸载时调用的函数。在库终止时调用函数__coveragescanner_save()

示例

*
    static void plugin_load(void)   __attribute__ ((constructor)) ;
    static void plugin_unload(void) __attribute__ ((destructor))  ;

    static void plugin_load(void)
    {
    #ifdef __COVERAGESCANNER__
      /* Initialization of the CoverageScanner library.        */
      /* Replace "mylib" with your filename without extension  */
      __coveragescanner_filename("mylib");
    #endif
        ...
    }

    static void plugin_unload(void)
    {
        ...
    #ifdef __COVERAGESCANNER__
      /* Saves the execution report */
      __coveragescanner_save();
    #endif
    }

Coco v7.2.0©2024 Qt公司有限公司。
Qt及其相关标志是Qt公司在芬兰以及/或其他国家的商标。所有其他商标均为其各自所有者的财产。