Install a software bill of materials The license obligations of a Ceres build depend on the optional dependencies it links against. Notices in the license file or in the configuration output have been suggested to convey these obligations, but such notices cannot be processed by license compliance tooling. A software bill of materials in the standard SPDX format is the established means for this purpose. Install an SPDX SBOM describing the package, its license and the linked libraries when CMake supports it. SBOM generation rejects generator expressions in link libraries, so the Abseil linkage is resolved at configure time and the SBOM is skipped if a static Abseil still requires one. Change-Id: Idf175a1d75f2cba4921461dd6efddc02e1b70b1f
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e81b77..6911897 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -31,6 +31,24 @@ cmake_minimum_required(VERSION 3.22...4.4) +# Opt into the experimental software bill of materials (SBOM) generation. +# CMake enables an experimental feature only if its gate variable is set to a +# specific UUID. The UUID acknowledges that the feature is unstable and may +# change with every CMake release. The values used here are documented in the +# corresponding CMake sources: +# +# https://gitlab.kitware.com/cmake/cmake/-/blob/v4.3.5/Help/dev/experimental.rst +# https://gitlab.kitware.com/cmake/cmake/-/blob/v4.4.4/Help/dev/experimental.rst +if (CMAKE_VERSION VERSION_GREATER_EQUAL 4.3) + if (CMAKE_VERSION VERSION_LESS 4.4) + set(CMAKE_EXPERIMENTAL_GENERATE_SBOM + ca494ed3-b261-4205-a01f-603c95e4cae0) + else (CMAKE_VERSION VERSION_LESS 4.4) + set(CMAKE_EXPERIMENTAL_GENERATE_SBOM + 2d856d6d-53e8-488b-a17f-d486d2cac317) + endif (CMAKE_VERSION VERSION_LESS 4.4) +endif (CMAKE_VERSION VERSION_GREATER_EQUAL 4.3) + # NOTE: The 'generic' CMake variables CMAKE_[SOURCE/BINARY]_DIR should not be # used. Always use the project-specific variants (generated by CMake): # <PROJECT_NAME_MATCHING_CASE>_[SOURCE/BINARY]_DIR, e.g. @@ -687,6 +705,15 @@ install(FILES ${_Ceres_CONFIG_DEPENDENCY_MODULES} DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR}) endif() + +# The license of the installed package covers the Ceres sources and the +# installed find modules, but not the dependencies which are licensed +# separately. +set(_Ceres_SPDX_LICENSE BSD-3-Clause) +if ("${Ceres_SOURCE_DIR}/cmake/FindMETIS.cmake" IN_LIST + _Ceres_CONFIG_DEPENDENCY_MODULES) + string(APPEND _Ceres_SPDX_LICENSE " AND MIT") +endif() unset(_Ceres_CONFIG_DEPENDENCY_MODULES) unset(_Ceres_FIND_MODULE) unset(_Ceres_FIND_MODULE_LINK_RESULT) @@ -729,6 +756,77 @@ install(FILES "${Ceres_BINARY_DIR}/CeresConfigVersion.cmake" DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR}) +set_property(TARGET ceres PROPERTY SPDX_LICENSE BSD-3-Clause) + +if (TARGET ceres_cuda_kernels) + set_property(TARGET ceres_cuda_kernels PROPERTY SPDX_LICENSE BSD-3-Clause) +endif (TARGET ceres_cuda_kernels) + +# SBOM generation fails for targets whose link libraries contain generator +# expressions, such as the whole archive linkage of a static Abseil. +set(_Ceres_SBOM_SUPPORTED OFF) + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 4.3 + AND CMAKE_EXPERIMENTAL_GENERATE_SBOM) + set(_Ceres_SBOM_SUPPORTED ON) + + foreach (_Ceres_TARGET IN ITEMS ceres ceres_cuda_kernels) + if (NOT TARGET ${_Ceres_TARGET}) + continue() + endif (NOT TARGET ${_Ceres_TARGET}) + + get_target_property(_Ceres_LINK_LIBRARIES ${_Ceres_TARGET} LINK_LIBRARIES) + + if (_Ceres_LINK_LIBRARIES MATCHES "\\$<") + message(WARNING "Skipping SBOM generation because the link libraries " + "of target ${_Ceres_TARGET} contain generator expressions: " + "${_Ceres_LINK_LIBRARIES}") + set(_Ceres_SBOM_SUPPORTED OFF) + endif (_Ceres_LINK_LIBRARIES MATCHES "\\$<") + endforeach (_Ceres_TARGET IN ITEMS ceres ceres_cuda_kernels) + + unset(_Ceres_LINK_LIBRARIES) + unset(_Ceres_TARGET) +endif (CMAKE_VERSION VERSION_GREATER_EQUAL 4.3 + AND CMAKE_EXPERIMENTAL_GENERATE_SBOM) + +if (_Ceres_SBOM_SUPPORTED) + set(_Ceres_SBOM_ARGUMENTS + PROJECT Ceres + DESTINATION ${CMAKE_INSTALL_DATADIR}/sbom + VERSION ${CERES_VERSION} + LICENSE ${_Ceres_SPDX_LICENSE} + DESCRIPTION "${PROJECT_DESCRIPTION}" + HOMEPAGE_URL ${PROJECT_HOMEPAGE_URL} + FORMAT spdx-3.0+json + ) + + if (CMAKE_VERSION VERSION_GREATER_EQUAL 4.4) + # The experimental SBOM support is enabled deliberately. Silence the + # corresponding warning for this command only. + block(SCOPE_FOR DIAGNOSTICS) + cmake_diagnostic(SET CMD_EXPERIMENTAL IGNORE) + install(SBOM Ceres + EXPORTS CeresExport + PACKAGE_URL https://github.com/ceres-solver/ceres-solver + ${_Ceres_SBOM_ARGUMENTS} + ) + endblock() + else (CMAKE_VERSION VERSION_GREATER_EQUAL 4.4) + # CMake 4.3 provides no means to silence the warning from within the + # project. Users can pass -Wno-dev instead. + install(SBOM Ceres + EXPORT CeresExport + ${_Ceres_SBOM_ARGUMENTS} + ) + endif (CMAKE_VERSION VERSION_GREATER_EQUAL 4.4) + + unset(_Ceres_SBOM_ARGUMENTS) +endif (_Ceres_SBOM_SUPPORTED) + +unset(_Ceres_SBOM_SUPPORTED) +unset(_Ceres_SPDX_LICENSE) + if (WITH_UNINSTALL_TARGET) # Create an uninstall target to remove all installed files. configure_file("${Ceres_SOURCE_DIR}/cmake/uninstall.cmake.in"
diff --git a/docs/source/version_history.rst b/docs/source/version_history.rst index 8f37367..7217e5e 100644 --- a/docs/source/version_history.rst +++ b/docs/source/version_history.rst
@@ -51,6 +51,11 @@ #. Move C++17 Bessel functions availability checks from configuration time to inclusion time, with fallback to POSIX implementations on ``libc++``. (Sergiu Deitsch) +#. Install a software bill of materials (SBOM) in the `SPDX + <https://spdx.dev/>`_ format describing the package, its license, and the + libraries it links against when using CMake 4.3 or later. The SBOM is not + generated if a static Abseil requires whole archive linkage. (Sergiu + Deitsch) Backward Incompatible API Changes
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index 4b28ae1..de2261e 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt
@@ -40,9 +40,17 @@ list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES absl::log_flags) else() # Apply $<LINK_LIBRARY:...> generator expression only if the corresponding - # target is a static library. Otherwise link only to the target. - list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES - $<IF:$<STREQUAL:$<TARGET_PROPERTY:absl::log_flags,TYPE>,STATIC_LIBRARY>,$<LINK_LIBRARY:WHOLE_ARCHIVE,absl::log_flags>,absl::log_flags>) + # target is a static library. Otherwise link only to the target. The library + # type is determined at configure time because SBOM generation does not + # support generator expressions in link libraries. + get_target_property(_Ceres_ABSL_LOG_FLAGS_TYPE absl::log_flags TYPE) + if (_Ceres_ABSL_LOG_FLAGS_TYPE STREQUAL STATIC_LIBRARY) + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES + $<LINK_LIBRARY:WHOLE_ARCHIVE,absl::log_flags>) + else() + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES absl::log_flags) + endif() + unset(_Ceres_ABSL_LOG_FLAGS_TYPE) endif() list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES absl::strings)