【学习笔记】Mastering CMake (十六)—— CDash

前言:

学习笔记,随时更新。如有谬误,欢迎指正。


说明:

  1. 红色字体为较为重要部分。
  2. 绿色字体为个人理解部分。

16 CDash

随着项目测试需求的增长,跟踪测试结果可能变得难以应对。对于每晚在许多不同平台上进行测试的项目来说,情况尤其如此。在这些情况下,我们建议使用测试指示板来总结测试结果。

测试指示板总结了许多平台上许多测试的结果,它的超链接允许人们快速深入到更多的细节级别。 CTest 可执行文件包括对生成测试指示板的支持。当使用正确的选项运行时, CTest 将生成基于 XML 的输出,记录构建和测试结果,并将它们发布到指示板服务器。指示板服务器运行一个名为 CDash 的开源软件包。 CDash 收集 XML 结果并从中生成 HTML 网页。

在讨论如何使用 CTest 生成指示板之前,让我们考虑一下测试指示板的主要部分。每天晚上在指定的时间,指示板服务器将打开一个新的指示板,这样每天都有一个新的网页显示这 24 小时期间的测试结果。主页上有一些链接,可以让你快速浏览不同的日期。查看项目的主页(例如 www.cmake.org 上的 CMake 指示板),你将看到它被划分为几个主要组件。在靠近顶部的地方,你会发现一组链接,允许你转到以前的指示板,以及到项目页面的链接,如 bug 跟踪器、文档等。

在那下面,你会发现结果组。典型的组包括夜间测试( Nightly )、实验性( Experimental )、持续性( Continuous )、覆盖范围( Coverage )和动态分析( Dynamic Analysis )。指示板项放入的类别取决于它是如何生成的。最简单的是 Experimental 项,它表示某人当前项目源代码副本的指示板结果。对于 Experimental 指示板,源代码不能保证是最新的。相反,在 Nightly 指示板项中, CTest 试图将源代码更新到特定的日期和时间。我们的期望是,指定日期的所有 Nightly 指示板项都应该基于相同的源代码。

Continuous 指示板项被设计为在每次签入新文件时运行。根据一天中检查新文件的频率,指示板可能有许多的 Continuous 项。 Continuous 指示板对于可能只在某些平台上出现问题的跨平台项目尤其有用。在这种情况下,开发人员可以提交在他们的平台上适用的更改,然后另一个平台运行持续构建将可以捕获错误,这让开发人员能及时纠正问题。

Dynamic Analysis 和 Coverage 指示板被设计用来测试项目的内存安全和代码覆盖范围。Dynamic Analysis 指示板项是在启用内存访问/泄漏检查程序的情况下运行所有测试的项。任何产生的错误或警告都会被解析、总结并显示出来。这对于验证你的软件是否有泄漏内存或是都从未初始化的内存中读取是很重要的。 Coverage 指示板项是类似的,因为所有的测试都被运行,但是所有测试被执行的代码行被跟踪。运行完所有测试后,将生成每一行代码执行次数的列表,并显示在指示板上。

16.1 向项目增加 CDash 指示板支持

开始使用 CDash 的最简单方法是在 https://my.cdash.org 上注册一个帐户并创建一个新项目。

如果你希望安装自己的 CDash 服务器,请遵循以下指导之一:

-------下面一段是老版本的文档中关于 CDash 配置文件的说明-------

在 CDash 服务器填完创建项目所需的必要信息后,你可以点击“创建项目”来在 CDash 中创建项目。在这个时候服务器做好了接受指示板提交的准备。接下来的步骤是向你的软件项目提供指示板服务器信息。这个信息保存在你的源码树的顶层的名为 CTestConfig.cmake 的文件中。你可以通过点击你指示板上的“编辑项目”按钮来下载这个文件(图标看起来像饼状图下面有个扳手),然后点击杂项选项卡并选择“下载 CTestConfig ”,并在你的源码树中保存 CTestConfig.cmake 。

16.2 客户端设置

为了在你的项目中支持指示板,你需要如下所示包含 CTest 模块。

# 包含 CDash 指示板测试模块
include(CTest)

然后 CTest 模块将从你创建的、或者从CDash下载的 CTestConfig.cmake 文件中读取设置。如果你已经在你的项目中添加了 add_test 命令调用,创建一个指示板项就像运行如下命令一样简单:

ctest -D Experimental

-D 选项告诉 CTest 创建一个指示板项。下一个参数指示要创建的指示板项的类型。创建指示板项涉及许多步骤,这些步骤可以独立运行,也可以作为一个命令运行。在本例中, Experimental 参数将导致 CTest 作为一个命令执行许多不同的步骤。下面总结了创建指示板项的不同步骤。

Start

  • 准备一个新的指示板项。这将在构建目录中创建一个 Testing 子目录。 Testing 子目录将包含一个用于(存放)指示板结果的子目录,其名称与指示板时间相对应。 Testing 子目录还将包含一个名为 Temporary 的(存放)临时测试结果的子目录。

Update

  • 执行源代码的源代码控制更新(通常用于 Nightly 或 Contunious 运行)。目前 CTest 支持 Concurrent Versions System (CVS) 、 Subversion 、 Git 、 Mercurial 和 Bazaar 。

Configure

  • 在项目上运行 CMake 以确保 Makefiles 或项目文件是最新的。

Build

  • 使用指定的生成器构建软件。

Test

  • 运行所有测试并记录结果。

MemoryCheck

  • 使用 Purify 或 valgrind 执行内存检查。

Coverage

  • 使用 gcov 或 Bullseye 收集源代码覆盖范围信息。

Submit

  • 将测试结果作为指示板条项交到服务器。

这些步骤中的每一个都可以使用以下语法为 Nightly 或 Experimental 项来独立运行:

ctest -D NightlyStart
ctest -D NightlyBuild
ctest -D NightlyCoverage -D NightlySubmit

