构建自动化系统的支持

Make及其变体

Coco还可以在不修改项目的情况下为项目生成代码覆盖率信息。原理是将CoverageScanner编译器包装器的路径添加到PATH变量,并使用COVERAGESCANNER_ARGS环境变量设置仪表化参数。要激活仪表化,COVERAGESCANNER_ARGS中必须有--cs-on。如果没有这种情况,CoverageScanner将完全禁用。

注意:变量COVERAGESCANNER_ARGS应该只在本地设置,例如在脚本或命令行中。如果全局设置,它将影响每个构建。

GNU Make

在UNIX®系统上,按照以下步骤使用GNU Make生成项目进行配置

export PATH=/opt/SquishCoco/wrapper/bin:$PATH
export COVERAGESCANNER_ARGS=--cs-on
make clean
make

对于macOS,将第一行替换为

export PATH=/opt/SquishCoco/wrapper:$PATH

Microsoft NMake

要使用NMake生成的项目进行配置

set PATH=%SQUISHCOCO%\visualstudio;%PATH%
set COVERAGESCANNER_ARGS=--cs-on
nmake clean
nmake

Microsoft MSBuild

要对使用MSBuild生成的项目进行配置

set PATH=%SQUISHCOCO%\visualstudio;%PATH%
set COVERAGESCANNER_ARGS=--cs-on
msbuild /p:UseEnv=true myproject.sln /t:ReBuild

CMake

CMake是从Kitware提供的跨平台构建工具。

使用预加载脚本的仪表化

以下方法在所有简单情况下应能用于设置CMake项目的代码覆盖率。

存在一个通用文件,例如squishcoco.cmake,和特定设置文件(例如squishcoco-gcc.cmake),该文件指定编译器。然后使用类似于以下命令行配置项目时包含设置文件

cmake <other options> -Csquishcoco-gcc.cmake

然后,项目针对代码覆盖率进行配置。

如果缺少编译器的设置文件,可以通过修改现有文件之一来创建它。

squishcoco.cmake文件

请将以下文件保存为 "squishcoco.cmake" 在您的源代码根目录。更改第一行,以便包含您需要的选项。选项列表必须是一个带有空格分隔的引号字符串。如果没有选项,则启用覆盖率。

此文件不能单独使用(除Qt Creator外),必须从编译器设置文件中包含(见下文)。

set(coverage_flags "--cs-mcdc --cs-no-assignments") // Set your own options

foreach(var IN ITEMS CMAKE_C_COMPILER CMAKE_CXX_COMPILER)
    if(NOT DEFINED ${var})
        message(FATAL_ERROR "Variable ${var} must be defined.")
    endif()
endforeach()

set(CMAKE_C_FLAGS_INIT "${coverage_flags}"
    CACHE STRING "Coverage flags for the C compiler." FORCE)
set(CMAKE_CXX_FLAGS_INIT "${coverage_flags}"
    CACHE STRING "Coverage flags for the C++ compiler." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_INIT "${coverage_flags}"
    CACHE STRING "Coverage flags for the linker." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_INIT "${coverage_flags}"
    CACHE STRING "Coverage flags to link shared libraries." FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_INIT "${coverage_flags}"
    CACHE STRING "Coverage flags to link static libraries." FORCE)

if (DEFINED ENV{SQUISHCOCO})
    set(cocopath $ENV{SQUISHCOCO})
else()
    find_file(cocopath SquishCoco
      PATHS "$ENV{HOME}" /opt/ "/Applications"
      REQUIRED
      NO_DEFAULT_PATH
    )
endif()

if(CMAKE_HOST_APPLE)
    set(wrapperdir "${cocopath}/")
elseif(CMAKE_HOST_UNIX)
    set(wrapperdir "${cocopath}/bin/")
elseif(MINGW)
    set(wrapperdir "${cocopath}\\bin\\")
else()
    set(wrapperdir "${cocopath}\\" )
endif()

get_filename_component(c_compiler ${CMAKE_C_COMPILER} NAME)
find_program(code_coverage_c_compiler cs${c_compiler}
    PATHS ${wrapperdir}
    NO_DEFAULT_PATH)
