Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Generate a target for checking package dependencies #316

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions modules/InstallBasicPackageFiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES]
# [DEPENDENCIES <dependency1> "<dependency2> [...]" ...]
# [PRIVATE_DEPENDENCIES <dependency1> "<dependency2> [...]" ...]
# [NO_PACKAGE_DEPENDENCIES_CHECK]
# [INCLUDE_FILE <file> | INCLUDE_CONTENT <content>]
# [COMPONENT <component>] # (default = "<Name>")
# )
Expand Down Expand Up @@ -59,6 +60,13 @@
# argument, since the ``PRIVATE_DEPENDENCIES`` argument would work only when
# :variable:`BUILD_SHARED_LIBS` is disabled.
#
# If an export set is installed, and if testing is enabled (cf.
# :cmake:command:`enable_testing`), an extra target
# ``check-package-dependencies`` is generated which fails to build if one of
# the exported targets has a dependency which is not listed among
# ``DEPENDENCIES`` or ``PRIVATE_DEPENDENCIES``. This check can be suppressed
# by setting the ``NO_PACKAGE_DEPENDENCIES_CHECK`` option.
#
# When using a custom template file, the ``@PACKAGE_DEPENDENCIES@``
# string is replaced with the code checking for the dependencies
# specified by these two argument.
Expand Down Expand Up @@ -239,6 +247,7 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name)
NO_EXPORT
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
NO_PACKAGE_DEPENDENCIES_CHECK
UPPERCASE_FILENAMES
LOWERCASE_FILENAMES
NO_COMPATIBILITY_VARS # Deprecated
Expand Down Expand Up @@ -670,6 +679,84 @@ ${_compatibility_vars}
export(${_export_cmd}
NAMESPACE ${_IBPF_NAMESPACE}
FILE "${_IBPF_EXPORT_DESTINATION}/${_targets_filename}")

# To validate package dependencies, generate a subproject which consumes our build directory as a package
# and defines an executable target which links to all targets our package exports. Then bind the subproject
# to a target using `ExternalProject_Add()`.

# In order to reuse the same compiler toolchain for the subproject, we need to pick a language that is supported
# by the toolchain.
get_property(_enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
if("CXX" IN_LIST _enabled_languages)
set(_probe_lang "CXX")
set(_probe_lang_ext ".cpp")
elseif("C" IN_LIST _enabled_languages)
set(_probe_lang "C")
set(_probe_lang_ext ".c")
elseif("Fortran" IN_LIST _enabled_languages)
set(_probe_lang "Fortran")
set(_probe_lang_ext ".f77")
elseif("CUDA" IN_LIST _enabled_languages)
set(_probe_lang "CUDA")
set(_probe_lang_ext ".cu")
elseif("CSharp" IN_LIST _enabled_languages)
set(_probe_lang "CSharp")
set(_probe_lang_ext ".cs")
elseif("OBJC" IN_LIST _enabled_languages)
set(_probe_lang "OBJC")
set(_probe_lang_ext ".m")
elseif("OBJCPP" IN_LIST _enabled_languages)
set(_probe_lang "OBJCPP")
set(_probe_lang_ext ".mm")
elseif("Swift" IN_LIST _enabled_languages)
set(_probe_lang "Swift")
set(_probe_lang_ext ".swift")
elseif("ASM" IN_LIST _enabled_languages)
set(_probe_lang "ASM")
set(_probe_lang_ext ".asm")
elseif(NOT _IBPF_NO_PACKAGE_DEPENDENCIES_CHECK)
message(AUTHOR_WARNING "No known language is available; cannot check package dependencies")
set(_IBPF_NO_PACKAGE_DEPENDENCIES_CHECK TRUE)
endif()

# Only check the package dependencies if testing was previously enabled with a call to `enable_testing()`, and
# if `NO_PACKAGE_DEPENDENCIES_CHECK` was not set.
if(CMAKE_TESTING_ENABLED AND NOT _IBPF_NO_PACKAGE_DEPENDENCIES_CHECK)

# Generate an empty source file; the subproject is only configured, never built.
file(WRITE "${_IBPF_EXPORT_DESTINATION}/check-package-dependencies/main${_probe_lang_ext}" "")

# Generate the subproject definition file: a project with a single executable target that links all exported
# targets. Unfortunately CMake doesn't currently support enumerating the targets in an export set (cf.
# https://gitlab.kitware.com/cmake/cmake/issues/19333), hence we parse the targets file generated by CMake
# for `add_library(<target> ... IMPORTED)` statements. Note that this needs to be done in the subproject
# because CMake writes the targets file only *after* the current CMake script has been processed.
file(WRITE "${_IBPF_EXPORT_DESTINATION}/check-package-dependencies/CMakeLists.txt"
"cmake_minimum_required(VERSION 3.12)
project(${_Name}-check-package-dependencies LANGUAGES ${_probe_lang})
find_package(${_Name} ${_IBPF_VERSION} EXACT REQUIRED CONFIG)
add_executable(${_Name}-check-package-dependencies \"main${_probe_lang_ext}\")
list(INSERT CMAKE_MODULE_PATH 0 \"${_IBPF_EXPORT_DESTINATION}\")
file(STRINGS \"${_IBPF_EXPORT_DESTINATION}/${_targets_filename}\" _imported_targets)
foreach(_target \${_imported_targets})
if(_target MATCHES \"^[ ]*add_library\\\\(([A-Za-z:_-][A-Za-z0-9:_-]*) .* IMPORTED([ ]*)\\\\)[ ]*$\")
target_link_libraries(${_Name}-check-package-dependencies PRIVATE \${CMAKE_MATCH_1})
endif()
endforeach()")

# There is no `CONFIG_ALWAYS` argument for `ExternalProject_Add()`. But `ExternalProject_Add()` will re-run
# the configuration if any of the config arguments changes, so we force a new configuration run by passing
# a timestamp as an argument.
string(TIMESTAMP _timestamp UTC)

include(ExternalProject)
ExternalProject_Add(check-package-dependencies
SOURCE_DIR "${_IBPF_EXPORT_DESTINATION}/check-package-dependencies"
BINARY_DIR "${_IBPF_EXPORT_DESTINATION}/check-package-dependencies/build"
CMAKE_ARGS "--no-warn-unused-cli -D_ibpf_timestamp=${_timestamp}"
BUILD_COMMAND "" # never build
INSTALL_COMMAND "") # never install
endif()
endif()

# Export build directory if CMAKE_EXPORT_PACKAGE_REGISTRY is set.
Expand Down