ctest -D ExperimentalStart
ctest -D ExperimentalConfigure
ctest -D ExperimentalCoverage -D ExperimentalSubmit

或者,你可以使用快捷方式一次性执行最常见的组合。 CTest 定义的快捷方式包括:

ctest -D Experimental

  • 执行 start 、 configure 、 build 、 test 、 coverage 和 submit 。

ctest -D Nightly

  • 执行 start 、 update 、 configure 、 build 、 test 、 coverage 和 submit 。

ctest -D Continuous

  • 执行 start 、 update 、 configure 、 build 、 test 、 coverage 和 submit 。

ctest -D MemoryCheck

  • 执行 start 、 configure 、 build 、 memorycheck 、 coverage 和 submit 。

当第一次设置指示板时,将 -D 选项与 -V 选项结合起来通常是很有用的。这将允许你查看指示板流程的所有不同阶段的输出。同样, CTest 在它在二进制树中创建的 Testing/Temporary 目录中维护了日志文件。在那里,你将找到指示板运行的最近的日志文件。指示板结果( XML 文件)也存储在 Testing 目录中。

16.3 为项目定制指示板

CTest 有一些选项可以用来控制它如何处理项目。当 CTest 运行一个指示板时,它会在二进制树中找到 CTestCustom.ctest 文件,它将加载这些文件并使用其中的设置来控制其行为。 CTestCustom 文件的语法与常规的 CMake 语法相同。也就是说,这个文件中通常只使用 set 命令。这些命令指定 CTest 在执行测试时将考虑的属性。

16.3.1 指示板提交设置

从 CDash 下载的文件中提供了许多基本的指示板设置。如果你愿意,可以编辑这些初始值并提供附加值。设置的第一个值是 Nightly 的开始时间。这是世界各地的指示板用来签出 Nightly 源代码副本的时间。这个时间还将控制如何将指示板提交分组在一起。从晚上开始时间到下一个晚上开始时间的所有提交都将包括在同一“天”。

# 指示板从指定的 NIGHTLY_START_TIME 开始开放 24 小时,在这期间可以提交代码。时间以 24 小时的格式指定。
set (CTEST_NIGHTLY_START_TIME "01:00:00 UTC")

下一组设置控制提交测试结果的位置。这是 CDash 服务器的位置。

# 用于提交结果的 CDash 服务器(由客户端使用)
set (CTEST_DROP_METHOD http)
set (CTEST_DROP_SITE "my.cdash.org")
set (CTEST_DROP_LOCATION "/submit.php?project=KensTest")
set (CTEST_DROP_SITE_CDASH TRUE)

CTEST_DROP_SITE 指定 CDash 服务器的位置。 CDash 客户端生成的构建和测试结果被发送到此位置。 CTEST_DROP_LOCATION 是 CDash 客户端保存构建和测试报告的服务器上的目录或HTTP URL。 CTEST_DROP_SITE_CDASH 指定当前服务器是 CDash ,这防止 CTest 尝试“触发”提交(如果该变量没有设置为允许向后兼容 Dart 和 Dart 2 ,则仍然会执行此操作)。

目前 CDash 只支持 HTTP 的 drop 提交方式,但是 CTest 支持其他提交类型。 CTEST_DROP_METHOD 指定用于提交测试结果的方式。对此最常见的设置是 HTTP ,它使用超文本传输协议( HTTP )将测试数据传输到服务器。对于 FTP 和 SCP 等特殊情况,支也持其他 drop 方式。在下面的例子中,使用 HTTP 协议提交结果的客户端使用一个 web 地址作为 drop 站点。如果通过 FTP 提交,则此位置相对于 CTEST_DROP_SITE_USER 在默认情况下登录的位置。 CTEST_DROP_SITE_USER 指定客户端将在服务器上使用的 FTP 用户名。对于 FTP 提交,这个用户通常是“匿名的”。但是,可以使用与服务器通信的任何用户名。对于需要密码的 FTP 服务器,密码可以存储在 CTEST_DROP_SITE_PASSWORD 变量中。 CTEST_DROP_SITE_MODE (在本例中没有使用)是一个可选变量,你可以使用它指定 FTP 模式。大多数 FTP 服务器将处理默认的被动模式,但是如果你的服务器不会这样做,你可以显式地将该模式设置为主动模式。

CTest 也可以在防火墙后面运行。如果防火墙允许 FTP 或 HTTP 流量,则不需要进行其他设置。当防火墙需要使用 FTP/HTTP 代理,或者使用 SOCKS4 、 SOCKS5 类型的代理时,需要设置一些环境变量。 HTTP_PROXY 和 FTP_PROXY 指定服务 HTTP 和 FTP 代理请求的服务器。 HTTP_PROXY_PORT 和 FTP_PROXY_PORT 指定 HTTP 和 FTP 代理所在的端口。 HTTP_PROXY_TYPE 指定使用的 HTTP 代理的类型。默认情况下支持的三种不同类型的代理,其中包括一个通用的 HTTP/FTP 代理、“ SOCKS4 ”、以及“ SOCKS5 ”,它们指定了 SOCKS4 和 SOCKS5 兼容的代理。

16.3.2 过滤错误和警告

默认情况下, CTest 有一个正则表达式列表,用于从构建过程的输出中查找错误和警告。你可以使用如下所示的几个变量在 CTestCustom.ctest 文件中覆盖这些设置。

set (CTEST_CUSTOM_WARNING_MATCH
  ${CTEST_CUSTOM_WARNING_MATCH}
  "{standard input}:[0-9][0-9]*: Warning: "
  )

set (CTEST_CUSTOM_WARNING_EXCEPTION
  ${CTEST_CUSTOM_WARNING_EXCEPTION}
  "tk8.4.5/[^/]+/[^/]+.c[:\"]"
  "xtree.[0-9]+. : warning C4702: unreachable code"
  "warning LNK4221"
  "variable .var_args[2]*. is used before its value is set"
  "jobserver unavailable"
  )

