Skip to content

Commit c4eff35

Browse files
committed
Update scripts to build/test VecCore with CTest
The script can be generically called as ctest -VV -S cmake/TestVecCore.cmake from the top directory of the repository. There are several options to customize the build, the main ones are: -DCOVERAGE=1 Enables test coverage analysis with gcov -DMEMCHECK=1 Enables memory checking with valgrind -DSTATIC_ANALYSIS=1 Enables static analysis with clang-tidy -DINSTALL=1 Enables an extra step to call make install When enabling coverage, a report is generated by default in the coverage/ directory inside the build directory. The results can be viewed by opening the file coverage/coverage_details.html. This step can be disabled by passing -DGCOVR=0 to ctest. It is recommended to use a build with debug info and low optimizations to generate the coverage analysis. The configuration can also be specified directly on the command line via the -C option. For example, to run a coverage build with less verbose output, and using AVX2 SIMD ISA, run: ctest -V -C RelWithDebInfo -DCOVERAGE=1 -S cmake/TestVecCore.cmake,AVX2 Some environment variables can also influence the behavior of the script, like CC, CXX, CMAKE_GENERATOR, CTEST_CONFIGURATION_TYPE, CMAKE_BUILD_PARALLEL_LEVEL, CTEST_PARALLEL_LEVEL, and CMAKE_ARGS. These are mostly self-explanatory and can be used to override the provided defaults. For example, to build with the clang compiler and use Ninja as CMake generator, one can run: env CC=clang CXX=clang++ CMAKE_GENERATOR=Ninja ctest -V -S cmake/TestVecCore.cmake Finally, the script tries to load configuration files from the .ci subdirectory in the source directory. The default configuration is used if no specific configuration is found for the detected OS. For example, on Ubuntu, a file named ubuntu.cmake will be used if present instead of config.cmake. The script also tries to detect a version, so, for example, on Alma, one could use almalinux8.cmake which would have higher precedence than almalinux.cmake.
1 parent 942b748 commit c4eff35

File tree

3 files changed

+210
-57
lines changed

3 files changed

+210
-57
lines changed

.ci/config.cmake

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
set(BUILD_BENCHMARKS 1 CACHE BOOL "")
2+
set(BUILD_TESTING 1 CACHE BOOL "")
3+
set(BUILD_GOOGLETEST 1 CACHE BOOL "")
4+
set(BUILD_GOOGLEBENCH 1 CACHE BOOL "")
5+
set(BUILD_UMESIMD ${UNIX} CACHE BOOL "")
6+
set(BUILD_VC ${UNIX} CACHE BOOL "")
7+
set(UMESIMD ${UNIX} CACHE BOOL "")
8+
set(VC ${UNIX} CACHE BOOL "")
9+
set(CMAKE_DISABLE_FIND_PACKAGE_PkgConfig ${WIN32} CACHE BOOL "")

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ if (BUILD_DOCS)
8484
add_subdirectory(doc)
8585
endif()
8686

87+
include(CTest)
8788
enable_testing()
8889

8990
if (BUILD_TESTING)

cmake/TestVecCore.cmake

+200-57
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
cmake_minimum_required(VERSION 3.16...3.25)
1+
cmake_minimum_required(VERSION 3.16...3.29)
22

33
set(CTEST_PROJECT_NAME "VecCore")
44

55
set(ENV{LANG} "C")
66
set(ENV{LC_ALL} "C")
7+
set(CTEST_USE_LAUNCHERS TRUE)
78

89
if(CDASH)
910
set(CTEST_DROP_METHOD "http")
@@ -12,17 +13,23 @@ if(CDASH)
1213
set(CTEST_DROP_SITE_CDASH TRUE)
1314
endif()
1415

