diff --git a/.ci/config.cmake b/.ci/config.cmake new file mode 100644 index 0000000000000000000000000000000000000000..bf59fdee6c3bd82f0cd257235cafc4c32456cb8f --- /dev/null +++ b/.ci/config.cmake @@ -0,0 +1,9 @@ +set(BUILD_BENCHMARKS 1 CACHE BOOL "") +set(BUILD_TESTING 1 CACHE BOOL "") +set(BUILD_GOOGLETEST 1 CACHE BOOL "") +set(BUILD_GOOGLEBENCH 1 CACHE BOOL "") +set(BUILD_UMESIMD ${UNIX} CACHE BOOL "") +set(BUILD_VC ${UNIX} CACHE BOOL "") +set(UMESIMD ${UNIX} CACHE BOOL "") +set(VC ${UNIX} CACHE BOOL "") +set(CMAKE_DISABLE_FIND_PACKAGE_PkgConfig ${WIN32} CACHE BOOL "") diff --git a/CMakeLists.txt b/CMakeLists.txt index 8307b936c227998260205008d0a48ef1155b9800..069a719c47cfd2b3fdf0c8e7a8f3578896e4937c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ if (BUILD_DOCS) add_subdirectory(doc) endif() +include(CTest) enable_testing() if (BUILD_TESTING) diff --git a/cmake/TestVecCore.cmake b/cmake/TestVecCore.cmake index 9ea6c80de1a6e40b690ef6735fdf1e3b78c14069..117f05c72033d5e8cf9fa0d9eba333b05619ca6b 100644 --- a/cmake/TestVecCore.cmake +++ b/cmake/TestVecCore.cmake @@ -1,9 +1,10 @@ -cmake_minimum_required(VERSION 3.16...3.25) +cmake_minimum_required(VERSION 3.16...3.29) set(CTEST_PROJECT_NAME "VecCore") set(ENV{LANG} "C") set(ENV{LC_ALL} "C") +set(CTEST_USE_LAUNCHERS TRUE) if(CDASH) set(CTEST_DROP_METHOD "http") @@ -12,17 +13,23 @@ if(CDASH) set(CTEST_DROP_SITE_CDASH TRUE) endif() -if(NOT DEFINED CTEST_SITE) - site_name(CTEST_SITE) - if(EXISTS "/etc/os-release") - file(STRINGS "/etc/os-release" OSPN REGEX "^PRETTY_NAME=.*$") - string(REGEX REPLACE "PRETTY_NAME=\"(.*)\"$" "\\1" DISTRO "${OSPN}") - string(APPEND CTEST_SITE " (${DISTRO} ${CMAKE_SYSTEM_PROCESSOR})") - else() - cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME) - cmake_host_system_information(RESULT OS_VERSION QUERY OS_VERSION) - string(APPEND CTEST_SITE " (${OS_NAME} ${OS_VERSION} ${CMAKE_SYSTEM_PROCESSOR})") - endif() +if(EXISTS "/etc/os-release") + file(STRINGS "/etc/os-release" OS_NAME REGEX "^ID=.*$") + string(REGEX REPLACE "ID=[\"']?([^\"']*)[\"']?$" "\\1" OS_NAME "${OS_NAME}") + file(STRINGS "/etc/os-release" OS_VERSION REGEX "^VERSION_ID=.*$") + string(REGEX REPLACE "VERSION_ID=[\"']?([^\"'.]*).*$" "\\1" OS_VERSION "${OS_VERSION}") + file(STRINGS "/etc/os-release" OS_FULL_NAME REGEX "^PRETTY_NAME=.*$") + string(REGEX REPLACE "PRETTY_NAME=[\"']?([^\"']*)[\"']?$" "\\1" OS_FULL_NAME "${OS_FULL_NAME}") + string(REGEX REPLACE "[ ]*\\(.*\\)" "" OS_FULL_NAME "${OS_FULL_NAME}") +elseif(APPLE) + set(OS_NAME "macOS") + execute_process(COMMAND sw_vers -productVersion + OUTPUT_VARIABLE OS_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + set(OS_FULL_NAME "${OS_NAME} ${OS_VERSION}") +else() + cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME) + cmake_host_system_information(RESULT OS_VERSION QUERY OS_VERSION) + set(OS_FULL_NAME "${OS_NAME} ${OS_VERSION}") endif() cmake_host_system_information(RESULT @@ -38,18 +45,6 @@ if(NOT DEFINED ENV{CTEST_PARALLEL_LEVEL}) set(ENV{CTEST_PARALLEL_LEVEL} ${NCORES}) endif() -if(DEFINED ENV{CMAKE_GENERATOR}) - set(CTEST_CMAKE_GENERATOR $ENV{CMAKE_GENERATOR}) -else() - execute_process(COMMAND ${CMAKE_COMMAND} --system-information - OUTPUT_VARIABLE CMAKE_SYSTEM_INFORMATION ERROR_VARIABLE ERROR) - if(ERROR) - message(FATAL_ERROR "Could not detect default CMake generator") - endif() - string(REGEX REPLACE ".+CMAKE_GENERATOR \"([-0-9A-Za-z ]+)\".*$" "\\1" - CTEST_CMAKE_GENERATOR "${CMAKE_SYSTEM_INFORMATION}") -endif() - if(NOT DEFINED CTEST_CONFIGURATION_TYPE) if(DEFINED ENV{CMAKE_BUILD_TYPE}) set(CTEST_CONFIGURATION_TYPE $ENV{CMAKE_BUILD_TYPE}) @@ -58,14 +53,6 @@ if(NOT DEFINED CTEST_CONFIGURATION_TYPE) endif() endif() -if(DEFINED CTEST_SCRIPT_ARG) - set(TARGET_ISA ${CTEST_SCRIPT_ARG}) -else() - set(TARGET_ISA Native) -endif() - -set(CTEST_BUILD_NAME "${CMAKE_SYSTEM_NAME}") - execute_process(COMMAND ${CMAKE_COMMAND} --system-information OUTPUT_VARIABLE CMAKE_SYSTEM_INFORMATION ERROR_VARIABLE ERROR) @@ -80,55 +67,211 @@ string(REPLACE "GNU" "GCC" COMPILER_ID "${COMPILER_ID}") string(REGEX REPLACE ".+CMAKE_CXX_COMPILER_VERSION \"([^\"]+)\".*$" "\\1" COMPILER_VERSION "${CMAKE_SYSTEM_INFORMATION}") +set(CTEST_BUILD_NAME "${OS_FULL_NAME}") string(APPEND CTEST_BUILD_NAME " ${COMPILER_ID} ${COMPILER_VERSION}") string(APPEND CTEST_BUILD_NAME " ${CTEST_CONFIGURATION_TYPE}") -string(APPEND CTEST_BUILD_NAME " ${TARGET_ISA}") + +if(DEFINED ENV{CMAKE_GENERATOR}) + set(CTEST_CMAKE_GENERATOR $ENV{CMAKE_GENERATOR}) +else() + string(REGEX REPLACE ".+CMAKE_GENERATOR \"([-0-9A-Za-z ]+)\".*$" "\\1" + CTEST_CMAKE_GENERATOR "${CMAKE_SYSTEM_INFORMATION}") +endif() + +if(NOT CTEST_CMAKE_GENERATOR MATCHES "Makefile") + string(APPEND CTEST_BUILD_NAME " ${CTEST_CMAKE_GENERATOR}") +endif() + +if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + string(APPEND CTEST_BUILD_NAME " ${CMAKE_SYSTEM_PROCESSOR}") +endif() + +if(DEFINED ENV{GITHUB_ACTIONS}) + set(CTEST_SITE "GitHub Actions ($ENV{GITHUB_REPOSITORY_OWNER})") + + if("$ENV{GITHUB_REPOSITORY_OWNER}" STREQUAL "root-project") + set(CDASH TRUE) + set(MODEL "Continuous") + endif() + + if("$ENV{GITHUB_EVENT_NAME}" MATCHES "pull_request") + set(GROUP "Pull Requests") + set(ENV{BASE_REF} $ENV{GITHUB_SHA}^1) + set(ENV{HEAD_REF} $ENV{GITHUB_SHA}^2) + string(REGEX REPLACE "/merge" "" PR_NUMBER "$ENV{GITHUB_REF_NAME}") + string(PREPEND CTEST_BUILD_NAME "#${PR_NUMBER} ($ENV{GITHUB_ACTOR}) ") + else() + set(ENV{HEAD_REF} $ENV{GITHUB_SHA}) + string(APPEND CTEST_BUILD_NAME " ($ENV{GITHUB_REF_NAME})") + endif() + + if("$ENV{GITHUB_RUN_ATTEMPT}" GREATER 1) + string(APPEND CTEST_BUILD_NAME " #$ENV{GITHUB_RUN_ATTEMPT}") + endif() + + macro(section title) + message("::group::${title}") + endmacro() + + macro(endsection) + message("::endgroup::") + endmacro() +else() + macro(section title) + endmacro() + macro(endsection) + endmacro() +endif() + +if(NOT DEFINED CTEST_SITE) + site_name(CTEST_SITE) +endif() if(NOT DEFINED CTEST_SOURCE_DIRECTORY) - set(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") + get_filename_component(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/.." REALPATH) endif() if(NOT DEFINED CTEST_BINARY_DIRECTORY) - get_filename_component(CTEST_BINARY_DIRECTORY "$ENV{PWD}/build" REALPATH) + get_filename_component(CTEST_BINARY_DIRECTORY "build" REALPATH) endif() -if(EXISTS "${CTEST_BINARY_DIRECTORY}") - ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}") +if(NOT DEFINED MODEL) + set(MODEL Experimental) +endif() + +if(NOT DEFINED GROUP) + set(GROUP ${MODEL}) +endif() + +if(DEFINED CTEST_SCRIPT_ARG) + set(TARGET_ISA ${CTEST_SCRIPT_ARG}) +else() + set(TARGET_ISA Native) +endif() + +string(APPEND CTEST_BUILD_NAME " ${TARGET_ISA}") + +set(CMAKE_ARGS $ENV{CMAKE_ARGS} ${CMAKE_ARGS}) + +if(COVERAGE) + find_program(CTEST_COVERAGE_COMMAND NAMES gcov) + list(PREPEND CMAKE_ARGS "-DCMAKE_C_FLAGS=--coverage -fprofile-update=atomic") + list(PREPEND CMAKE_ARGS "-DCMAKE_CXX_FLAGS=--coverage -fprofile-update=atomic") endif() if(MEMCHECK) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) endif() -set(CMAKE_ARGS - -DBUILD_BENCHMARKS=ON - -DBUILD_TESTING=ON - -DBUILD_GOOGLETEST=ON - -DBUILD_GOOGLEBENCH=ON - -DBUILD_UMESIMD=${UNIX} - -DBUILD_VC=${UNIX} - -DCMAKE_DISABLE_FIND_PACKAGE_PkgConfig=${WIN32} - -DTARGET_ISA=${TARGET_ISA} - $ENV{CMAKE_ARGS} - ${CMAKE_ARGS} -) +if(STATIC_ANALYSIS) + find_program(CMAKE_CXX_CLANG_TIDY NAMES clang-tidy) + list(PREPEND CMAKE_ARGS "-DCMAKE_CXX_CLANG_TIDY=${CMAKE_CXX_CLANG_TIDY}") +endif() -if(NOT DEFINED MODEL) - set(MODEL Experimental) +foreach(FILENAME ${OS_NAME}${OS_VERSION}.cmake ${OS_NAME}.cmake config.cmake) + if(EXISTS "${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME}") + message(STATUS "Using CMake cache file ${FILENAME}") + list(PREPEND CMAKE_ARGS -C ${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME}) + list(APPEND CTEST_NOTES_FILES ${CTEST_SOURCE_DIRECTORY}/.ci/${FILENAME}) + break() + endif() +endforeach() + +if(IS_DIRECTORY "${CTEST_BINARY_DIRECTORY}") + ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}") endif() ctest_read_custom_files("${CTEST_SOURCE_DIRECTORY}") -ctest_start(${MODEL}) -ctest_configure(OPTIONS "${CMAKE_ARGS}") +if(IS_DIRECTORY ${CTEST_SOURCE_DIRECTORY}/.git) + find_program(CTEST_GIT_COMMAND NAMES git) +endif() + +if(EXISTS "${CTEST_GIT_COMMAND}" AND DEFINED ENV{HEAD_REF} AND NOT DEFINED ENV{BASE_REF}) + set(CTEST_CHECKOUT_COMMAND + "\"${CTEST_GIT_COMMAND}\" --git-dir \"${CTEST_SOURCE_DIRECTORY}/.git\" checkout -f $ENV{HEAD_REF}") +endif() + +ctest_start(${MODEL} GROUP "${GROUP}") + +if(EXISTS "${CTEST_GIT_COMMAND}") + if(DEFINED ENV{BASE_REF}) + execute_process(COMMAND ${CTEST_GIT_COMMAND} checkout -f $ENV{BASE_REF} + WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY} ERROR_QUIET RESULT_VARIABLE GIT_STATUS) + if(NOT ${GIT_STATUS} EQUAL 0) + message(FATAL_ERROR "Could not checkout base ref: $ENV{BASE_REF}") + endif() + endif() + if(DEFINED ENV{HEAD_REF}) + set(CTEST_GIT_UPDATE_CUSTOM + ${CTEST_GIT_COMMAND} --git-dir ${CTEST_SOURCE_DIRECTORY}/.git checkout -f $ENV{HEAD_REF}) + else() + set(CTEST_GIT_UPDATE_CUSTOM ${CTEST_GIT_COMMAND} --git-dir ${CTEST_SOURCE_DIRECTORY}/.git diff) + endif() + + ctest_update() +endif() + +section("Configure") +ctest_configure(OPTIONS "${CMAKE_ARGS}" RETURN_VALUE CONFIG_RESULT) ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}") list(APPEND CTEST_NOTES_FILES ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt) -ctest_build() -ctest_test() -ctest_memcheck() +if(NOT ${CONFIG_RESULT} EQUAL 0) + if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}")) + ctest_submit() + endif() + message(FATAL_ERROR "Configuration failed") +endif() +endsection() + +section("Build") +ctest_build(RETURN_VALUE BUILD_RESULT) -if(CDASH) +if(NOT ${BUILD_RESULT} EQUAL 0) + if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}")) + ctest_submit() + endif() + message(FATAL_ERROR "Build failed") +endif() + +if(INSTALL) + set(ENV{DESTDIR} "${CTEST_BINARY_DIRECTORY}/install") + ctest_build(TARGET install) +endif() +endsection() + +section("Test") +ctest_test(PARALLEL_LEVEL $ENV{CTEST_PARALLEL_LEVEL} RETURN_VALUE TEST_RESULT) + +if(NOT ${TEST_RESULT} EQUAL 0) + message(SEND_ERROR "Tests failed") +endif() +endsection() + +if(DEFINED CTEST_COVERAGE_COMMAND) + section("Coverage") + find_program(GCOVR NAMES gcovr) + if(EXISTS ${GCOVR}) + execute_process(COMMAND + ${GCOVR} --gcov-executable ${CTEST_COVERAGE_COMMAND} + -r ${CTEST_SOURCE_DIRECTORY} ${CTEST_BINARY_DIRECTORY} + --html-details ${CTEST_BINARY_DIRECTORY}/coverage/ ERROR_VARIABLE ERROR) + if(ERROR) + message(SEND_ERROR "Failed to generate coverage report") + endif() + endif() + ctest_coverage() + endsection() +endif() + +if(DEFINED CTEST_MEMORYCHECK_COMMAND) + section("Memcheck") + ctest_memcheck() + endsection() +endif() + +if(CDASH OR (DEFINED ENV{CDASH} AND "$ENV{CDASH}")) ctest_submit() endif()