-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathCTestDashboard.cmake
More file actions
357 lines (326 loc) · 13.9 KB
/
CTestDashboard.cmake
File metadata and controls
357 lines (326 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
## ---------------------------------------------------------------------------
## CTestDashboard.cmake -- CTest dashboard driver script for MAPL
##
## Usage:
## ctest -S CTestDashboard.cmake [options] -V
##
## Optional command-line overrides (pass with -D before -S):
## -D model=Nightly # default: Experimental
## -D build_type=Debug # default: Release
## -D generator=Ninja # default: Ninja
## -D jobs=8 # default: 6
## -D site=myhost # default: auto-detected hostname
## # NOTE: Set this explicitly on CI runners (GitHub Actions),
## # SLURM compute nodes, or laptops on VPNs. Otherwise, CDash
## # sees a different random hostname each time and cannot
## # connect the builds into a contiguous history timeline.
## -D build_name=my-label # default: auto-generated
##
## Environment variables (optional):
## CTEST_EXTRA_CMAKE_ARGS Space-separated extra args passed to cmake
## configure. Example:
## export CTEST_EXTRA_CMAKE_ARGS="-DCMAKE_Fortran_COMPILER=gfortran -DMPIEXEC_PREFLAGS=--oversubscribe"
## CDASH_AUTH_TOKEN CDash authentication token for submissions.
## Generate one at my.cdash.org → Project Settings
## → Authentication tokens. Keep this out of git!
##
## Example - quick experimental submit:
## ctest -S CTestDashboard.cmake -V
##
## Example - nightly with 8 jobs:
## ctest -D model=Nightly -D jobs=8 -S CTestDashboard.cmake -V
##
## CDash project: https://my.cdash.org/index.php?project=MAPL
## ---------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.27)
## ---------------------------------------------------------------------------
## 0. Defaults (can be overridden via -D on the ctest command line)
## ---------------------------------------------------------------------------
if(NOT DEFINED model)
set(model "Experimental")
endif()
if(NOT DEFINED build_type)
set(build_type "Release")
endif()
if(NOT DEFINED generator)
set(generator "Ninja")
endif()
if(NOT DEFINED jobs)
set(jobs 6)
endif()
## ---------------------------------------------------------------------------
## Coverage: gcov tool selection
##
## On macOS /usr/bin/gcov is Apple LLVM gcov and cannot read .gcda files
## produced by gfortran. We search for a versioned gcov (gcov-15, gcov-14,
## ...) matching the Homebrew gfortran in PATH, falling back to plain gcov.
## On Linux with GCC this usually resolves to the correct gcov automatically.
## The GMAO Docker images install GCC under /gcc/bin (non-standard prefix),
## so we add that path explicitly to ensure find_program locates gcov there.
## ---------------------------------------------------------------------------
find_program(_gcov_cmd
NAMES gcov-15 gcov-14 gcov-13 gcov-12 gcov
PATHS /gcc/bin
NO_DEFAULT_PATH
DOC "gcov tool for coverage data collection"
)
# If not found under the non-standard prefix, fall back to PATH search
# (covers standard Linux installs and Homebrew on macOS)
if(NOT _gcov_cmd)
find_program(_gcov_cmd
NAMES gcov-15 gcov-14 gcov-13 gcov-12 gcov
DOC "gcov tool for coverage data collection"
)
endif()
if(_gcov_cmd)
set(CTEST_COVERAGE_COMMAND "${_gcov_cmd}")
message(STATUS "Coverage gcov: ${CTEST_COVERAGE_COMMAND}")
else()
message(WARNING "No versioned gcov found -- coverage may use wrong gcov on macOS")
endif()
## ---------------------------------------------------------------------------
## 1. Source and binary directories
## ---------------------------------------------------------------------------
# Source directory is the directory containing this script
get_filename_component(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
# Build directory mirrors the preset naming convention: build-<preset>
# For Release+Ninja -> build-Release-Ninja
# For Release+Unix Makefiles -> build-Release
if(generator STREQUAL "Ninja")
set(_preset_suffix "${build_type}-Ninja")
else()
set(_preset_suffix "${build_type}")
endif()
set(CTEST_BINARY_DIRECTORY "${CTEST_SOURCE_DIRECTORY}/build-${_preset_suffix}")
## ---------------------------------------------------------------------------
## 2. Site and build name
## ---------------------------------------------------------------------------
cmake_host_system_information(RESULT _hostname QUERY HOSTNAME)
cmake_host_system_information(RESULT _os_name QUERY OS_NAME)
cmake_host_system_information(RESULT _os_rel QUERY OS_RELEASE)
if(NOT DEFINED site)
set(site "${_hostname}")
endif()
set(CTEST_SITE "${site}")
# Auto-detect compiler from environment if possible
if(NOT DEFINED build_name)
# Try to identify the Fortran compiler for a descriptive name
if(DEFINED ENV{FC})
get_filename_component(_fc_name "$ENV{FC}" NAME)
elseif(EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt")
# Read from an existing cache
file(STRINGS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" _cache_fc
REGEX "^CMAKE_Fortran_COMPILER:FILEPATH=")
if(_cache_fc)
string(REGEX REPLACE ".*=(.*)" "\\1" _fc_path "${_cache_fc}")
get_filename_component(_fc_name "${_fc_path}" NAME)
endif()
endif()
if(NOT _fc_name)
set(_fc_name "unknown-FC")
endif()
# Try to grab the current git branch name
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}"
RESULT_VARIABLE _git_res
OUTPUT_VARIABLE _git_branch
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_git_res EQUAL 0 AND NOT _git_branch STREQUAL "HEAD" AND NOT _git_branch STREQUAL "")
string(REPLACE "/" "-" _safe_branch "${_git_branch}")
set(build_name "${_safe_branch}-${_os_name}-${_os_rel}-${_fc_name}-${build_type}-${generator}")
else()
set(build_name "${_os_name}-${_os_rel}-${_fc_name}-${build_type}-${generator}")
endif()
endif()
set(CTEST_BUILD_NAME "${build_name}")
## ---------------------------------------------------------------------------
## 3. CMake configure command (equivalent to cmake --preset <name>)
## We call cmake directly so the script controls the preset selection.
## ---------------------------------------------------------------------------
# Use the same cmake that is running this script -- avoids picking up
# CMake.app or other GUI wrappers via find_program() on macOS.
set(CTEST_CMAKE_COMMAND "${CMAKE_COMMAND}")
find_program(CTEST_GIT_COMMAND NAMES git)
# Map generator name to cmake -G argument
if(generator STREQUAL "Ninja")
set(_cmake_generator "Ninja")
else()
set(_cmake_generator "Unix Makefiles")
endif()
# We pick up the preset's installDir convention too
set(_install_dir "${CTEST_SOURCE_DIRECTORY}/install-${_preset_suffix}")
# Pick up any extra cmake args from the environment
# (e.g. -DCMAKE_Fortran_COMPILER=gfortran set by CI)
set(_extra_cmake_args "$ENV{CTEST_EXTRA_CMAKE_ARGS}")
# CTEST_CONFIGURE_COMMAND must be a single string (not a CMake list) --
# CTest passes it directly to the shell via 'sh -c'.
# Rules:
# - Quote the cmake binary path (may contain spaces on some systems).
# - Quote the generator name (may contain spaces, e.g. "Unix Makefiles").
# - Do NOT add extra shell-level quotes around -D values; cmake receives
# them after shell word-splitting and the literal " chars corrupt the value.
# - Quote the source directory path at the end.
set(CTEST_CONFIGURE_COMMAND "\"${CTEST_CMAKE_COMMAND}\"")
string(APPEND CTEST_CONFIGURE_COMMAND " -G \"${_cmake_generator}\"")
string(APPEND CTEST_CONFIGURE_COMMAND " -DCMAKE_BUILD_TYPE=${build_type}")
string(APPEND CTEST_CONFIGURE_COMMAND " -DCMAKE_INSTALL_PREFIX=${_install_dir}")
if(_extra_cmake_args)
string(APPEND CTEST_CONFIGURE_COMMAND " ${_extra_cmake_args}")
endif()
string(APPEND CTEST_CONFIGURE_COMMAND " \"${CTEST_SOURCE_DIRECTORY}\"")
## ---------------------------------------------------------------------------
## 4. Build commands (all must be single strings)
## Step 1: install (the main build)
## Step 2: build-tests (MAPL test executables are a separate target)
## Note: We combine both into a single build command to ensure the
## total build time is correctly captured in a single CDash step.
## ---------------------------------------------------------------------------
set(CTEST_BUILD_COMMAND
"\"${CTEST_CMAKE_COMMAND}\" --build \"${CTEST_BINARY_DIRECTORY}\" --parallel ${jobs} --target install build-tests"
)
## ---------------------------------------------------------------------------
## 5. CMake 4.3 instrumentation: add cdashSubmit + dynamicSystemInformation
## for this dashboard run. CMakeLists.txt already enables trace +
## staticSystemInformation for all builds; we add the CDash-specific
## options here so they only apply when running via this script.
## ---------------------------------------------------------------------------
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.3")
set(_query_dir
"${CTEST_BINARY_DIRECTORY}/.cmake/instrumentation/v1/query")
file(MAKE_DIRECTORY "${_query_dir}")
file(WRITE "${_query_dir}/dashboard-cdash.json"
[=[{
"version": 1,
"options": [
"dynamicSystemInformation",
"cdashSubmit"
]
}
]=])
message(STATUS "CDash instrumentation query written to ${_query_dir}/dashboard-cdash.json")
endif()
## ---------------------------------------------------------------------------
## 6. CTest Use Launchers
## Enables per-compile-line error/warning capture in Build.xml on CDash.
## ---------------------------------------------------------------------------
set(CTEST_USE_LAUNCHERS ON)
set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 1)
## ---------------------------------------------------------------------------
## 7. CDash authentication token
## Set CDASH_AUTH_TOKEN in your environment (never commit the value).
## On GitHub Actions this comes from a repository secret.
## CDash requires an HTTP Authorization Bearer header -- CTEST_AUTH_TOKEN
## is not a real CMake variable; the token must be passed via HTTPHEADER
## in every ctest_submit() call.
## ---------------------------------------------------------------------------
if(DEFINED ENV{CDASH_AUTH_TOKEN})
set(_cdash_auth_header "Authorization: Bearer $ENV{CDASH_AUTH_TOKEN}")
message(STATUS "CDash auth token loaded from CDASH_AUTH_TOKEN env var")
else()
set(_cdash_auth_header "")
message(WARNING
"CDASH_AUTH_TOKEN is not set -- submission will likely be rejected.\n"
"Generate a token at https://my.cdash.org then:\n"
" export CDASH_AUTH_TOKEN=<your-token>")
endif()
## ---------------------------------------------------------------------------
## 8. Dashboard pipeline
## ---------------------------------------------------------------------------
message(STATUS "=== MAPL CDash Dashboard ===")
message(STATUS " Model: ${model}")
message(STATUS " Site: ${CTEST_SITE}")
message(STATUS " Build name: ${CTEST_BUILD_NAME}")
message(STATUS " Source: ${CTEST_SOURCE_DIRECTORY}")
message(STATUS " Binary: ${CTEST_BINARY_DIRECTORY}")
message(STATUS " Generator: ${_cmake_generator}")
message(STATUS " Build type: ${build_type}")
message(STATUS " Jobs: ${jobs}")
message(STATUS "============================")
# Start the dashboard submission
ctest_start(${model})
# Update step (records git revision info; non-fatal if no remote)
ctest_update(RETURN_VALUE _update_result)
message(STATUS "Update result: ${_update_result}")
# Configure (runs cmake to generate build system)
ctest_configure(RETURN_VALUE _configure_result)
if(_configure_result)
message(WARNING "Configure step returned ${_configure_result} -- submitting configure errors")
if(_cdash_auth_header)
ctest_submit(PARTS Configure HTTPHEADER "${_cdash_auth_header}")
else()
ctest_submit(PARTS Configure)
endif()
return()
endif()
# Build (install & build-tests targets)
ctest_build(
NUMBER_ERRORS _build_errors
NUMBER_WARNINGS _build_warnings
RETURN_VALUE _build_result
)
message(STATUS "Build: ${_build_errors} error(s), ${_build_warnings} warning(s)")
# Stop early if the build failed -- don't attempt to run tests against broken binaries.
if(_build_errors GREATER 0)
message(WARNING "Build had ${_build_errors} error(s) -- skipping test step")
if(_cdash_auth_header)
ctest_submit(PARTS Configure Build HTTPHEADER "${_cdash_auth_header}"
RETURN_VALUE _submit_result)
else()
ctest_submit(PARTS Configure Build RETURN_VALUE _submit_result)
endif()
if(_submit_result)
message(WARNING "CDash submission returned ${_submit_result}")
else()
message(STATUS "Build errors submitted to https://my.cdash.org/index.php?project=MAPL")
endif()
return()
endif()
# Run ESSENTIAL tests only (matching CI behaviour).
# Run serially (parallel 1) as in CI to avoid MPI oversubscription issues.
ctest_test(
INCLUDE_LABEL "ESSENTIAL"
PARALLEL_LEVEL 1
RETURN_VALUE _test_result
)
message(STATUS "Test result: ${_test_result}")
# If any tests failed, rerun only the failing ones once (matching CI behaviour)
if(_test_result)
message(STATUS "Re-running only failing tests...")
ctest_test(
INCLUDE_LABEL "ESSENTIAL"
PARALLEL_LEVEL 1
RERUN_FAILED
RETURN_VALUE _test_result
APPEND
)
message(STATUS "Rerun result: ${_test_result}")
endif()
# Collect coverage data (only meaningful for Coverage build type)
if(build_type STREQUAL "Coverage")
ctest_coverage(RETURN_VALUE _coverage_result)
if(_coverage_result)
message(WARNING "Coverage step returned ${_coverage_result}")
else()
message(STATUS "Coverage data collected")
endif()
endif()
# Submit everything to CDash
if(_cdash_auth_header)
ctest_submit(
PARTS Configure Build Test Coverage
HTTPHEADER "${_cdash_auth_header}"
RETURN_VALUE _submit_result
)
else()
ctest_submit(
PARTS Configure Build Test Coverage
RETURN_VALUE _submit_result
)
endif()
if(_submit_result)
message(WARNING "CDash submission returned ${_submit_result}")
else()
message(STATUS "Results submitted to https://my.cdash.org/index.php?project=MAPL")
endif()