15-
if(NOT DEFINED CTEST_SITE)
16-
site_name(CTEST_SITE)
17-
if(EXISTS "/etc/os-release")
18-
file(STRINGS "/etc/os-release" OSPN REGEX "^PRETTY_NAME=.*$")
19-
string(REGEX REPLACE "PRETTY_NAME=\"(.*)\"$" "\\1" DISTRO "${OSPN}")
20-
string(APPEND CTEST_SITE " (${DISTRO} ${CMAKE_SYSTEM_PROCESSOR})")
21-
else()
22-
cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME)
23-
cmake_host_system_information(RESULT OS_VERSION QUERY OS_VERSION)
24-
string(APPEND CTEST_SITE " (${OS_NAME} ${OS_VERSION} ${CMAKE_SYSTEM_PROCESSOR})")
25-
endif()
16+
if(EXISTS "/etc/os-release")
17+
file(STRINGS "/etc/os-release" OS_NAME REGEX "^ID=.*$")
18+
string(REGEX REPLACE "ID=[\"']?([^\"']*)[\"']?$" "\\1" OS_NAME "${OS_NAME}")
19+
file(STRINGS "/etc/os-release" OS_VERSION REGEX "^VERSION_ID=.*$")
20+
string(REGEX REPLACE "VERSION_ID=[\"']?([^\"'.]*).*$" "\\1" OS_VERSION "${OS_VERSION}")
21+
file(STRINGS "/etc/os-release" OS_FULL_NAME REGEX "^PRETTY_NAME=.*$")
22+
string(REGEX REPLACE "PRETTY_NAME=[\"']?([^\"']*)[\"']?$" "\\1" OS_FULL_NAME "${OS_FULL_NAME}")
23+
string(REGEX REPLACE "[ ]*\\(.*\\)" "" OS_FULL_NAME "${OS_FULL_NAME}")
24+
elseif(APPLE)
25+
set(OS_NAME "macOS")
26+
execute_process(COMMAND sw_vers -productVersion
27+
OUTPUT_VARIABLE OS_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
28+
set(OS_FULL_NAME "${OS_NAME} ${OS_VERSION}")
29+
else()
30+
cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME)
31+
cmake_host_system_information(RESULT OS_VERSION QUERY OS_VERSION)
32+
set(OS_FULL_NAME "${OS_NAME} ${OS_VERSION}")
2633
endif()
2734

