diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dccad1adaf2d9b05733c35d0165a8052cf35c1ef..69b00809c99a9893555fc7e61d45a4c4b427364f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,8 +52,10 @@ default: - .ccache .build-check: &template_build_check + variables: + LOG: build/build.log script: - - ci-utils/build-check build/build.log + - ci-utils/build-check ${LOG} allow_failure: true .test: &template_test @@ -77,6 +79,25 @@ default: when: always expire_in: 1 week +.test_headers: &template_test_headers + tags: + - cvmfs + script: + - export CCACHE_DIR=$PWD/.ccache_headers + - find build -type f -exec touch -d $(date +@%s) \{} \; # not to re-run cmake + - ccache -z + - cmake --build build --target test_public_headers_build 2>&1 | tee build/test_public_headers_build.log + - ccache -s + artifacts: + paths: + - build/test_public_headers_build.log + when: always + expire_in: 1 week + cache: + key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + paths: + - .ccache_headers + ### Build x86_64-centos7-gcc11-opt: @@ -135,12 +156,24 @@ x86_64-centos7-gcc11-opt:test: - job: "x86_64-centos7-gcc11-opt" artifacts: true +x86_64-centos7-gcc11-opt:test_headers: + <<: *template_test_headers + needs: + - job: "x86_64-centos7-gcc11-opt" + artifacts: true + x86_64-centos7-gcc11-dbg:test: <<: *template_test needs: - job: "x86_64-centos7-gcc11-dbg" artifacts: true +x86_64-centos7-gcc11-dbg:test_headers: + <<: *template_test_headers + needs: + - job: "x86_64-centos7-gcc11-dbg" + artifacts: true + view-gcc8:test: <<: *template_test needs: @@ -189,6 +222,22 @@ x86_64-centos7-gcc11-dbg:build-check: - job: "x86_64-centos7-gcc11-dbg" artifacts: true +x86_64-centos7-gcc11-opt:build-headers-check: + <<: *template_build_check + variables: + LOG: build/test_public_headers_build.log + needs: + - job: "x86_64-centos7-gcc11-opt:test_headers" + artifacts: true + +x86_64-centos7-gcc11-dbg:build-headers-check: + <<: *template_build_check + variables: + LOG: build/test_public_headers_build.log + needs: + - job: "x86_64-centos7-gcc11-dbg:test_headers" + artifacts: true + view-gcc8:build-check: <<: *template_build_check needs: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8923c373c27bbeca3cfbd9c0108a5158efe1628f..959b0e6ee4a559a61f9d49e7edb885209fce5c18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,7 @@ install(EXPORT ${PROJECT_NAME} NAMESPACE ${PROJECT_NAME}:: DESTINATION "${GAUDI_INSTALL_CONFIGDIR}") # Install cmake files for downstream project to be able to use Gaudi gaudi_install(CMAKE cmake/GaudiToolbox.cmake + cmake/header_build_test.tpl cmake/GaudiDependencies.cmake cmake/DeveloperBuildType.cmake "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" diff --git a/cmake/GaudiToolbox.cmake b/cmake/GaudiToolbox.cmake index 47b7170fa66b64ea2994e39ba21595f15c8f1efb..7e4e5aae74a62203576a130789e7c00e2b601ef2 100644 --- a/cmake/GaudiToolbox.cmake +++ b/cmake/GaudiToolbox.cmake @@ -91,6 +91,8 @@ Functions include_guard(GLOBAL) # Protect from multiple include (global scope, because # everything defined in this file is globally visible) +set(GAUDI_TOOLBOX_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Directory containing this file") + ################################ Global options ################################ # Option used to know if the install() function must be called with OPTIONAL @@ -110,6 +112,10 @@ endif() # Option to prefer local targets to imported ones option(GAUDI_PREFER_LOCAL_TARGETS "Prefer local targets over imported ones" FALSE) +option(GAUDI_TEST_PUBLIC_HEADERS_BUILD + "Execute a test build of all public headers in the global target 'all'" + FALSE) + # Default layout fo the installation (may be overridden in the cache) set(CMAKE_INSTALL_BINDIR "bin" CACHE STRING "Install executable in <prefix>/\${CMAKE_INSTALL_BINDIR}") set(CMAKE_INSTALL_LIBDIR "lib" CACHE STRING "Install libraries in <prefix>/\${CMAKE_INSTALL_LIBDIR}") @@ -118,7 +124,7 @@ set(GAUDI_INSTALL_PLUGINDIR "${CMAKE_INSTALL_LIBDIR}" CACHE STRING "Install plug set(GAUDI_INSTALL_PYTHONDIR "python" CACHE STRING "Install python packages in <prefix>/\${GAUDI_INSTALL_PYTHONDIR}") set(GAUDI_INSTALL_CONFIGDIR "lib/cmake/${PROJECT_NAME}" CACHE STRING "Install cmake files in <prefix>/\${GAUDI_INSTALL_CONFIGDIR}") -set(scan_dict_deps_command ${CMAKE_CURRENT_LIST_DIR}/scan_dict_deps.py +set(scan_dict_deps_command ${GAUDI_TOOLBOX_DIR}/scan_dict_deps.py CACHE INTERNAL "command to use to scan dependencies of dictionary headers") ################################## Functions ################################## @@ -152,6 +158,60 @@ macro(_gaudi_runtime_append runtime value) set_property(TARGET target_runtime_paths APPEND PROPERTY runtime_${runtime} ${value}) endmacro() +# Helper function to add build test for every public header +function(_test_build_public_headers lib_name) + if(NOT BUILD_TESTING) + # we test the build of the public headers only when tests are enabled + return() + endif() + # collect the list of public headers + file(GLOB_RECURSE headers + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hxx + ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp + ) + # list the test source files generated (in a previous config) + file(GLOB_RECURSE old_srcs + ${CMAKE_CURRENT_BINARY_DIR}/headers_build_test/*.h.cpp + ${CMAKE_CURRENT_BINARY_DIR}/headers_build_test/*.hxx.cpp + ${CMAKE_CURRENT_BINARY_DIR}/headers_build_test/*.hpp.cpp + ) + set(srcs) + if(headers) + # create a cpp file for each header file to test + foreach(header IN LISTS headers) + set(s "${CMAKE_CURRENT_BINARY_DIR}/headers_build_test/${header}.cpp") + configure_file("${GAUDI_TOOLBOX_DIR}/header_build_test.tpl" "${s}") + list(APPEND srcs "${s}") + endforeach() + # create an object library (we never need to use the product) + add_library(test_public_headers_build_${lib_name} OBJECT EXCLUDE_FROM_ALL ${srcs}) + target_link_libraries(test_public_headers_build_${lib_name} + PRIVATE ${lib_name}) + target_compile_definitions(test_public_headers_build_${lib_name} + PRIVATE GAUDI_TEST_PUBLIC_HEADERS_BUILD) + # add it to the global target "test_public_headers_build" (making sure it exists) + if(NOT TARGET test_public_headers_build) + if(GAUDI_TEST_PUBLIC_HEADERS_BUILD) + add_custom_target(test_public_headers_build ALL + COMMENT "test build of public headers") + else() + add_custom_target(test_public_headers_build + COMMENT "test build of public headers") + endif() + endif() + add_dependencies(test_public_headers_build test_public_headers_build_${lib_name}) + # keep in old_srcs only the source files not needed anymore + list(REMOVE_ITEM old_srcs ${srcs}) + endif() + # remove stale test source files + if(old_srcs) + file(REMOVE ${old_srcs}) + endif() +endfunction() + #[========================================================================[.rst: .. command:: gaudi_add_library @@ -216,6 +276,7 @@ function(gaudi_add_library lib_name) install(DIRECTORY include/ TYPE INCLUDE) set_property(DIRECTORY PROPERTY include_installed TRUE) + _test_build_public_headers(${lib_name}) endif() # Runtime ROOT_INCLUDE_PATH _gaudi_runtime_append(root_include_path $<TARGET_PROPERTY:${lib_name},INTERFACE_INCLUDE_DIRECTORIES>) @@ -287,6 +348,7 @@ function(gaudi_add_header_only_library lib_name) install(DIRECTORY include/ TYPE INCLUDE) set_property(DIRECTORY PROPERTY include_installed TRUE) + _test_build_public_headers(${lib_name}) endif() # Runtime ROOT_INCLUDE_PATH _gaudi_runtime_append(root_include_path $<TARGET_PROPERTY:${lib_name},INTERFACE_INCLUDE_DIRECTORIES>) diff --git a/cmake/header_build_test.tpl b/cmake/header_build_test.tpl new file mode 100644 index 0000000000000000000000000000000000000000..6c200e893f0130704e134a415fd59d4fd7f3a675 --- /dev/null +++ b/cmake/header_build_test.tpl @@ -0,0 +1 @@ +#include <${header}>