Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
Add find_package and add_subdirectory CMake support.
Browse files Browse the repository at this point in the history
To validate installation + packages, run the new tests:

```
mkdir build
cd build
cmake -Dlibcudacxx_ENABLE_CMAKE_TESTS=ON ..
ctest --output-on-failure
```
  • Loading branch information
alliepiper committed Jan 18, 2022
1 parent 4e9f28e commit 0e9e5b1
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ compare_git_to_perforce.bash
.clangd/
.cache
compile_commands.json
*~
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
cmake_minimum_required(VERSION 3.8)
project(libcudacxx CXX)

# Determine whether libcudacxx is the top-level project or included into
# another project via add_subdirectory().
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_LIST_DIR}")
set(libcudacxx_TOPLEVEL_PROJECT ON)
else()
set(libcudacxx_TOPLEVEL_PROJECT OFF)
endif()

include(cmake/libcudacxxInstallRules.cmake)

if (NOT libcudacxx_TOPLEVEL_PROJECT)
include(cmake/libcudacxxAddSubdir.cmake)
return()
endif()

# Note that this currently returns and skips the rest of the build
# system.
option(libcudacxx_ENABLE_CMAKE_TESTS "Enable ctest-based testing." OFF)
if (libcudacxx_ENABLE_CMAKE_TESTS)
# Might be able to lower this, but would need to do some testing:
cmake_minimum_required(VERSION 3.20.1)
include(CTest)
enable_testing() # Must be called in root CMakeLists.txt
add_subdirectory(cmake/test/)
return()
endif()

set(PACKAGE_NAME libcudacxx)
set(PACKAGE_VERSION 11.0)
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
Expand Down
4 changes: 4 additions & 0 deletions cmake/libcudacxxAddSubdir.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
find_package(libcudacxx REQUIRED CONFIG
NO_DEFAULT_PATH # Only check the explicit path in HINTS:
HINTS "${CMAKE_CURRENT_LIST_DIR}/.."
)
38 changes: 38 additions & 0 deletions cmake/libcudacxxInstallRules.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
option(libcudacxx_ENABLE_INSTALL_RULES
"Enable installation of libcudacxx" ${libcudacxx_TOPLEVEL_PROJECT}
)

if (NOT libcudacxx_ENABLE_INSTALL_RULES)
return()
endif()

# Bring in CMAKE_INSTALL_LIBDIR
include(GNUInstallDirs)

# libcudacxx is a header library; no need to build anything before installing:
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE)

# Libcudacxx headers
install(DIRECTORY "${libcudacxx_SOURCE_DIR}/include/cuda"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(DIRECTORY "${libcudacxx_SOURCE_DIR}/include/nv"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)

# Libcudacxx cmake package
install(DIRECTORY "${libcudacxx_SOURCE_DIR}/lib/cmake/libcudacxx"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake"
PATTERN libcudacxx-header-search EXCLUDE
)

# Need to configure a file to store CMAKE_INSTALL_INCLUDEDIR
# since it can be defined by the user. This is common to work around collisions
# with the CTK installed headers.
configure_file("${libcudacxx_SOURCE_DIR}/lib/cmake/libcudacxx/libcudacxx-header-search.cmake.in"
"${libcudacxx_BINARY_DIR}/lib/cmake/libcudacxx/libcudacxx-header-search.cmake"
@ONLY
)
install(FILES "${libcudacxx_BINARY_DIR}/lib/cmake/libcudacxx/libcudacxx-header-search.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/libcudacxx"
)
75 changes: 75 additions & 0 deletions cmake/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}")
# There's a bug that prevents build-and-test from working on MSVC.
# See NVIDIA/nvbench#43.
return()
endif()

set(cmake_opts
-D "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
-D "CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
-D "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
)

# Temporary installation prefix for tests against installed project:
set(tmp_install_prefix "${CMAKE_CURRENT_BINARY_DIR}/test_install")

# Add a build-and-test CTest.
# - full_test_name_var will be set to the full name of the test.
# - subdir is the relative path to the test project directory.
# - test_id is used to generate a unique name for this test, allowing the
# subdir to be reused.
# - Any additional args will be passed to the project configure step.
function(libcudacxx_add_compile_test full_test_name_var subdir test_id)
set(test_name libcudacxx.test.cmake.${subdir}.${test_id})
set(src_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}/${test_id}")
add_test(NAME ${test_name}
COMMAND "${CMAKE_CTEST_COMMAND}"
--build-and-test "${src_dir}" "${build_dir}"
--build-generator "${CMAKE_GENERATOR}"
--build-options
${cmake_opts}
${ARGN}
--test-command "${CMAKE_CTEST_COMMAND}" --output-on-failure
)
set(${full_test_name_var} ${test_name} PARENT_SCOPE)
endfunction()