CTestCustom 文件的另一个有用特性是,你可以使用它来限制为内存检查指示板运行的测试。使用 purify 或 valgrind 进行内存检查是一个 CPU 密集型的过程,对于通常只需要 1 小时的指示板来说可能需要 20 个小时。为了帮助缓解这个问题, CTest 允许你从内存检查过程中排除一些测试,如下所示:

set (CTEST_CUSTOM_MEMCHECK_IGNORE
     ${CTEST_CUSTOM_MEMCHECK_IGNORE}
  TestSetGet
  otherPrint-ParaView
  Example-vtkLocal
  Example-vtkMy
  )

排除测试的格式只是一个列表,该列表是在使用 add_test 将测试添加到 CMakeLists 文件时指定的测试名称。

除了演示的设置,例如 CTEST_CUSTOM_WARNING_MATCH 、 CTEST_CUSTOM_WARNING_EXCEPTION 和 CTEST_CUSTOM_MEMCHECK_IGNORE , CTest 还检查其他几个变量。

CTEST_CUSTOM_ERROR_MATCH

  • 将构建行视为错误行的附加正则表达式。

CTEST_CUSTOM_ERROR_EXCEPTION

  • 不将构建行视为错误行的附加正则表达式。

CTEST_CUSTOM_WARNING_MATCH

  • 将构建行视为警告行的附加正则表达式。

CTEST_CUSTOM_WARNING_EXCEPTION

  • 不将构建行视为警告行的附加正则表达式。

CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS

  • CTest 停止报告错误之前的最大错误数(默认 50 )。

CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS

  • CTest 停止报告警告前的最大警告数(默认 50 )。

CTEST_CUSTOM_COVERAGE_EXCLUDE

  • 要从覆盖范围分析中排除的文件的正则表达式。

CTEST_CUSTOM_PRE_MEMCHECK

  • 执行内存检查前要执行的命令列表。

CTEST_CUSTOM_POST_MEMCHECK

  • 执行内存检查后要执行的命令列表。

CTEST_CUSTOM_MEMCHECK_IGNORE

  • 要从内存检查步骤中排除的测试列表。

CTEST_CUSTOM_PRE_TEST

  • 执行测试前要执行的命令列表。

CTEST_CUSTOM_POST_TEST

  • 执行测试后要执行的命令列表。

CTEST_CUSTOM_TESTS_IGNORE

  • 要从测试步骤中排除的测试列表。

CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE

  • 通过的测试的最大测试输出大小(默认 1k )。

CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE

  • 失败测试的最大测试输出大小(默认 300k )。

在 CTEST_CUSTOM_PRE_TEST 和 CTEST_CUSTOM_POST_TEST 中指定的命令,以及等效的内存检查命令,在每次 CTest 运行时执行一次。例如,如果所有测试都需要进行一些初始设置和执行一些最后的清理,那么可以使用这些命令。

16.3.3 向指示板添加注释

CTest 和 CDash 支持向指示板提交添加注释文件。它们将以可点击图标的形式出现在指示板上,该图标链接到所有注释文件的文本。添加注释,可以使用 ctest -A 选项,后面跟着一个分号分隔的文件名列表。这些文件的内容将作为指示板的注释提交。例如:

ctest -D Continuous -A C:/MyNotes.txt;C:/OtherNotes.txt

使用指示板提交注释的另一种方法是将注释作为文件复制或写入二进制树的 Testing 目录下的 Notes 目录。 CTest 提交指示板时在这里发现的任何文件也将作为注释上传。

16.4 CTest 脚本

本节描述如何编写基于命令的 CTest 脚本,这些脚本允许维护者对指示板的各个步骤进行细粒度控制。

指示板维护者可以访问单独的 CTest 命令函数,比如 ctest_configurectest_build 。通过单独运行这些功能,用户可以灵活地开发自定义测试方案。下面是一个 CTest 脚本的例子:

make_minimum_required(VERSION 3.20)

set(CTEST_SITE          "andoria.kitware")
set(CTEST_BUILD_NAME    "Linux-g++")
set(CTEST_NOTES_FILES
    "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")

set(CTEST_DASHBOARD_ROOT   "$ENV{HOME}/Dashboards/My Tests")
set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/CMake")
set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/CMake-gcc ")

set(CTEST_UPDATE_COMMAND    "/usr/bin/cvs")
set(CTEST_CONFIGURE_COMMAND
    "\"${CTEST_SOURCE_DIRECTORY}/bootstrap\"")
set(CTEST_BUILD_COMMAND     "/usr/bin/make -j 2")


ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})

ctest_start(Nightly)
ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}")
ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_submit()

第一块中包含了关于提交的变量。

set(CTEST_SITE              "andoria.kitware")
set(CTEST_BUILD_NAME        "Linux-g++")
set(CTEST_NOTES_FILES
    "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")

一旦系统将结果提交给指示板,这些变量将用于识别系统。 CTEST_NOTES_FILES 是应该作为指示板提交的注释所提交的文件列表。这个变量对应于 ctest 的 -A 标志。

第二块描述了 CTest 函数将用于执行的任务信息:

set(CTEST_DASHBOARD_ROOT   "$ENV{HOME}/Dashboards/My Tests")
set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/CMake")
set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/CMake-gcc ")
set(CTEST_UPDATE_COMMAND    "/usr/bin/cvs")
set(CTEST_CONFIGURE_COMMAND
   "\"${CTEST_SOURCE_DIRECTORY}/bootstrap\"")
set(CTEST_BUILD_COMMAND     "/usr/bin/make -j 2")

CTEST_UPDATE_COMMAND 是用于从仓库更新源码目录的命令的路径。目前 CTest 支持并发版本系统( CVS )、 Subversion 、 Git 、 Mercurial 和 Bazaar 。

配置和构建处理器都支持两种模式。一种模式是提供将在该阶段调用的完整命令。这是为了支持不使用 CMake 作为配置或构建工具的项目。在本例中,你可以通过分别设置 CTEST_CONFIGURE_COMMANDCTEST_BUILD_COMMAND 变量来指定配置和构建项目的完整命令行。