set(CMAKE_C_COMPILER "${code_coverage_c_compiler}"
    CACHE FILEPATH "CoverageScanner wrapper for C compiler" FORCE)

get_filename_component(cxx_compiler ${CMAKE_CXX_COMPILER} NAME)
find_program(code_coverage_cxx_compiler cs${cxx_compiler}
    PATHS ${wrapperdir}
    NO_DEFAULT_PATH)
set(CMAKE_CXX_COMPILER "${code_coverage_cxx_compiler}"
    CACHE FILEPATH "CoverageScanner wrapper for C++ compiler" FORCE)

if(DEFINED CMAKE_LINKER)
    get_filename_component(linker_prog ${CMAKE_LINKER} NAME)
    find_program(code_coverage_linker cs${linker_prog}
        PATHS ${wrapperdir}
        NO_DEFAULT_PATH)
    set(CMAKE_LINKER "${code_coverage_linker}"
        CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE)
elseif(${c_compiler} STREQUAL "cl.exe") # special case for Visual Studio
    find_program(code_coverage_linker "cslink.exe"
        PATHS ${wrapperdir}
        NO_DEFAULT_PATH)
    set(CMAKE_LINKER "${code_coverage_linker}"
        CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE)
endif()

if(DEFINED CMAKE_AR)
    get_filename_component(ar_prog ${CMAKE_AR} NAME)
    find_program(code_coverage_ar cs${ar_prog}
        PATHS ${wrapperdir}
        NO_DEFAULT_PATH)
    set(CMAKE_AR "${code_coverage_ar}"
        CACHE FILEPATH "CoverageScanner wrapper for ar" FORCE)
endif()

mark_as_advanced(
  cocopath
  code_coverage_c_compiler code_coverage_cxx_compiler code_coverage_linker code_coverage_ar
)

文件 squishcoco-gcc.cmake

此文件需要用于使用 GCC 的事前编译。它必须与 squishcoco.cmake 在同一目录下。

set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_AR ar)
set(CMAKE_LINKER gcc)

include(squishcoco.cmake)

文件 squishcoco-clang.cmake

此文件需要用于使用 Clang 的事前编译。它必须与 squishcoco.cmake 在同一目录下。

set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_AR ar)
set(CMAKE_LINKER clang)

include(squishcoco.cmake)

文件 squishcoco-visualstudio.cmake

此文件需要用于使用微软 Visual C/C++ 的事前编译。它必须与 squishcoco.cmake 在同一目录下。

set(CMAKE_C_COMPILER cl)
set(CMAKE_CXX_COMPILER cl)
set(CMAKE_LINKER link)

include(squishcoco.cmake)
Windows 下的误导性 CMake 输出

至少在版本 3.20 以及在 Windows 下运行时,CMake 会有误导性的输出

C:\cmake -C\somepath\squishcoco-visualstudio.cmake
-- Building for: Visual Studio 16 2019
-- Selecting Windows SDK version 10.0.22621.0 to target Windows 10.0.22631.
-- The C compiler identification is MSVC 19.29.30154.0
-- The CXX compiler identification is MSVC 19.29.30154.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done

该输出表明项目仍在使用原始编译器(cl.exe),而不是包装器,但事实并非如此:配置了 squishcoco-visualstudio.cmake 的项目实际上生成了仪器化代码。

当您对项目是否使用 Coco 编译存疑时,查看 CMakeCache.txt。如果它包含此类行,

//CoverageScanner wrapper for C++ compiler
CMAKE_CXX_COMPILER:FILEPATH=C:/Program Files/squishcoco/cscl.exe

则表示使用了 Coco 包装器并启用了仪器化。

创建自己的设置文件

通过这些示例,应能够轻松自定义其他编译器的设置文件。只需设置所使用的程序名称,而不是它们的完整路径。变量 CMAKE_AR 仅用于 GCC 类型的编译器,如 GCC、Clang 或许多用于交叉编译的编译器。

使用工具链文件进行仪器化

注意: 这是一个较旧的方法,只有在没有使用工具链文件的情况下才有效。为了应对仍然需要这种情况,将其保留在文档中。