2835
cmake_host_system_information(RESULT
@@ -38,18 +45,6 @@ if(NOT DEFINED ENV{CTEST_PARALLEL_LEVEL})
3845
set(ENV{CTEST_PARALLEL_LEVEL} ${NCORES})
3946
endif()
4047

41-
if(DEFINED ENV{CMAKE_GENERATOR})
42-
set(CTEST_CMAKE_GENERATOR $ENV{CMAKE_GENERATOR})
43-
else()
44-
execute_process(COMMAND ${CMAKE_COMMAND} --system-information
45-
OUTPUT_VARIABLE CMAKE_SYSTEM_INFORMATION ERROR_VARIABLE ERROR)
46-
if(ERROR)
47-
message(FATAL_ERROR "Could not detect default CMake generator")
48-
endif()
49-
string(REGEX REPLACE ".+CMAKE_GENERATOR \"([-0-9A-Za-z ]+)\".*$" "\\1"
50-
CTEST_CMAKE_GENERATOR "${CMAKE_SYSTEM_INFORMATION}")
51-
endif()
52-
5348
if(NOT DEFINED CTEST_CONFIGURATION_TYPE)
5449
if(DEFINED ENV{CMAKE_BUILD_TYPE})
5550
set(CTEST_CONFIGURATION_TYPE $ENV{CMAKE_BUILD_TYPE})
@@ -58,14 +53,6 @@ if(NOT DEFINED CTEST_CONFIGURATION_TYPE)
5853
endif()
5954
endif()
6055

61-
if(DEFINED CTEST_SCRIPT_ARG)
62-
set(TARGET_ISA ${CTEST_SCRIPT_ARG})
63-
else()
64-
set(TARGET_ISA Native)
65-
endif()
66-
67-
set(CTEST_BUILD_NAME "${CMAKE_SYSTEM_NAME}")
68-
6956
execute_process(COMMAND ${CMAKE_COMMAND} --system-information
7057
OUTPUT_VARIABLE CMAKE_SYSTEM_INFORMATION ERROR_VARIABLE ERROR)
7158

@@ -80,55 +67,211 @@ string(REPLACE "GNU" "GCC" COMPILER_ID "${COMPILER_ID}")
8067
string(REGEX REPLACE ".+CMAKE_CXX_COMPILER_VERSION \"([^\"]+)\".*$" "\\1"
8168
COMPILER_VERSION "${CMAKE_SYSTEM_INFORMATION}")
8269

70+
set(CTEST_BUILD_NAME "${OS_FULL_NAME}")
8371
string(APPEND CTEST_BUILD_NAME " ${COMPILER_ID} ${COMPILER_VERSION}")
8472
string(APPEND CTEST_BUILD_NAME " ${CTEST_CONFIGURATION_TYPE}")
85-
string(APPEND CTEST_BUILD_NAME " ${TARGET_ISA}")
73+
74+
if(DEFINED ENV{CMAKE_GENERATOR})
75+
set(CTEST_CMAKE_GENERATOR $ENV{CMAKE_GENERATOR})
76+
else()
77+
string(REGEX REPLACE ".+CMAKE_GENERATOR \"([-0-9A-Za-z ]+)\".*$" "\\1"
78+
CTEST_CMAKE_GENERATOR "${CMAKE_SYSTEM_INFORMATION}")
79+
endif()
80+
81+
if(NOT CTEST_CMAKE_GENERATOR MATCHES "Makefile")
82+
string(APPEND CTEST_BUILD_NAME " ${CTEST_CMAKE_GENERATOR}")
83+
endif()
84+
85+
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
86+
string(APPEND CTEST_BUILD_NAME " ${CMAKE_SYSTEM_PROCESSOR}")
87+
endif()
88+
89+
if(DEFINED ENV{GITHUB_ACTIONS})
90+
set(CTEST_SITE "GitHub Actions ($ENV{GITHUB_REPOSITORY_OWNER})")
91+
92+
if("$ENV{GITHUB_REPOSITORY_OWNER}" STREQUAL "root-project")
93+
set(CDASH TRUE)
94+
set(MODEL "Continuous")
95+
endif()
96+
97+
if("$ENV{GITHUB_EVENT_NAME}" MATCHES "pull_request")
98+
set(GROUP "Pull Requests")
99+
set(ENV{BASE_REF} $ENV{GITHUB_SHA}^1)
100+
set(ENV{HEAD_REF} $ENV{GITHUB_SHA}^2)
101+
string(REGEX REPLACE "/merge" "" PR_NUMBER "$ENV{GITHUB_REF_NAME}")
102+
string(PREPEND CTEST_BUILD_NAME "#${PR_NUMBER} ($ENV{GITHUB_ACTOR}) ")
103+
else()
104+
set(ENV{HEAD_REF} $ENV{GITHUB_SHA})
105+
string(APPEND CTEST_BUILD_NAME " ($ENV{GITHUB_REF_NAME})")
106+
endif()
107+
108+
if("$ENV{GITHUB_RUN_ATTEMPT}" GREATER 1)
109+
string(APPEND CTEST_BUILD_NAME " #$ENV{GITHUB_RUN_ATTEMPT}")
110+
endif()
111+
112+
macro(section title)
113+
message("::group::${title}")
114+
endmacro()
115+
116+
macro(endsection)
117+
message("::endgroup::")
118+
endmacro()
119+
else()
120+
macro(section title)
121+
endmacro()
122+
macro(endsection)
123+
endmacro()
124+
endif()
125+
126+
if(NOT DEFINED CTEST_SITE)
127+
site_name(CTEST_SITE)
128+
endif()
86129

87130
if(NOT DEFINED CTEST_SOURCE_DIRECTORY)
88-
set(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..")
131+
get_filename_component(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/.." REALPATH)
89132
endif()
90133

91134
if(NOT DEFINED CTEST_BINARY_DIRECTORY)
92-
get_filename_component(CTEST_BINARY_DIRECTORY "$ENV{PWD}/build" REALPATH)
135+
get_filename_component(CTEST_BINARY_DIRECTORY "build" REALPATH)
93136
endif()
94137

95-
if(EXISTS "${CTEST_BINARY_DIRECTORY}")
96-
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
138+
if(NOT DEFINED MODEL)
139+
set(MODEL Experimental)
140+
endif()
141+
142+
if(NOT DEFINED GROUP)
143+
set(GROUP ${MODEL})
144+
endif()
145+
146+
if(DEFINED CTEST_SCRIPT_ARG)
147+
set(TARGET_ISA ${CTEST_SCRIPT_ARG})
148+
else()
149+
set(TARGET_ISA Native)
150+
endif()
151+
152+
string(APPEND CTEST_BUILD_NAME " ${TARGET_ISA}")
153+
154+
set(CMAKE_ARGS $ENV{CMAKE_ARGS} ${CMAKE_ARGS})
155+
156+
if(COVERAGE)
157+
find_program(CTEST_COVERAGE_COMMAND NAMES gcov)
158+
list(PREPEND CMAKE_ARGS "-DCMAKE_C_FLAGS=--coverage -fprofile-update=atomic")
159+
list(PREPEND CMAKE_ARGS "-DCMAKE_CXX_FLAGS=--coverage -fprofile-update=atomic")
97160
endif()
98161

99162
if(MEMCHECK)
100163
find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind)
101164
endif()
102165

103-
set(CMAKE_ARGS
104-
-DBUILD_BENCHMARKS=ON
105-
-DBUILD_TESTING=ON
106-
-DBUILD_GOOGLETEST=ON
107-
-DBUILD_GOOGLEBENCH=ON
108-
-DBUILD_UMESIMD=${UNIX}
109-
-DBUILD_VC=${UNIX}
110-
-DCMAKE_DISABLE_FIND_PACKAGE_PkgConfig=${WIN32}
111-
-DTARGET_ISA=${TARGET_ISA}
112-
$ENV{CMAKE_ARGS}
113-
${CMAKE_ARGS}
114-
)
166+
if(STATIC_ANALYSIS)
167+
find_program(CMAKE_CXX_CLANG_TIDY NAMES clang-tidy)
168+
list(PREPEND CMAKE_ARGS "-DCMAKE_CXX_CLANG_TIDY=${CMAKE_CXX_CLANG_TIDY}")
169+
endif()
115170

116-
if(NOT DEFINED MODEL)
117-
set(MODEL Experimental)
171+
foreach(FILENAME ${OS_NAME}${OS_VERSION}.cmake ${OS_NAME}.cmake config.cmake)
172+
if(EXISTS "${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME}")
173+
message(STATUS "Using CMake cache file ${FILENAME}")
174+
list(PREPEND CMAKE_ARGS -C ${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME})
175+
list(APPEND CTEST_NOTES_FILES ${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME})
176+
break()
177+
endif()
178+
endforeach()
179+
180+
if(IS_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
181+
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
118182
endif()
119183

120184
ctest_read_custom_files("${CTEST_SOURCE_DIRECTORY}")
121185

122-
ctest_start(${MODEL})
123-
ctest_configure(OPTIONS "${CMAKE_ARGS}")
186+
if(IS_DIRECTORY ${CTEST_SOURCE_DIRECTORY}/.git)
187+
find_program(CTEST_GIT_COMMAND NAMES git)
188+
endif()
189+
190+
if(EXISTS "${CTEST_GIT_COMMAND}" AND DEFINED ENV{HEAD_REF} AND NOT DEFINED ENV{BASE_REF})
191+
set(CTEST_CHECKOUT_COMMAND
192+
"\"${CTEST_GIT_COMMAND}\" --git-dir \"${CTEST_SOURCE_DIRECTORY}/.git\" checkout -f $ENV{HEAD_REF}")
193+
endif()
194+
195+
ctest_start(${MODEL} GROUP "${GROUP}")
196+
197+
if(EXISTS "${CTEST_GIT_COMMAND}")
198+
if(DEFINED ENV{BASE_REF})
199+
execute_process(COMMAND ${CTEST_GIT_COMMAND} checkout -f $ENV{BASE_REF}
200+
WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY} ERROR_QUIET RESULT_VARIABLE GIT_STATUS)
201+
if(NOT ${GIT_STATUS} EQUAL 0)
202+
message(FATAL_ERROR "Could not checkout base ref: $ENV{BASE_REF}")
203+
endif()
204+
endif()
205+
if(DEFINED ENV{HEAD_REF})
206+
set(CTEST_GIT_UPDATE_CUSTOM
207+
${CTEST_GIT_COMMAND} --git-dir ${CTEST_SOURCE_DIRECTORY}/.git checkout -f $ENV{HEAD_REF})
208+
else()
209+
set(CTEST_GIT_UPDATE_CUSTOM ${CTEST_GIT_COMMAND} --git-dir ${CTEST_SOURCE_DIRECTORY}/.git diff)
210+
endif()
211+
212+
ctest_update()
213+
endif()
214+
215+
section("Configure")
216+
ctest_configure(OPTIONS "${CMAKE_ARGS}" RETURN_VALUE CONFIG_RESULT)
124217

125218
ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}")
126219
list(APPEND CTEST_NOTES_FILES ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt)
127220

128-
ctest_build()
129-
ctest_test()
130-
ctest_memcheck()
221+
if(NOT ${CONFIG_RESULT} EQUAL 0)
222+
if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}"))
223+
ctest_submit()
224+
endif()
225+
message(FATAL_ERROR "Configuration failed")
226+
endif()
227+
endsection()
228+
229+
section("Build")
230+
ctest_build(RETURN_VALUE BUILD_RESULT)
131231