对于构建步骤,你还应该设置变量 CTEST_PROJECT_NAME 和 CTEST_BUILD_CONFIGURATION ,以指定如何构建项目。在这种情况下, CTEST_PROJECT_NAME 将匹配顶层 CMakeLists 文件的 project 命令。 CTEST_BUILD_CONFIGURATION 应该是 Release 、 Debug 、 MinSizeRel 或 RelWithDebInfo 之一。此外, CTEST_BUILD_FLAGS 可以作为构建命令的提示。一个基于 CMake 的项目测试的例子入如下示:

set(CTEST_PROJECT_NAME "Grommit")
set(CTEST_BUILD_CONFIGURATION "Debug")

最后一块执行实际的测试和提交:

ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})

ctest_start(Nightly)

ctest_update(SOURCE
             "${CTEST_SOURCE_DIRECTORY}" RETURN_VALUE res)
ctest_configure(BUILD
                "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
ctest_submit(RETURN_VALUE res)

ctest_empty_binary_directory 命令清空目录和所有子目录。请注意,这个命令有一个内置的安全措施,即只有在顶层目录中有 CMakeCache.txt 文件时,它才会删除该目录。这是为了防止 CTest 错误地删除非构建目录。

这一块其余部分包含对实际 CTest 函数的调用。每一个都对应一个 CTest -D 选项。例如,相较于:

ctest -D ExperimentalBuild

该脚本使用:

ctest_start(Experimental)
ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)

每个步骤都会产生一个返回值,该值表示该步骤是否成功。例如, Update 阶段的返回值可以在 Continuous 指示板中使用,以确定是否应该运行指示板的其余部分。

让我们研究一个更高级的 CTest 脚本。这个脚本驱动名为 Slicer 的应用程序的测试。 Slicer 内部使用 CMake ,但它通过一系列 Tcl 脚本驱动构建过程。这种方法的问题之一是它不支持源外构建。此外,在 Windows 上,某些模块是预先构建的,因此必须将它们复制到构建目录。为了测试这样的项目,我们会使用这样的脚本:

cmake_minimum_required(VERSION 3.20)

# 设置指示板特定的变量 —— 名称和注释
set(CTEST_SITE              "dash11.kitware")
set(CTEST_BUILD_NAME        "Win32-VS71")
set(CTEST_NOTES_FILES
     "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")

# 不要让任何一个测试运行超过 1500 秒
set(CTEST_TIMEOUT "1500")

# 设置源码目录和二进制目录
set(CTEST_SOURCE_DIRECTORY  "C:/Dashboards/MyTests/slicer2")
set(CTEST_BINARY_DIRECTORY  "${CTEST_SOURCE_DIRECTORY}-build")

set (SLICER_SUPPORT
     "//Dash11/Shared/Support/SlicerSupport/Lib")
set (TCLSH   "${SLICER_SUPPORT}/win32/bin/tclsh84.exe")
# 设置完整的更新、配置和构建命令
set (CTEST_UPDATE_COMMAND
     "C:/Program Files/TortoiseCVS/cvs.exe")
set (CTEST_CONFIGURE_COMMAND
    "\"${TCLSH}\"
     \"${CTEST_BINARY_DIRECTORY}/Scripts/genlib.tcl\"")
set (CTEST_BUILD_COMMAND
    "\"${TCLSH}\"
     \"${CTEST_BINARY_DIRECTORY}/Scripts/cmaker.tcl\"")

# 清除二进制树
file (WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt"
      "// Dummy cache just so that ctest will wipe binary dir")
ctest_empty_binary_directory (${CTEST_BINARY_DIRECTORY})