当 Coco 与 CMake 一起使用时,变更部分取决于用于编译的工具链。我们首先描述添加新构建类型的方法,该类型与工具链无关,然后介绍针对微软® Visual Studio® 和 GNU GCC 的附加变更。

为仪器化编译添加新的构建类型

第一步与所使用的工具链无关。其目的是声明用于指定仪器化编译的 CMake 变量。在 CMake 中,这是通过声明一个 构建类型 来实现的,我们在这里将其称为 COVERAGE

为此,将以下行添加到 CMakeLists.txt 文件中。第一行中的变量 COVERAGE_FLAGS 指定了 CoverageScanner 命令行选项。将其值更改为符合您的要求。只有 --cs-on 必须始终存在。

SET(COVERAGE_FLAGS "--cs-on --cs-count")
SET(CMAKE_CXX_FLAGS_COVERAGE
    "${CMAKE_CXX_FLAGS_RELEASE} ${COVERAGE_FLAGS}" CACHE STRING
    "Flags used by the C++ compiler during coverage builds."
    FORCE )
SET(CMAKE_C_FLAGS_COVERAGE
    "${CMAKE_C_FLAGS_RELEASE} ${COVERAGE_FLAGS}" CACHE STRING
    "Flags used by the C compiler during coverage builds."
    FORCE )
SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
    "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${COVERAGE_FLAGS}" CACHE STRING
    "Flags used for linking binaries during coverage builds."
    FORCE )
SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
    "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${COVERAGE_FLAGS}" CACHE STRING
    "Flags used by the shared libraries linker during coverage builds."
    FORCE )
SET( CMAKE_STATIC_LINKER_FLAGS_COVERAGE
    "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} ${COVERAGE_FLAGS}" CACHE STRING
    "Flags used by the static libraries linker during coverage builds."
    FORCE )
MARK_AS_ADVANCED(
    CMAKE_CXX_FLAGS_COVERAGE
    CMAKE_C_FLAGS_COVERAGE
    CMAKE_EXE_LINKER_FLAGS_COVERAGE
    CMAKE_SHARED_LINKER_FLAGS_COVERAGE
    CMAKE_STATIC_LINKER_FLAGS_COVERAGE
    COMPILE_DEFINITIONS_COVERAGE
)

这些命令将 Release 构建类型的编译器和链接器标志添加到其中。如果您想使用其他构建类型的标志,请将此代码中的后缀 _RELEASE 替换为另一个构建类型的名称,例如 _DEBUG

Microsoft Visual Studio

在 Visual Studio 中,我们需要将新的 Coverage 构建类型设置为对 IDE 可见。为此,我们向基于您发布配置的 CMakeSettings.json 中的 configurations 列表添加一个项目。

{
"configurations": [
     "_comment" : "other configurations here... ",
      {
        "name": "CodeCoverage-x64-Release",
        "generator": "Ninja",
        "configurationType": "Release",
        "buildRoot": "${projectDir}\\out\\build\\${name}",
        "installRoot": "${projectDir}\\out\\install\\${name}",
        "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=cl.cmake -DCMAKE_BUILD_TYPE=COVERAGE",
        "buildCommandArgs": "",
        "ctestCommandArgs": "",
        "inheritEnvironments": [ "msvc_x64_x64" ],
        "variables": []
      }
   ]
}

这里的重要细节是 cmakeCommandArgs,它告诉 cmake 使用 cl.cmake 工具链文件,并使用 COVERAGE 构建类型。其他参数/变量可以复制或根据另一个工作配置进行自定义。

使用 Microsoft NMake 进行编译