################################################################################
# Test against source dir

libcudacxx_add_compile_test(test_name
test_export
source_tree
-D "libcudacxx_DIR=${libcudacxx_SOURCE_DIR}/lib/cmake/libcudacxx/"
-D TEST_TYPE=SOURCE_TREE
)

################################################################################
# Test against install tree

libcudacxx_add_compile_test(test_name
test_export
install_tree
-D "libcudacxx_DIR=${tmp_install_prefix}/lib/cmake/libcudacxx/"
-D TEST_TYPE=INSTALL_TREE
)
set_tests_properties(${test_name} PROPERTIES FIXTURES_REQUIRED install_tree)

################################################################################
# Install tree fixtures
add_test(NAME libcudacxx.test.cmake.install_tree.install
COMMAND "${CMAKE_COMMAND}"
--install "${libcudacxx_BINARY_DIR}"
--prefix "${tmp_install_prefix}"
)
set_tests_properties(libcudacxx.test.cmake.install_tree.install PROPERTIES
FIXTURES_SETUP install_tree
)

add_test(NAME libcudacxx.test.cmake.install_tree.cleanup
COMMAND "${CMAKE_COMMAND}" -E rm -rf "${tmp_install_prefix}"
)
set_tests_properties(libcudacxx.test.cmake.install_tree.cleanup PROPERTIES
FIXTURES_CLEANUP install_tree
)
14 changes: 14 additions & 0 deletions cmake/test/test_export/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.20.1)
project(libcudacxxTestExport CXX)

message(STATUS "libcudacxx_DIR=${libcudacxx_DIR}")
find_package(libcudacxx)

add_executable(version_check version_check.cxx)
target_link_libraries(version_check PRIVATE libcudacxx::libcudacxx)
enable_testing()
add_test(NAME version_check COMMAND "$<TARGET_FILE:version_check>")
set_property(TEST version_check PROPERTY
PASS_REGULAR_EXPRESSION
"${libcudacxx_VERSION_MAJOR}\.${libcudacxx_VERSION_MINOR}\.${libcudacxx_VERSION_PATCH}"
)
18 changes: 18 additions & 0 deletions cmake/test/test_export/version_check.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <cuda/std/atomic>

#include <cstdio>

int main()
{
cuda::std::atomic<int> x{0};

printf("Built with libcudacxx version %d.%d.%d.\n",
_LIBCUDACXX_CUDA_API_VERSION_MAJOR,
_LIBCUDACXX_CUDA_API_VERSION_MINOR,
_LIBCUDACXX_CUDA_API_VERSION_PATCH);

return x;
}



36 changes: 36 additions & 0 deletions lib/cmake/libcudacxx/libcudacxx-config-version.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Parse version information from version header:
include("${CMAKE_CURRENT_LIST_DIR}/libcudacxx-header-search.cmake")

file(READ "${_libcudacxx_VERSION_INCLUDE_DIR}/cuda/std/detail/__config"
libcudacxx_VERSION_HEADER
)

string(REGEX MATCH
"#define[ \t]+_LIBCUDACXX_CUDA_API_VERSION[ \t]+([0-9]+)" unused_var
"${libcudacxx_VERSION_HEADER}"
)

set(libcudacxx_VERSION_FLAT ${CMAKE_MATCH_1})
math(EXPR libcudacxx_VERSION_MAJOR "${libcudacxx_VERSION_FLAT} / 1000000")
math(EXPR libcudacxx_VERSION_MINOR "(${libcudacxx_VERSION_FLAT} / 1000) % 1000")
math(EXPR libcudacxx_VERSION_PATCH "${libcudacxx_VERSION_FLAT} % 1000")
set(libcudacxx_VERSION_TWEAK 0)

set(libcudacxx_VERSION
"${libcudacxx_VERSION_MAJOR}.${libcudacxx_VERSION_MINOR}.${libcudacxx_VERSION_PATCH}.${libcudacxx_VERSION_TWEAK}"
)

set(PACKAGE_VERSION ${libcudacxx_VERSION})
set(PACKAGE_VERSION_COMPATIBLE FALSE)
set(PACKAGE_VERSION_EXACT FALSE)
set(PACKAGE_VERSION_UNSUITABLE FALSE)

