Skip to content

Commit

Permalink
Extend rapids_export to support the concept of optional COMPONENTS
Browse files Browse the repository at this point in the history
rapids_export via the COMPONENTS and COMPONENTS_EXPORT_SET commands
can now generate find modules that have optional components.
  • Loading branch information
robertmaynard committed Jan 17, 2023
1 parent e988663 commit 9879c20
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 14 deletions.
75 changes: 75 additions & 0 deletions rapids-cmake/export/detail/component.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#=============================================================================
# Copyright (c) 2022-2023, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include_guard(GLOBAL)

#[=======================================================================[.rst:
rapids_export_component
-----------------------
.. versionadded:: v22.04.00
.. code-block:: cmake
Generate the necessary -Config.cmake modules needed for an optional component
of a rapids export package.
rapids_export_component( (BUILD|INSTALL) <project_name> <component_name> <export_set> <namespace>)
The :cmake:command:`rapids_export_component` function generates
the `<proj>-<comp>-targets.cmake` and `<proj>-<comp>-dependencies.cmake`
files necessary for :cmake:command:`rapids_export` to support optional
components.
.. note::
It is an anti-pattern to use this function directly. The vast majority of projects
would use :cmake:command:`rapids_export`
#]=======================================================================]
# cmake-lint: disable=W0105
function(rapids_export_component type project_name component_name export_set namespace)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.export.rapids_export_component")

string(TOLOWER ${type} type)

set(deps_destination)
if(type STREQUAL "install")
include("${rapids-cmake-dir}/cmake/install_lib_dir.cmake")
rapids_cmake_install_lib_dir(install_location)
set(install_location "${install_location}/cmake/${project_name}")

set(deps_destination "${PROJECT_BINARY_DIR}/rapids-cmake/${project_name}/export")

install(EXPORT ${export_set} FILE ${project_name}-${component_name}-targets.cmake
NAMESPACE ${namespace} DESTINATION "${install_location}")

else()
set(install_location "${PROJECT_BINARY_DIR}")
set(deps_destination "${install_location}/")

export(EXPORT ${export_set} NAMESPACE ${namespace}
FILE "${install_location}/${project_name}-${component_name}-targets.cmake")

endif()

if(TARGET rapids_export_${type}_${export_set})
include("${rapids-cmake-dir}/export/write_dependencies.cmake")
rapids_export_write_dependencies(
${type} ${export_set}
"${deps_destination}/${project_name}-${component_name}-dependencies.cmake")
endif()