在用 NMake 编译的项目中

  1. 创建一个工具链定义文件 cl.cmake,用于替换编译器和链接器,用它们的 CoverageScanner 包装器代替。

    例如

    # this one is important
    SET(CMAKE_SYSTEM_NAME Windows)
    
    # specify the cross compiler
    FILE(TO_CMAKE_PATH "$ENV{SQUISHCOCO}/visualstudio" SQUISHCOCO)
    SET(CMAKE_C_COMPILER ${SQUISHCOCO}/cl.exe
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
    SET(CMAKE_CXX_COMPILER ${SQUISHCOCO}/cl.exe
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
    SET(CMAKE_LINKER ${SQUISHCOCO}/link.exe
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
  2. 创建一个 Makefile 项目。将工具链设置为 CoverageScanner 包装器,并将构建模式设置为 COVERAGE

    例如

    cmake.exe -DCMAKE_TOOLCHAIN_FILE=cl.cmake -DCMAKE_BUILD_TYPE=COVERAGE \
              -G "NMake Makefiles" <i>path of cmake project</i>
  3. 使用 nmake 构建项目。

使用 GNU GCC 进行编译

以下操作必须在用 gcc 编译的项目中执行

  1. 创建一个工具链定义文件 gcc.cmake,用它们的 CoverageScanner 包装器替换编译器和链接器。

    例如

    find_program(CODE_COVERAGE_GCC gcc
        PATHS /opt/SquishCoco/wrapper/bin "$ENV{HOME}/SquishCoco/wrapper/bin"
        NO_DEFAULT_PATH )
    find_program(CODE_COVERAGE_GXX g++
        PATHS /opt/SquishCoco/wrapper/bin "$ENV{HOME}/SquishCoco/wrapper/bin"
        NO_DEFAULT_PATH )
    find_program(CODE_COVERAGE_AR ar
        PATHS /opt/SquishCoco/wrapper/bin "$ENV{HOME}/SquishCoco/wrapper/bin"
        NO_DEFAULT_PATH )
    
    # specify the cross compiler
    SET(CMAKE_C_COMPILER "${CODE_COVERAGE_GCC}"
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
    SET(CMAKE_CXX_COMPILER "${CODE_COVERAGE_GXX}"
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
    SET(CMAKE_LINKER "${CODE_COVERAGE_GXX}"
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
    SET(CMAKE_AR "${CODE_COVERAGE_AR}"
        CACHE FILEPATH "CoverageScanner wrapper" FORCE)
  2. 创建一个 Makefile 项目。将工具链设置为 CoverageScanner 包装器,并将构建模式设置为 COVERAGE

    例如

    cmake -DCMAKE_TOOLCHAIN_FILE=gcc.cmake -DCMAKE_BUILD_TYPE=COVERAGE \
          -G "Unix Makefiles" <i>path of cmake project</i>
  3. 使用 make 构建项目。

Qt 框架

注意:较新的 Qt 版本也支持 CMake 作为其构建系统。CMake 章节中的说明也适用于 Qt 项目。

qmake

qmake 是一个工具,Qt 通过使用所谓的 项目文件 以平台无关的方式生成 makefile。它也被 Qt Creator 使用。

默认情况下,qmake 选择用于编译的程序。我们可以通过将一些声明放入 qmake 项目文件来使用 Coco 包装器。这可以通过将一些声明放入 qmake 项目文件来完成。由于需要以带有和不带覆盖率的方式来构建项目,所以新的定义必须放在一个作用域中。作用域是指可以在需要时激活的 qmake 项目文件中的一个区域。

以下列表显示了一个名为 CoverageScanner 的作用域模板,这对于大多数项目通常足够。

CodeCoverage {
  COVERAGE_OPTIONS =

  QMAKE_CFLAGS   += $$COVERAGE_OPTIONS
  QMAKE_CXXFLAGS += $$COVERAGE_OPTIONS
  QMAKE_LFLAGS   += $$COVERAGE_OPTIONS

  QMAKE_CC=cs$$QMAKE_CC
  QMAKE_CXX=cs$$QMAKE_CXX
  QMAKE_LINK=cs$$QMAKE_LINK
  QMAKE_LINK_SHLIB=cs$$QMAKE_LINK_SHLIB
  QMAKE_AR=cs$$QMAKE_AR
  QMAKE_LIB=cs$$QMAKE_LIB
}

我们在这里还设置了变量 QMAKE_LINK_SHLIBQMAKE_AR,它们包含链接共享库和生成归档的命令。此外,您可以使用 COVERAGE_OPTIONS 来设置 coveragescanner 命令行选项(请参阅 选项列表)以自定义项目。空值 COVERAGE_OPTIONS 也可以使用,并会导致默认的探测。

在小型项目中,将 CodeCoverage 作用域复制到所有的配置文件中,即以 .pro 结尾的文件。实际上,只需将这些插入到真正编译代码的文件中,而不是只包含其他文件的文件即可。如果项目较大,它通常有一个包含所有配置的常见设置的文件,然后这就是唯一一次插入 CodeCoverage 作用域的最方便的地方。

默认情况下,新的探测作用域是禁用的。要在构建的项目中启用代码覆盖率,只需在用 qmake 配置时将作用域的名称添加到 CONFIG 变量中即可

$ qmake CONFIG+=CodeCoverage

moc

元对象编译器(moc)为从QObject派生的每个类生成一些方法。例如,翻译函数tr,所有信号的开源代码,类型转换操作符qt_cast……为了使用Qt框架对代码进行插桩而不是moc生成的代码,CoverageScanner提供了命令行选项--cs-qt3用于Qt3和--cs-qt4用于Qt4至Qt6。它们默认启用。

在这种情况下

  • Q_OBJECT宏不再进行插桩。
  • 所有信号都会进行插桩,以跟踪它们的发送。
  • 用于信号/槽机制的粘合代码不会进行插桩。
  • 在Qt4中,Q_FOREACH宏的代码不会进行插桩。

qbs

要将Coco与Qt构建套件(qbs)一起使用,请将其设置为一个工具链。然后,您可以使用此工具链为所有qbs项目。

要将Coco设置为一个工具链,请执行以下命令

qbs setup-toolchains --type gcc /opt/SquishCoco/bin/csgcc csgcc

对于基于Unix的操作系统,需要一些额外的配置步骤

qbs config profiles.csgcc.cpp.archiverPath /opt/SquishCoco/bin/csar
qbs config profiles.csgcc.cpp.linkerName csg++
qbs config profiles.csgcc.cpp.nmPath /opt/SquishCoco/bin/csgcc-nm

然后,csgcc工具链也可以用作Qt项目的基准配置文件

qbs setup-qt /opt/Qt/bin/qmake qt-csgcc
qbs config profiles.qt-csgcc.baseProfile csgcc

SCons

要使用Coco与SCons

  1. 将Coco的包装器(csgcccscl等)的路径添加到PATH环境变量。PATH环境变量应设置为能够执行Coco包装器。
  2. CCARLINK变量设置为相应的Coco包装器。例如:当使用Microsoft Visual Studio编译器时,将CC设置为cscl.exe,将LINK设置为cslink.exe,将AR设置为cslib.exe

    注意:不要使用到编译器包装器的绝对文件路径,因为某些版本的SCons不能正确处理文件名中的空格。

  3. 将代码覆盖率设置添加到变量CCFLAGSARFLAGSLINKFLAGS中,以排除插桩示例文件。

以下是一个可用于Visual Studio命令行工具的代码片段

import os
from os.path import pathsep

env = Environment()

# Add the path of Squish Coco compiler wrapper
env[ 'ENV' ][ 'PATH' ] = os.environ[ 'SQUISHCOCO' ] + pathsep + env[ 'ENV' ][ 'PATH' ]
# TEMP variable need to be defined
env[ 'ENV' ][ 'TEMP' ] = os.environ[ 'TEMP' ]
env[ 'ENV' ][ 'INCLUDE' ] = os.environ[ 'INCLUDE' ]

# Set the compiler to Squish Coco wrappers
env[ 'CC' ]   = 'cs' + env[ 'CC' ] ;
env[ 'AR' ]   = 'cs' + env[ 'AR' ] ;
env[ 'LINK' ] = 'cs' + env[ 'LINK' ] ;

# Code coverage settings
coverageflags = [ '--cs-count' ]
env[ 'CCFLAGS' ]   = env[ 'CCFLAGS' ] + coverageflags ;
env[ 'ARFLAGS' ]   = env[ 'ARFLAGS' ] + coverageflags ;
env[ 'LINKFLAGS' ] = env[ 'LINKFLAGS' ] + coverageflags ;

要正确设置构建环境,您必须从Visual Studio的开发者提示(通过开始菜单可用)或构建环境选择提供的Coco控制台开始构建。

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