if(PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION)
if(PACKAGE_FIND_VERSION_MAJOR VERSION_EQUAL libcudacxx_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
endif()

if(PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
56 changes: 56 additions & 0 deletions lib/cmake/libcudacxx/libcudacxx-config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#
# find_package(libcudacxx) config file.
#
# Defines a libcudacxx::libcudacxx target that may be linked from user projects to include
# libcudacxx.

if (TARGET libcudacxx::libcudacxx)
return()
endif()

function(_libcudacxx_declare_interface_alias alias_name ugly_name)
# 1) Only IMPORTED and ALIAS targets can be placed in a namespace.
# 2) When an IMPORTED library is linked to another target, its include
# directories are treated as SYSTEM includes.
# 3) nvcc will automatically check the CUDA Toolkit include path *before* the
# system includes. This means that the Toolkit libcudacxx will *always* be used
# during compilation, and the include paths of an IMPORTED libcudacxx::libcudacxx
# target will never have any effect.
# 4) This behavior can be fixed by setting the property NO_SYSTEM_FROM_IMPORTED
# on EVERY target that links to libcudacxx::libcudacxx. This would be a burden and a
# footgun for our users. Forgetting this would silently pull in the wrong libcudacxx!
# 5) A workaround is to make a non-IMPORTED library outside of the namespace,
# configure it, and then ALIAS it into the namespace (or ALIAS and then
# configure, that seems to work too).
add_library(${ugly_name} INTERFACE)
add_library(${alias_name} ALIAS ${ugly_name})
endfunction()

#
# Setup targets
#

_libcudacxx_declare_interface_alias(libcudacxx::libcudacxx _libcudacxx_libcudacxx)
# Pull in the include dir detected by libcudacxx-config-version.cmake
set(_libcudacxx_INCLUDE_DIR "${_libcudacxx_VERSION_INCLUDE_DIR}"
CACHE INTERNAL "Location of libcudacxx headers."
)
unset(_libcudacxx_VERSION_INCLUDE_DIR CACHE) # Clear tmp variable from cache
target_include_directories(_libcudacxx_libcudacxx INTERFACE "${_libcudacxx_INCLUDE_DIR}")

#
# Standardize version info
#

set(LIBCUDACXX_VERSION ${${CMAKE_FIND_PACKAGE_NAME}_VERSION} CACHE INTERNAL "")
set(LIBCUDACXX_VERSION_MAJOR ${${CMAKE_FIND_PACKAGE_NAME}_VERSION_MAJOR} CACHE INTERNAL "")
set(LIBCUDACXX_VERSION_MINOR ${${CMAKE_FIND_PACKAGE_NAME}_VERSION_MINOR} CACHE INTERNAL "")
set(LIBCUDACXX_VERSION_PATCH ${${CMAKE_FIND_PACKAGE_NAME}_VERSION_PATCH} CACHE INTERNAL "")
set(LIBCUDACXX_VERSION_TWEAK ${${CMAKE_FIND_PACKAGE_NAME}_VERSION_TWEAK} CACHE INTERNAL "")
set(LIBCUDACXX_VERSION_COUNT ${${CMAKE_FIND_PACKAGE_NAME}_VERSION_COUNT} CACHE INTERNAL "")

include(FindPackageHandleStandardArgs)
if (NOT libcudacxx_CONFIG)
set(libcudacxx_CONFIG "${CMAKE_CURRENT_LIST_FILE}")
endif()
find_package_handle_standard_args(libcudacxx CONFIG_MODE)
8 changes: 8 additions & 0 deletions lib/cmake/libcudacxx/libcudacxx-header-search.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Parse version information from version header:
unset(_libcudacxx_VERSION_INCLUDE_DIR CACHE) # Clear old result to force search
find_path(_libcudacxx_VERSION_INCLUDE_DIR cuda/std/detail/__config
NO_DEFAULT_PATH # Only search explicit paths below:
PATHS
"${CMAKE_CURRENT_LIST_DIR}/../../../include" # Source tree
)
set_property(CACHE _libcudacxx_VERSION_INCLUDE_DIR PROPERTY TYPE INTERNAL)
8 changes: 8 additions & 0 deletions lib/cmake/libcudacxx/libcudacxx-header-search.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Parse version information from version header:
unset(_libcudacxx_VERSION_INCLUDE_DIR CACHE) # Clear old result to force search
find_path(_libcudacxx_VERSION_INCLUDE_DIR cuda/std/detail/__config
NO_DEFAULT_PATH # Only search explicit paths below:
PATHS
"${CMAKE_CURRENT_LIST_DIR}/../../../@CMAKE_INSTALL_INCLUDEDIR@" # Install tree
)
set_property(CACHE _libcudacxx_VERSION_INCLUDE_DIR PROPERTY TYPE INTERNAL)

0 comments on commit 0e9e5b1

Please sign in to comment.