endfunction()
49 changes: 46 additions & 3 deletions rapids-cmake/export/export.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Generate a projects -Config.cmake module and all related information
rapids_export( (BUILD|INSTALL) <project_name>
EXPORT_SET <export_set>
[ GLOBAL_TARGETS <targets...> ]
[ COMPONENTS <components...> ]
[ COMPONENTS_EXPORT_SET <component 1 export set, component 2 export set...> ]
[ VERSION <X.Y.Z> ]
[ NAMESPACE <name_space> ]
[ DOCUMENTATION <doc_variable> ]
Expand All @@ -50,6 +52,30 @@ calls to :cmake:command:`find_dependency`, or :cmake:command:`CPMFindPackage`.
Explicitly list what targets should be made globally visible to
the consuming project.
``COMPONENTS``
.. versionadded:: v22.04.00
A list of the optional `COMPONENTS` that are offered by this exported
package. The names listed here will be what consumers calling
:cmake:command:`find_package` will use to enable these components.
For each entry in `COMPONENTS` it is required to have an entry in
`COMPONENTS_EXPORT_SET` at the same positional location.
-> COMPONENTS A B
-> COMPONENTS A-export B-export
This is needed so that :cmake:command:`rapids_export` can correctly
establish the dependency and import target information for each
component.
``COMPONENTS_EXPORT_SET``
.. versionadded:: v22.04.00
A list of the associated export set for each optional `COMPONENT`.
Each entry in `COMPONENTS_EXPORT_SET` is associated to the component
as the same position in the `COMPONENTS` list.
``VERSION``
Explicitly list the version of the package being exported. By
default :cmake:command:`rapids_export` uses the version specified by the
Expand Down Expand Up @@ -159,9 +185,13 @@ function(rapids_export type project_name)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.export.export")
string(TOLOWER ${type} type)

set(project_name_orig ${project_name})
string(TOLOWER ${project_name} project_name)
string(TOUPPER ${project_name} project_name_uppercase)

set(options "")
set(one_value EXPORT_SET VERSION NAMESPACE DOCUMENTATION FINAL_CODE_BLOCK)
set(multi_value GLOBAL_TARGETS LANGUAGES)
set(multi_value GLOBAL_TARGETS COMPONENTS COMPONENTS_EXPORT_SET LANGUAGES)
cmake_parse_arguments(_RAPIDS "${options}" "${one_value}" "${multi_value}" ${ARGN})

set(rapids_version_set ON)
Expand All @@ -187,6 +217,21 @@ function(rapids_export type project_name)
set(_RAPIDS_PROJECT_NAMESPACE ${_RAPIDS_NAMESPACE})
endif()

if(_RAPIDS_COMPONENTS AND NOT _RAPIDS_COMPONENTS_EXPORT_SET)
message(FATAL_ERROR "rapids_export(${type} ${project_name} is missing COMPONENTS_EXPORT_SET as COMPONENTS was provided."
)
endif()
if(_RAPIDS_COMPONENTS_EXPORT_SET AND NOT _RAPIDS_COMPONENTS)
message(FATAL_ERROR "rapids_export(${type} ${project_name} is missing COMPONENTS as COMPONENTS_EXPORT_SET was provided."
)
endif()

include("${rapids-cmake-dir}/export/detail/component.cmake")
foreach(comp comp_export_set IN ZIP_LISTS _RAPIDS_COMPONENTS _RAPIDS_COMPONENTS_EXPORT_SET)
rapids_export_component(${type} ${project_name} ${comp} ${comp_export_set}
${_RAPIDS_PROJECT_NAMESPACE})
endforeach()

set(_RAPIDS_PROJECT_DOCUMENTATION "Generated ${project_name}-config module")
if(DEFINED _RAPIDS_DOCUMENTATION)
if(NOT DEFINED ${_RAPIDS_DOCUMENTATION})
Expand All @@ -203,8 +248,6 @@ function(rapids_export type project_name)
endif()

# Write configuration and version files
string(TOLOWER ${project_name} project_name)
string(TOUPPER ${project_name} project_name_uppercase)
if(type STREQUAL "install")
include("${rapids-cmake-dir}/cmake/install_lib_dir.cmake")
rapids_cmake_install_lib_dir(install_location)
Expand Down
30 changes: 20 additions & 10 deletions rapids-cmake/export/template/config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,26 @@ foreach(lang IN LISTS rapids_global_languages)
endforeach()
unset(rapids_global_languages)

if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@project_name@-dependencies.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-dependencies.cmake")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-dependencies.cmake" OPTIONAL)

set(rapids_allowed_components @_RAPIDS_COMPONENTS@)
foreach(comp IN LISTS rapids_allowed_components)
# find dependencies before creating targets that use them
# this way if a dependency can't be found we fail
if(${comp} IN_LIST @project_name@_FIND_COMPONENTS)
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-${comp}-dependencies.cmake" OPTIONAL)
endif()
endforeach()

if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@project_name@-targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-targets.cmake")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-targets.cmake" OPTIONAL)
foreach(comp IN LISTS rapids_allowed_components)
if(${comp} IN_LIST @project_name@_FIND_COMPONENTS)
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-${comp}-targets.cmake" OPTIONAL)
set(@project_name@_${comp}_FOUND TRUE)
endif()
endforeach()

if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@project_name@-config-version.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-config-version.cmake")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@project_name@-config-version.cmake" OPTIONAL)

# Set our version variables
set(@project_name_uppercase@_VERSION_MAJOR @rapids_orig_major_version@)
Expand All @@ -62,7 +71,7 @@ set(@project_name_uppercase@_VERSION @rapids_orig_version@)
set(rapids_global_targets @_RAPIDS_GLOBAL_TARGETS@)
set(rapids_namespaced_global_targets @_RAPIDS_GLOBAL_TARGETS@)
if(rapids_namespaced_global_targets)
list(TRANSFORM rapids_namespaced_global_targets PREPEND @_RAPIDS_NAMESPACE@ )
list(TRANSFORM rapids_namespaced_global_targets PREPEND @_RAPIDS_PROJECT_NAMESPACE@ )
endif()

foreach(target IN LISTS rapids_namespaced_global_targets)
Expand Down Expand Up @@ -91,6 +100,7 @@ if("rapids_config_@type@" STREQUAL "rapids_config_build")
endforeach()
endif()

unset(rapids_allowed_components)
unset(rapids_global_targets)
unset(rapids_namespaced_global_targets)

Expand Down
8 changes: 7 additions & 1 deletion testing/export/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#=============================================================================
# Copyright (c) 2021, NVIDIA CORPORATION.
# Copyright (c) 2021-2023, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -20,12 +20,16 @@ add_cmake_config_test( export_cpm-build.cmake )
add_cmake_config_test( export_cpm-install.cmake )
add_cmake_config_test( export_cpm-options-escaped.cmake )