132-
if(CDASH)
232+
if(NOT ${BUILD_RESULT} EQUAL 0)
233+
if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}"))
234+
ctest_submit()
235+
endif()
236+
message(FATAL_ERROR "Build failed")
237+
endif()
238+
239+
if(INSTALL)
240+
set(ENV{DESTDIR} "${CTEST_BINARY_DIRECTORY}/install")
241+
ctest_build(TARGET install)
242+
endif()
243+
endsection()
244+
245+
section("Test")
246+
ctest_test(PARALLEL_LEVEL $ENV{CTEST_PARALLEL_LEVEL} RETURN_VALUE TEST_RESULT)
247+
248+
if(NOT ${TEST_RESULT} EQUAL 0)
249+
message(SEND_ERROR "Tests failed")
250+
endif()
251+
endsection()
252+
253+
if(DEFINED CTEST_COVERAGE_COMMAND)
254+
section("Coverage")
255+
find_program(GCOVR NAMES gcovr)
256+
if(EXISTS ${GCOVR})
257+
execute_process(COMMAND
258+
${GCOVR} --gcov-executable ${CTEST_COVERAGE_COMMAND}
259+
-r ${CTEST_SOURCE_DIRECTORY} ${CTEST_BINARY_DIRECTORY}
260+
--html-details ${CTEST_BINARY_DIRECTORY}/coverage/ ERROR_VARIABLE ERROR)
261+
if(ERROR)
262+
message(SEND_ERROR "Failed to generate coverage report")
263+
endif()
264+
endif()
265+
ctest_coverage()
266+
endsection()
267+
endif()
268+
269+
if(DEFINED CTEST_MEMORYCHECK_COMMAND)
270+
section("Memcheck")
271+
ctest_memcheck()
272+
endsection()
273+
endif()
274+
275+
if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}"))
133276
ctest_submit()
134277
endif()

0 commit comments

Comments
 (0)