# 用于 Slicer 构建程序的特殊变量
set (ENV{MSVC6}              "0")
set (ENV{GENERATOR}          "Visual Studio 7 .NET 2003")
set (ENV{MAKE}               "devenv.exe ")
set (ENV{COMPILER_PATH}
     "C:/Program Files/Microsoft Visual Studio .NET
2003/Common7/Vc7/bin")
set (ENV{CVS}                "${CTEST_UPDATE_COMMAND}")

# 启动并更新指示板
ctest_start (Nightly)
ctest_update (SOURCE "${CTEST_SOURCE_DIRECTORY}")

# 定义一个宏来复制目录
macro (COPY_DIR srcdir destdir)
  exec_program ("${CMAKE_EXECUTABLE_NAME}" ARGS
               "-E copy_directory \"${srcdir}\" \"${destdir}\"")
endmacro ()

# Slicer 不支持源外构建,因此我们首先将源目录复制到二进制目录,然后再构建它
copy_dir ("${CTEST_SOURCE_DIRECTORY}"
          "${CTEST_BINARY_DIRECTORY}")


# 将 Slicer 需要的库复制到二进制树中
copy_dir ("${SLICER_SUPPORT}"
          "${CTEST_BINARY_DIRECTORY}/Lib")

# 最后执行配置、构建、测试和提交步骤
ctest_configure (BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_build (BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_test (BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_submit ()

使用扩展的 CTest 脚本,我们可以完全控制流程,因此我们可以在任何地方执行任意命令。例如,在执行项目更新之后,脚本将源树复制到构建目录中。这允许它进行“源外”构建。

16.4.1 项目角色: CDash 支持三个等级的用户角色

  • 常规用户是对项目代码存储库具有读写访问权限的普通用户。
  • 站点维护人员负责定期向 CDash 提交内容。
  • 项目管理员保留了在 CDash 中管理项目的特权。

前两个级别可以由用户自己定义。项目管理员访问权限必须由项目的其他管理员或 CDash 服务器管理员授予。

16.4.2 提交备份

默认情况下, CDash 备份所有传入的 XML 提交,并将它们放在 backup 目录中。默认的时间范围是 48 小时。时间范围可以在 config.local.php 中修改,如下所示:

$CDASH_BACKUP_TIMEFRAME=72;

如果项目是私有的,建议将备份目录设置在根目录之外,以确保没有人可以访问 XML 文件,或者在 backup 目录下的 .htaccess 中添加以下行:

<Files *>
order allow,deny
deny from all
</Files>

注意,只有当新的提交到来时,备份目录才会被清空。如果需要, CDash 还可以从备份目录导入构建。

16.4.3 构建组

构建可以按组来组织。在 CDash 中,自动定义了三个不能删除的组: Nightly 、 Continuous 和 Experimental 。这些组与 CTest 施加的组相同。当单击主指示板上的组名时,每个组都有一个关联的描述。

默认情况下,构建属于与 CTest 定义的构建类型相关联的组,也就是说, Nightly 构建将进入 Nightly 部分。 CDash 根据其名称、站点和构建类型来匹配构建。例如,来自站点 “ midworld.kitware ” 的 Nightly 构建名为“ Linux-gcc-4.3 ”,它将被移到 Nightly 部分,除非有特殊规则被定义在了“ Linux-gcc-4.3 ”-“ midworld.kitware ”-“ Nightly ”上。有两种方法可以通过定义规则将构建移动到给定的组中:全局移动和单个移动。

16.4.3.1 单个移动只允许修改一个特定的构建

如果以项目管理员身份登录,则在主指示板页面上的每个构建旁边会显示一个小文件夹图标。单击图标会显示每个构建的一些选项。特别是,项目管理员可以将一个构建标记为预期、将构建移动到特定组、或删除虚假构建。

预期构建:项目管理员可以按预期标记某些构建。这意味着希望每天提交构建。这允许你快速检查构建是否没有提交到今天的指示板上,或者通过单击主指示板上的信息图标快速评估构建丢失了多长时间。

如果前一天没有提交预期的构建,并且选中了项目的“ Email build Missing ”选项,则将向站点维护者和项目管理员发送电子邮件以提醒他们(请参阅站点部分了解更多信息)。

16.4.4 邮件

当指定构建发生故障时, CDash 会向开发人员和项目管理员发送电子邮件。电子邮件特性的配置位于三个地方: config.local.php 文件、项目管理部分和项目的组部分。

在 config.local.php 中,定义了两个变量来指定发送电子邮件的电子邮件地址和回复地址。注意,不能在当前版本的 CDash 中定义 SMTP 服务器,它被假定为在机器上运行本地电子邮件服务器。

$CDASH_EMAIL_FROM = 'admin@mywebsite.com';
$CDASH_EMAIL_REPLY = 'noreply@mywebsite.com';

在项目的电子邮件配置部分,可以调整几个参数来控制电子邮件特性。

在项目的“构建组”管理部分,管理员可以决定是否将电子邮件发送到特定的组,或者是否只发送摘要电子邮件。当当天至少有一个构建失败时,将为给定组发送摘要电子邮件。

16.4.5 站点

CDash 将站点称为向给定项目提交至少一个构建的单个机器。一个站点可能会向存储在 CDash 中的多个项目提交多个构建( 例如 Nightly 和 Continuous )。

为了查看站点描述,请从项目的主指示板页面单击站点的名称。站点的描述包括有关处理器类型和速度的信息,以及给定机器上可用的内存量。站点的描述是由 CTest 自动发送的,但是在某些情况下可能需要手动编辑。再者,如果对机器进行升级,例如对内存进行升级, CDash 会追踪描述的历史记录,允许用户比较升级前后的性能。

站点通常属于一个维护者,负责向 CDash 提交内容。当站点没有提交时,向站点维护者发出警告是很重要的,因为这可能与配置问题有关。

一旦声明了站点,如果客户端机器由于未知的原因没有提交(假设站点预计每晚提交),则其维护者将收到电子邮件。此外,该站点将出现在维护者配置文件的“我的站点”部分,方便快速检查站点的状态。

站点页面的另一个特点是显示机器负载的饼状图。假设一个站点提交给多个项目,了解机器是否有空间向 CDash 提交其他内容通常是有用的。饼状图概述了每个项目的机器提交时间。

16.4.6 图表

CDash 目前绘制了三种类型的图表。图标是从数据库记录动态生成的,并且是交互式的。

构建时间图显示了一段时间内构建项目所需的时间。

测试时间图显示运行特定测试的时间以及它的状态(通过/失败)。

16.4.7 向构建添加注释

在某些情况下,告知其他开发人员有人正在查看构建错误是很有用的。

16.4.8 日志

CDash 支持使用 error_log() PHP 函数的内部日志记录机制。任何严重的 SQL 错误都会被记录下来。默认情况下, CDash 日志文件位于 backup 目录中,名称为 cdash.log 。可以通过更改 config.local.php 配置文件中的变量来修改日志文件的位置。

$CDASH_BACKUP_DIRECTORY='/var/temp/cdashbackup/log';

如果日志文件位于标准位置,则可以直接从 CDash 访问日志文件。

日志轮换机制允许用户将当前日志文件限制在一定的大小。

16.4.9 测试计时

CDas h支持对测试持续时间进行检查。 CDash 保存每个测试在数据库中运行所需时间的平均值和标准偏差的当前加权平均值。为了使计算尽可能高效,使用了以下公式,它只涉及到之前的构建。

// alpha 是当前计算的“窗口”
//默认 alpha 值为 0.3
newMean = (1-alpha)*oldMean + alpha*currentTime

newSD = sqrt((1-alpha)*SD*SD +
  alpha*(currentTime-newMean)*(currentTime-newMean)

根据以下逻辑,测试被定义为计时失败:

if previousSD < thresholdSD then previousSD = thresholdSD
if currentTime > previousMean+multiplier*previousSD then fail

16.4.10 移动支持

由于 CDash 是通过 XSLT 使用模板层编写的,因此开发新的布局就像添加新的呈现模板一样简单。作为演示,提供了一个带有当前版本的 CDash 的 iPhone web 模板。

http://mycdashserver/CDash/iphone

主页面显示了服务器上托管的公共项目列表。单击项目的名称将加载其当前指示板。以同样的方式,单击给定的构建将显示有关该构建的更详细信息。在撰写本文时,这种布局不支持登录和访问 CDash 的私有部分。

16.4.11 备份 CDash

CDash 使用的所有数据(日志除外)都存储在它的数据库中。定期备份数据库非常重要,尤其是在执行CDash 升级之前。有几种方法可以备份 MySQL 数据库。最简单的是使用 mysqldump 命令:

mysqldump -r cdashbackup.sql cdash

如果你只使用 MyISAM 表,你可以复制 MySQL 数据目录中的 CDash 目录。注意,在进行复制之前需要关闭 MySQL ,以便在复制期间不能更改文件。与 MySQL 类似, PostGreSQL 有一个 pg_dump 实用程序:

pg_dump -U posgreSQL_user cdash > cdashbackup.sql

16.4.12 更新 CDash

当新版本的 CDash 发布时,或者如果你决定更新存储库,如果当前数据库需要升级, CDash 将在首页上发出警告以告知你。升级到新版本时,应采取以下步骤:

  1. 备份 SQL 数据库(参见前一节)。

  2. 备份 config.local.php (或 config.php )配置文件。

  3. 用最新版本替换当前的 cdash 目录,并复制 cdash 目录中的 config.local.php 。

  4. 将浏览器导航到你的CDash页面。(例如:http://localhost/CDash )。

  5. 请注意主页上的版本号,它应该与你要升级到的版本相匹配。

  6. 可能会出现以下消息:“当前数据库模式与你正在运行的 CDash 版本不匹配,请在 CDash 的管理面板中升级数据库结构。”这是执行以下步骤的有用提示。

  7. 以管理员身份登录到 CDash 。

  8. 在“管理”部分,单击“数据库维护”。

  9. 点击“升级 CDash ”:这个过程可能需要一些时间,这取决于数据库的大小(不要关闭浏览器)。

    • 当 CDash 执行升级时,可能会出现进度消息。

    • 如果升级过程花费的时间太长,你可以在 backup/cdash.log 文件中查看该过程花费了很长时间和/或失败的地方。

    • 据报道,在一些系统中,旋转图标永远不会变成一个复选标记。如果你觉得升级时间太长,请检查 cdash.log 中的“升级完成”字符串。

    • 对于 50GB 的数据库,升级可能需要 2 个小时。

  10. 一些 web 浏览器在升级时可能会有问题(一些 javascript 变量没有正确传递),在这种情况下,你可以执行单独的更新。例如从 CDash 1-2 升级到 1-4 :

http://mywebsite.com/CDash/backwardCompatibilityTools.php?upgrade-1-4=1

16.4.13 CDash 维护

数据库维护:我们建议你定期进行数据库优化(更新索引、清理等),以保持数据库的稳定。 MySQL 有一个叫做 mysqlcheck 的实用程序, PostgreSQL 有几个实用程序,比如 vacuumdb 。

删除日期不正确的构建:某些构建可能会以错误的日期提交给 CDash ,这要么是因为 XML 文件中的日期不正确,要么是因为 CDash 无法识别时区(主要是PHP)。这些构建不会显示在任何指示板中,因为开始时间是假的。为了删除这些构建:

  1. 以管理员身份登录到CDash。
  2. 单击管理部分中的 [ CDash maintenance ]。
  3. 点击“删除错误开始日期的构建”。

重新计算测试时间:如果你刚刚升级了 CDash ,你可能会注意到当前提交显示了由于时间缺陷导致的大量失败测试。这是因为 CDash 没有足够的样本点来计算每个测试的平均值和标准偏差,特别是标准偏差可能非常小(前几个样本可能为零)。你应该关闭“启用测试计时”大约一个星期,或者直到你获得足够的构建提交,并且 CDash 已经计算出每个测试时间的近似平均值和标准偏差(才能再次开启测试计时)。

另一种选择是强迫 CDash 计算过去几天每个测试的平均值和标准偏差。需要注意的是,这个过程可能需要很长时间,这取决于所涉及的测试和项目的数量。为了重新计算测试时间:

  1. 以管理员身份登录到 CDash 。
  2. 单击管理部分中的 [ CDash maintenance ] 。
  3. 指定重新计算测试时间的天数(默认为 4 天)。
  4. 点击“ Compute test timing ”。流程完成后,应更新在此期间提交的测试的新平均值、标准偏差和状态。
16.4.13.1 自动化的构建移除

为了将数据库保持在合理的大小, CDash 可以自动清除旧的构建。目前有两种方法可以设置自动删除构建:不使用 cronjob ,编辑 config.local.php 并添加/编辑以下行

$CDASH_AUTOREMOVE_BUILDS='1';

CDash 将在当天的第一次提交时自动删除构建。请注意,删除构建可能会给数据库增加额外的负载,或者如果你的数据库很大且提交的数量很高,则会减慢当前的提交过程。如果可以使用 cronjob ,则可以使用 PHP 命令行工具在方便的时候触发构建删除。例如,在每周日早上 6 点移除所有项目的构建:

0 6 * * 0 php5 /var/www/CDash/autoRemoveBuilds.php all

请注意,可以将’ all '参数更改为特定的项目名称,以便从单个项目中清除构建。

16.4.13.2 CDash 的 XML 模式

可以很容易地扩展 CDash 中的 XML 解析器以支持新特性。当前由 CTest 生成的 XML 模式及其在书中描述的特性位于:

http://public.kitware.com/Wiki/CDash:XML

16.4.14 子项目

CDash 支持将项目拆分为子项目。一些子项目可能反过来依赖于其他子项目。一个典型的实际项目由库、可执行文件、测试套件、文档、网页和安装程序组成。将你的项目组织到定义良好的子项目中,并在 CDash 指示板上显示 Nightly 构建的结果,这有助于在不同的粒度级别上确定问题的位置。

带有子项目的项目与没有子项目的项目具有不同的顶层 CDash 页面视图。它包含整个项目的摘要行,以及每个子项目的摘要行。

16.4.14.1 组织和定义子项目

要将子项目组织添加到你的项目中,你必须:

  1. 为 CDash 定义子项目,以便它知道如何正确地显示它们。
  2. 使用 CTest 构建脚本来提交项目的子项目构建。
  3. 对项目的 CMakeLists.txt 文件进行一些(重新)组织也可能是必要的,以便允许按子项目构建项目。

有两种方法可以定义子项目及其依赖项:以项目管理员身份登录时在 CDash GUI 中交互地定义子项目,或者提交描述子项目和依赖项的 project .xml 文件。

16.4.14.2 交互式地添加子项目

作为一个项目管理员,“ Manage subprojects ”按钮将出现在你的 CDash 页面的每个项目上。单击“ Manage Subprojects ”按钮将打开管理子项目页面,你可以在其中为你作为管理员的任何项目添加新的子项目,或在现有子项目之间建立依赖关系。

16.4.14.3 自动地添加子项目

定义 CDash 子项目及其依赖关系的另一种方法是在 CTest 在向 CDash 提交构建时发送的常规提交文件中添加一个“ Project.xml ”文件。如果要定义与上面交互示例( Exes 和 Libs )相同的两个子项目,并具有相同的依赖关系( Exes 依赖于 Libs ), Project.xml 文件看起来像下面的示例:

<Project name="Tutorial">
  <SubProject name="Libs"></SubProject>
  <SubProject name="Exes">
    <Dependency name="Libs">
  </SubProject>
</Project>

一旦编写或生成了 Project.xml 文件,就可以使用 ctest_submit 命令的 FILES 参数从 ctest -S 脚本将其提交给 CDash ,或者直接从为指示板提交配置的构建树中的 ctest 命令行提交。

从 ctest -S 脚本内部:

ctest_submit(FILES "${CTEST_BINARY_DIRECTORY}/Project.xml")

从命令行:

cd ../Project-build
ctest --extra-submit Project.xml

CDash 将根据 Project.xml 文件自动添加子项目和依赖项。 CDash 还将删除 Project.xml 文件中未定义的任何子项目或依赖项。此外,如果同一个 Project.xml 被多次提交,第二次和随后的提交将没有可观察到的效果:第一次提交添加/修改数据,第二次和以后的提交发送相同的数据,因此不需要更改。随着时间的推移, CDash 追踪子项目定义的更改以允许项目发展。如果你从过去的日期查看指示板,那么 CDash 将根据该日期生效的子项目定义显示项目/子项目视图。

16.4.15 使用带有 PARTS 和 FILES 的 ctest_submit

ctest_submit 命令支持 PARTS 和 FILES 参数。使用 PARTS ,你可以通过每次 ctest_submit 调用发送 xml 文件的任何子集。默认情况下,所有可用的部件都会随 ctest_submit 调用一起发送。脚本可以等到所有指示板阶段完成,然后调用 ctest_submit 一次,在运行结束时发送所有阶段的结果。或者,脚本可以调用带有 PARTS 的 ctest_submit 来完成结果子集的部分提交。例如,可以在 ctest_configure 之后提交 configure 结果,在 ctest_build 之后提交 build 结果,在 ctest_test 之后提交 test 结果。这允许在构建过程中发布信息。

使用 FILES ,你可以将任意 XML 文件发送到 CDash 。除了 CTest 发送的标准构建结果 XML 文件之外, CDash 还处理描述子项目和依赖项的 Project.xml 文件。下面是一个指示板脚本的示例,它在最后一行包含一个 ctest_submit 调用

ctest_start(Experimental)
ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}")
ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_submit()

提交可以以增量方式进行,提交的每个部分在可用时发送:

ctest_start(Experimental)
ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}")
ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_submit(PARTS Update Configure Notes)

ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" APPEND)
ctest_submit(PARTS Build)

ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}")
ctest_submit(PARTS Test)

按部分增量提交意味着当构建仍在进行时,你可以在 CDash 指示板上实时检查配置阶段的结果。同样,你可以在测试仍在运行时实时检查构建阶段的结果。当按部分提交时,在 ctest_build 命令中使用 APPEND 关键字是很重要的。如果不使用 APPEND ,那么当 CDash 接收到 Build.xml 文件时,它将擦除具有相同构建名称、站点名称和构建戳的任何现有构建。

16.4.16 将项目拆分为多个子项目

一个 ctest_build 调用构建所有内容,然后一个 ctest_test 调用测试所有内容,这对于没有子项目的项目来说就足够了,但是如果你想要在每个子项目的基础上向 CDash 提交结果,你将不得不对你的项目和测试脚本进行一些更改。对于你的项目,你需要确定哪些目标是哪些子项目的一部分。如果你组织 CMakeLists 文件,这样你就可以为每个子项目构建一个目标,并且你可以根据子项目名称派生(或查找)该目标的名称,那么修改你的脚本以将其分成多个较小的配置/构建/测试块应该是相对轻松的。为此,你可以根据需要以各种方式修改 CMakeLists 文件。下面列出了最常规的修改。

16.4.16.1 CMakeLists.txt 的修改
  • 名称目标与子项目相同,以子项目名称为基础的目标名称,或者提供从子项目名称映射到目标名称的查找机制。
  • 可以添加自定义目标来将现有目标聚合到子项目中,使用 add_dependencies 来表示自定义目标所依赖的现有目标。
  • 将 LABELS 目标属性添加到具有子项目名称值的目标中。
  • 将 LABELS 测试属性添加到具有子项目名称值的测试中。

接下来,你需要修改运行指示板的 CTest 脚本。为了将一个大的单片构建拆分为更小的子项目构建,你可以在 CTest 驱动程序脚本中使用 foreach 循环。为了帮助你遍历子项目, CDash 在 CTestConfig.cmake 中提供了一个名为 CTEST_PROJECT_SUBPROJECTS 的变量。在上面的例子中, CDash 产生一个这样的变量:

set(CTEST_PROJECT_SUBPROJECTS Libs Exes)

CDash 对列表中的元素进行排序,首先是独立的子项目(不依赖于任何其他子项目),其次是仅依赖于独立子项目的子项目,然后是依赖于这些子项目的子项目。相同的逻辑将持续进行,直到所有子项目以有意义的顺序一个接一个地分别构建一次。

为了便于只构建与子项目相关联的目标,使用名为 CTEST_BUILD_TARGET 的变量来告诉 ctest_build 要构建什么。为了便于只运行与子项目相关联的测试,请将 LABELS 测试属性分配给测试,并将 INCLUDE_LABEL 参数用于 ctest_test

16.4.16.2 ctest 驱动脚本的修改
  • 按依赖顺序迭代子项目(从独立到最依赖…)。
  • 设置 SubProject 和 Label 全局属性 — CTest使用这些属性将结果提交到 CDash 服务器上正确的子项目。
  • 为这个子项目构建目标:根据子项目名称计算要构建的目标的名称,设置 CTEST_BUILD_TARGET ,调用 ctest_build
  • 使用 ctest_test 的 INCLUDE 或 INCLUDE_LABEL 参数运行此子项目的测试。
  • 使用 ctest_submit 和 PARTS 参数来提交完成的部分结果。

为了说明这一点,下面的示例显示了将构建拆分为更小的部分所需的更改。假设子项目名称与构建子项目组件所需的目标名称相同。例如,下面是设想的教程项目中 CMakeLists.txt 的一个片段。唯一需要添加的内容(因为目标名称与子项目名称相同)是对每个目标和每个测试的 set_property 的调用。

# " Libs "是库名称(目标名称)和子项目名称
add_library (Libs ...)
set_property (TARGET Libs PROPERTY LABELS Libs)
add_test (LibsTest1 ...)
add_test (LibsTest2 ...)
set_property (TEST LibsTest1 LibsTest2 PROPERTY LABELS Libs)

# "Exes" 是可执行文件名称 (目标名成)
# and the subproject name
add_executable (Exes ...)
target_link_libraries (Exes Libs)
set_property (TARGET Exes PROPERTY LABELS Exes)
add_test (ExesTest1 ...)
add_test (ExesTest2 ...)
set_property (TEST ExesTest1 ExesTest2 PROPERTY LABELS Exes)

下面是 CTest 驱动程序脚本在将这个项目组织到子项目之前和之后的样子的一个示例。改变之前:

ctest_start (Experimental)
ctest_update (SOURCE "${CTEST_SOURCE_DIRECTORY}")
ctest_configure (BUILD "${CTEST_BINARY_DIRECTORY}")
# 构建所有目标: Libs 和 Exes
ctest_build (BUILD "${CTEST_BINARY_DIRECTORY}")
# 运行所有测试
ctest_test (BUILD "${CTEST_BINARY_DIRECTORY}")
# 在最后,一次性提交所有内容
ctest_submit ()

改变之后:

ctest_start (Experimental)
ctest_update (SOURCE "${CTEST_SOURCE_DIRECTORY}")
ctest_submit (PARTS Update Notes)

# 获取 CTEST_PROJECT_SUBPROJECTS 定义
include ("${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake")

foreach (subproject ${CTEST_PROJECT_SUBPROJECTS})
  set_property (GLOBAL PROPERTY SubProject ${subproject})
  set_property (GLOBAL PROPERTY Label ${subproject})

  ctest_configure (BUILD "${CTEST_BINARY_DIRECTORY}")
  ctest_submit (PARTS Configure)

  set (CTEST_BUILD_TARGET "${subproject}")
  ctest_build (BUILD "${CTEST_BINARY_DIRECTORY}" APPEND)
    # builds target ${CTEST_BUILD_TARGET}
  ctest_submit (PARTS Build)

  ctest_test (BUILD "${CTEST_BINARY_DIRECTORY}"
    INCLUDE_LABEL "${subproject}"
  )
# 仅运行 LABELS 属性匹配“ ${subproject} ”的测试
  ctest_submit (PARTS Test)
endforeach ()

在一些项目中,可能需要多个 ctest_build 步骤来构建子项目的所有部分。例如,在 Trilinos 中,每个子项目构建 ${subproject}_libs 目标,然后构建 all 目标来构建测试套件中所有配置的可执行文件。它们还配置依赖项,以便在构建所有目标时,只构建需要为当前配置的包构建的可执行文件。

通常,如果将多个 Build.xml 文件提交给具有相同构建戳的 CDash ,它将删除现有项并在其位置添加新项。在需要多个 ctest_build 步骤的情况下,每个步骤都有自己的 ctest_submit(PARTS Build) 调用,并在所有属于一起的 ctest_build 调用中使用 APPEND 关键字参数。 APPEND 标志告诉 CDash 累积来自多个提交的结果,并在指示板上的一行中显示所有这些结果的聚合。从 CDash 的角度来看,多个 ctest_build 调用(使用相同的构建戳和子项目并打开 APPEND )会导致单个 CDash 构建。

在你最喜欢的基于 cmake 的项目中采用这些技巧和技术:

  • LABELS 是一个 CMake/CTest 属性,适用于源文件、目标文件和测试文件。标签在 xml 结果文件中,并被发送到 CDash 。
  • 使用 ctest_submit(PARTS…) 执行增量提交。结果可以更快地在指示板上查看。当按部分提交时,不要忘记在 ctest_build 调用中使用 APPEND 。
  • 使用带有 INCLUDE_LABEL 的 ctest_test 来只运行标签与正则表达式匹配的测试。
  • 使用 CTEST_BUILD_TARGET 一次构建一个子项目,并在此过程中提交子项目指示板。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值