add_cmake_build_test( export-verify-build-components-targets )
add_cmake_build_test( export-verify-build-components-dependencies )
add_cmake_build_test( export-verify-build-namespaces )
add_cmake_build_test( export-verify-code-block )
add_cmake_build_test( export-verify-doc-string )
add_cmake_build_test( export-verify-global-targets )

add_cmake_config_test( export-verify-bad-code-block-var.cmake SHOULD_FAIL "FINAL_CODE_BLOCK variable `var_doesn't_exist` doesn't exist")
add_cmake_config_test( export-verify-missing-components.cmake SHOULD_FAIL "is missing COMPONENTS as COMPONENTS_EXPORT_SET was provided")
add_cmake_config_test( export-verify-missing-components-export.cmake SHOULD_FAIL "is missing COMPONENTS_EXPOR22T_SET as COMPONENTS was provided")
add_cmake_config_test( export-verify-bad-doc-var.cmake SHOULD_FAIL "DOCUMENTATION variable `var_doesn't_exist` doesn't exist")
add_cmake_config_test( export-verify-calendar-version-matching.cmake )
add_cmake_config_test( export-verify-explicit-disabled-version.cmake )
Expand All @@ -38,6 +42,8 @@ add_cmake_config_test( export-verify-implicit-disabled-version.cmake )
add_cmake_config_test( export-verify-implicit-major-version-only-matching.cmake )
add_cmake_config_test( export-verify-version.cmake )

add_cmake_config_test( export_component-build )

add_cmake_config_test( export_package-build-possible-dir.cmake )
add_cmake_config_test( export_package-build-with-components.cmake )
add_cmake_config_test( export_package-build-with-components-and-version.cmake )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#=============================================================================
# Copyright (c) 2021-2023, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include(${rapids-cmake-dir}/export/export.cmake)

cmake_minimum_required(VERSION 3.20)
project(FakEProJecT LANGUAGES CXX VERSION 3.1.4)

add_library(fakeLib INTERFACE)
install(TARGETS fakeLib EXPORT fake_set)

add_library(fakeLib_c1 INTERFACE)
install(TARGETS fakeLib_c1 EXPORT fake_set_c1)

include(${rapids-cmake-dir}/export/package.cmake)
rapids_export_package( build CUDAToolkit fake_set_c1)

rapids_export(BUILD FakEProJecT
EXPORT_SET fake_set
COMPONENTS c1
COMPONENTS_EXPORT_SET fake_set_c1
LANGUAGES CXX
NAMESPACE test::
)

# Add a custom command that generates a second project
# that verifies our component targetd are exported correctly
file(WRITE "${CMAKE_BINARY_DIR}/verify-1/CMakeLists.txt" [=[
cmake_minimum_required(VERSION 3.20)
project(verify_build_targets LANGUAGES CXX)

foreach(comp c1)
message(STATUS "${CMAKE_CURRENT_LIST_DIR}/../fakeproject-${comp}-dependencies.cmake")
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../fakeproject-${comp}-dependencies.cmake")
message(FATAL_ERROR "rapids_export failed to generate correct component dependencies file name")
endif()

include("${CMAKE_CURRENT_LIST_DIR}/../fakeproject-${comp}-dependencies.cmake")
if(NOT TARGET CUDA::toolkit)
message(FATAL_ERROR "rapids_export failed to generate correct dependencies imports")
endif()
endforeach()
]=])

add_custom_target(verify_target_dependencies_files ALL
COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_BINARY_DIR}/verify-1/build"
COMMAND ${CMAKE_COMMAND} -S="${CMAKE_BINARY_DIR}/verify-1" -B="${CMAKE_BINARY_DIR}/verify-1/build"
)

# Add a custom command that generates a second project
# that verifies our component targetd are exported correctly
file(WRITE "${CMAKE_BINARY_DIR}/verify-2/CMakeLists.txt" [=[
cmake_minimum_required(VERSION 3.20)
project(verify_build_targets LANGUAGES CXX)

set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../)
find_package(fakeproject COMPONENTS c1 REQUIRED)
if(NOT TARGET CUDA::toolkit)
message(FATAL_ERROR "rapids_export failed to generate correct dependencies imports")
endif()
]=])

add_custom_target(verify_target_dependencies_find ALL
COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_BINARY_DIR}/verify-2/build"
COMMAND ${CMAKE_COMMAND} -S="${CMAKE_BINARY_DIR}/verify-2" -B="${CMAKE_BINARY_DIR}/verify-2/build"
)
Loading

0 comments on commit 9879c20

Please sign in to comment.