From 78dc51c5fcc8cca3f11912524c86bba1db973640 Mon Sep 17 00:00:00 2001 From: PENGUINLIONG Date: Mon, 16 Jan 2023 13:50:57 +0800 Subject: [PATCH] [aot] FindTaichi CMake module to help outside project integration (#7168) Issue: # ### Brief Summary This PR introduces a CMake module `FindTaichi.cmake` to help external project to integrate Taichi Runtime into their applications following the CMake convention to minimize the lines of codes they need in their `CMakeLists.txt`. The following is the integration CMake snippet: ```cmake # We need to set `FindTaichi.cmake` in module path to `find_package(taichi)`. set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) find_package(taichi REQUIRED) add_executable(${EXAMPLE_NAME} main.cpp) target_link_libraries(${EXAMPLE_NAME} PRIVATE taichi::runtime) # Copy redistributed libraries (`.so` and `.dll`) next to the executable. add_custom_command( TARGET ${EXAMPLE_NAME} PRE_BUILD COMMENT "-- Copy redistributed libraries to output directory (if different): ${taichi_REDIST_LIBRARIES}" COMMAND ${CMAKE_COMMAND} -E copy_if_different ${taichi_REDIST_LIBRARIES} "$") ``` --- CMakeLists.txt | 8 +- c_api/cmake/FindTaichi.cmake | 172 ++++++++++++++++++++++++++++++ cmake/TaichiCAPI.cmake | 73 ++++++++----- cmake/TaichiCXXFlags.cmake | 2 + cmake/TaichiConfig.cmake.in | 5 + cmake/taichi_c_apiConfig.cmake.in | 5 - 6 files changed, 228 insertions(+), 37 deletions(-) create mode 100644 c_api/cmake/FindTaichi.cmake create mode 100644 cmake/TaichiConfig.cmake.in delete mode 100644 cmake/taichi_c_apiConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 52fc900bb0169..5bd38c701f35b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,11 @@ include("cmake/utils.cmake") if (NOT DEFINED TI_VERSION_MAJOR) message(WARNING "It seems that you are running cmake manually, which may cause issues. Please use setup.py to build taichi from source, see https://docs.taichi-lang.org/docs/dev_install for more details.") - set(TI_VERSION_MAJOR 0) - set(TI_VERSION_MINOR 0) - set(TI_VERSION_PATCH 0) + file(READ "${CMAKE_CURRENT_LIST_DIR}/version.txt" TI_VERSION_LITERAL) + string(REGEX MATCH "v([0-9]+)\\.([0-9]+)\\.([0-9]+)" TI_VERSION_LITERAL ${TI_VERSION_LITERAL}) + set(TI_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(TI_VERSION_MINOR ${CMAKE_MATCH_2}) + set(TI_VERSION_PATCH ${CMAKE_MATCH_3}) endif() set(CMAKE_CXX_STANDARD 17) diff --git a/c_api/cmake/FindTaichi.cmake b/c_api/cmake/FindTaichi.cmake new file mode 100644 index 0000000000000..91762bf80fd76 --- /dev/null +++ b/c_api/cmake/FindTaichi.cmake @@ -0,0 +1,172 @@ +#[=======================================================================[.rst: +FindTaichi +---------- + +Finds the Taichi library. + +The module first attempts to locate ``TaichiConfig.cmake`` in any Taichi +installation in CMake variable ``TAICHI_C_API_INSTALL_DIR`` or environment +variable of the same name. If the config file cannot be found, the libraries are +heuristically searched by names and paths in ``TAICHI_C_API_INSTALL_DIR``. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``taichi::runtime`` + The Taichi Runtime library. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``taichi_FOUND`` + True if a Taichi installation is found. +``taichi_VERSION`` + Version of installed Taichi. Components might have lower version numbers. +``taichi_INCLUDE_DIRS`` + Paths to Include directories needed to use Taichi. +``taichi_LIBRARIES`` + Paths to Taichi linking libraries (``.libs``). +``taichi_REDIST_LIBRARIES`` + Paths to Taichi redistributed runtime libraries (``.so`` and ``.dll``). You + might want to copy them next to your executables. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``taichi_runtime_VERSION`` + Taichi runtime library version. +``taichi_runtime_INCLUDE_DIR`` + The directory containing ``taichi/taichi.h``. +``taichi_runtime_LIBRARY`` + Path to linking library of ``taichi_runtime``. +``taichi_runtime_REDIST_LIBRARY`` + Path to redistributed runtime library of ``taichi_runtime``. + +#]=======================================================================] + +cmake_policy(PUSH) + +# Support `IN_LIST` in CMake `if` command. +if(POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif() + +# Find TiRT in the installation directory. The installation directory is +# traditionally specified by an environment variable +# `TAICHI_C_API_INSTALL_DIR`. +if(NOT EXISTS ${TAICHI_C_API_INSTALL_DIR}) + set(TAICHI_C_API_INSTALL_DIR $ENV{TAICHI_C_API_INSTALL_DIR}) +endif() +if(EXISTS ${TAICHI_C_API_INSTALL_DIR}) + get_filename_component(TAICHI_C_API_INSTALL_DIR "${TAICHI_C_API_INSTALL_DIR}" ABSOLUTE) + message("-- TAICHI_C_API_INSTALL_DIR=${TAICHI_C_API_INSTALL_DIR}") +endif() + +set(TAICHI_C_API_INSTALL_DIR "${TAICHI_C_API_INSTALL_DIR}" CACHE PATH "Root directory to Taichi installation") + +# Set up default find components +if("${taichi_FIND_COMPONENTS}" STREQUAL "") + # (penguinliong) Currently we only have Taichi Runtime. We might make the + # codegen a library in the future? + set(taichi_FIND_COMPONENTS "runtime") +endif() + +message("-- Looking for Taichi components: ${taichi_FIND_COMPONENTS}") + +# (penguinliong) Note that the config files only exposes libraries and their +# public headers. We still need to encapsulate the libraries into semantical +# CMake targets in this list. So please DO NOT find Taichi in config mode +# directly. +find_package(taichi CONFIG QUIET HINTS "${TAICHI_C_API_INSTALL_DIR}") + +if(taichi_FOUND) + message("-- Found Taichi ${taichi_VERSION} in config mode: ${taichi_DIR}") +else() + message("-- Could NOT find Taichi in config mode; fallback to heuristic search") +endif() + +# - [taichi::runtime] ---------------------------------------------------------- + +if(("runtime" IN_LIST taichi_FIND_COMPONENTS) AND (NOT TARGET taichi::runtime)) + if(taichi_FOUND) + if(NOT TARGET taichi_c_api) + message(FATAL_ERROR "taichi is marked found but target taichi_c_api doesn't exists") + endif() + + # Already found in config mode. + get_target_property(taichi_runtime_CONFIG taichi_c_api IMPORTED_CONFIGURATIONS) + if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + get_target_property(taichi_runtime_LIBRARY taichi_c_api IMPORTED_IMPLIB_${taichi_runtime_CONFIG}) + get_target_property(taichi_runtime_REDIST_LIBRARY taichi_c_api IMPORTED_LOCATION_${taichi_runtime_CONFIG}) + else() + get_target_property(taichi_runtime_LIBRARY taichi_c_api IMPORTED_LOCATION_${taichi_runtime_CONFIG}) + get_target_property(taichi_runtime_REDIST_LIBRARY taichi_c_api IMPORTED_LOCATION_${taichi_runtime_CONFIG}) + endif() + get_target_property(taichi_runtime_INCLUDE_DIR taichi_c_api INTERFACE_INCLUDE_DIRECTORIES) + else() + find_library(taichi_runtime_LIBRARY + NAMES taichi_runtime taichi_c_api + HINTS ${TAICHI_C_API_INSTALL_DIR} + PATH_SUFFIXES lib + # CMake find root is overriden by Android toolchain. + NO_CMAKE_FIND_ROOT_PATH) + + find_library(taichi_runtime_REDIST_LIBRARY + NAMES taichi_runtime taichi_c_api + HINTS ${TAICHI_C_API_INSTALL_DIR} + PATH_SUFFIXES bin lib + # CMake find root is overriden by Android toolchain. + NO_CMAKE_FIND_ROOT_PATH) + + find_path(taichi_runtime_INCLUDE_DIR + NAMES taichi/taichi.h + HINTS ${TAICHI_C_API_INSTALL_DIR} + PATH_SUFFIXES include + NO_CMAKE_FIND_ROOT_PATH) + endif() + + # Capture Taichi Runtime version from header definition. + file(READ "${taichi_runtime_INCLUDE_DIR}/taichi/taichi_core.h" taichi_runtime_VERSION_LITERAL) + string(REGEX MATCH "#define TI_C_API_VERSION ([0-9]+)" taichi_runtime_VERSION_LITERAL ${taichi_runtime_VERSION_LITERAL}) + set(taichi_runtime_VERSION_LITERAL ${CMAKE_MATCH_1}) + math(EXPR taichi_runtime_VERSION_MAJOR "${taichi_runtime_VERSION_LITERAL} / 1000000") + math(EXPR taichi_runtime_VERSION_MINOR "(${taichi_runtime_VERSION_LITERAL} / 1000) % 1000") + math(EXPR taichi_runtime_VERSION_PATCH "${taichi_runtime_VERSION_LITERAL} % 1000") + set(taichi_runtime_VERSION "${taichi_runtime_VERSION_MAJOR}.${taichi_runtime_VERSION_MINOR}.${taichi_runtime_VERSION_PATCH}") + + # Ensure the version string is valid. + if(${taichi_runtime_VERSION} VERSION_GREATER "0") + message("-- Found Taichi Runtime ${taichi_runtime_VERSION}: ${taichi_runtime_LIBRARY}") + + add_library(taichi::runtime UNKNOWN IMPORTED) + set_target_properties(taichi::runtime PROPERTIES + IMPORTED_LOCATION "${taichi_runtime_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${taichi_runtime_INCLUDE_DIR}") + + list(APPEND COMPONENT_VARS + taichi_runtime_LIBRARY + taichi_runtime_INCLUDE_DIR) + list(APPEND taichi_LIBRARIES "${taichi_runtime_LIBRARY}") + if(EXISTS ${taichi_runtime_REDIST_LIBRARY}) + list(APPEND taichi_REDIST_LIBRARIES ${taichi_runtime_REDIST_LIBRARY}) + endif() + list(APPEND taichi_INCLUDE_DIRS "${taichi_runtime_INCLUDE_DIR}") + endif() +endif() + +# - [taichi] ------------------------------------------------------------------- + +set(taichi_VERSION taichi_runtime_VERSION) +set(taichi_FOUND TRUE) + +# Handle `QUIET` and `REQUIRED` args in the recommended way in `find_package`. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(taichi DEFAULT_MSG ${COMPONENT_VARS}) + +cmake_policy(POP) diff --git a/cmake/TaichiCAPI.cmake b/cmake/TaichiCAPI.cmake index c19a976b9421a..32f75c1488487 100644 --- a/cmake/TaichiCAPI.cmake +++ b/cmake/TaichiCAPI.cmake @@ -20,10 +20,23 @@ endif() endfunction() set(TAICHI_C_API_NAME taichi_c_api) -file(GLOB_RECURSE C_API_SOURCE "c_api/src/taichi_core_impl.cpp") +list(APPEND C_API_SOURCE "c_api/src/taichi_core_impl.cpp") +list(APPEND C_API_PUBLIC_HEADERS + "c_api/include/taichi/taichi_platform.h" + "c_api/include/taichi/taichi_core.h" + "c_api/include/taichi/taichi.h" + # FIXME: (penguinliong) Remove this in the future when we have a option for + # Unity3D integration? + "c_api/include/taichi/taichi_unity.h" + ) if (TI_WITH_LLVM) list(APPEND C_API_SOURCE "c_api/src/taichi_llvm_impl.cpp") + list(APPEND C_API_PUBLIC_HEADERS "c_api/include/taichi/taichi_cpu.h") + + if (TI_WITH_CUDA) + list(APPEND C_API_PUBLIC_HEADERS "c_api/include/taichi/taichi_cuda.h") + endif() endif() if (TI_WITH_OPENGL OR TI_WITH_VULKAN OR TI_WITH_METAL) @@ -32,14 +45,17 @@ endif() if (TI_WITH_OPENGL) list(APPEND C_API_SOURCE "c_api/src/taichi_opengl_impl.cpp") + list(APPEND C_API_PUBLIC_HEADERS "c_api/include/taichi/taichi_opengl.h") endif() if (TI_WITH_METAL) list(APPEND C_API_SOURCE "c_api/src/taichi_metal_impl.mm") + #list(APPEND C_API_PUBLIC_HEADERS "c_api/include/taichi/taichi_metal.h") endif() if (TI_WITH_VULKAN) list(APPEND C_API_SOURCE "c_api/src/taichi_vulkan_impl.cpp") + list(APPEND C_API_PUBLIC_HEADERS "c_api/include/taichi/taichi_vulkan.h") if (APPLE) install(FILES ${MoltenVK_LIBRARY} DESTINATION c_api/lib) endif() @@ -112,21 +128,29 @@ target_include_directories(${TAICHI_C_API_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/external/glad/include ${CMAKE_CURRENT_SOURCE_DIR}/external/glfw/include ) +set_property(TARGET ${TAICHI_C_API_NAME} PROPERTY PUBLIC_HEADER ${C_API_PUBLIC_HEADERS}) # This helper provides us standard locations across Linux/Windows/MacOS include(GNUInstallDirs) -install(TARGETS ${TAICHI_C_API_NAME} EXPORT ${TAICHI_C_API_NAME}Targets - LIBRARY DESTINATION c_api/lib - ARCHIVE DESTINATION c_api/lib - RUNTIME DESTINATION c_api/bin - INCLUDES DESTINATION c_api/include +install(TARGETS ${TAICHI_C_API_NAME} EXPORT TaichiExportTargets + LIBRARY DESTINATION c_api/${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION c_api/${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION c_api/${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION c_api/${CMAKE_INSTALL_INCLUDEDIR}/taichi ) +# The C++ wrapper is saved in a dedicated directory. +install( + FILES + "c_api/include/taichi/cpp/taichi.hpp" + DESTINATION + c_api/${CMAKE_INSTALL_INCLUDEDIR}/taichi/cpp +) + # Install the export set, which contains the meta data of the target -install(EXPORT ${TAICHI_C_API_NAME}Targets - FILE ${TAICHI_C_API_NAME}Targets.cmake - NAMESPACE ${TAICHI_C_API_NAME}:: +install(EXPORT TaichiExportTargets + FILE TaichiTargets.cmake DESTINATION c_api/${CMAKE_INSTALL_LIBDIR}/cmake/${TAICHI_C_API_NAME} ) @@ -134,36 +158,27 @@ include(CMakePackageConfigHelpers) # Generate the config file configure_package_config_file( - "${PROJECT_SOURCE_DIR}/cmake/${TAICHI_C_API_NAME}Config.cmake.in" - "${PROJECT_BINARY_DIR}/${TAICHI_C_API_NAME}Config.cmake" + "${PROJECT_SOURCE_DIR}/cmake/TaichiConfig.cmake.in" + "${PROJECT_BINARY_DIR}/TaichiConfig.cmake" INSTALL_DESTINATION - c_api/${CMAKE_INSTALL_LIBDIR}/cmake/${TAICHI_C_API_NAME} + c_api/${CMAKE_INSTALL_LIBDIR}/cmake/${TAICHI_C_API_NAME} ) # Generate the config version file -set(${TAICHI_C_API_NAME}_VERSION "${TI_VERSION_MAJOR}.${TI_VERSION_MINOR}.${TI_VERSION_PATCH}") +set(TAICHI_VERSION "${TI_VERSION_MAJOR}.${TI_VERSION_MINOR}.${TI_VERSION_PATCH}") write_basic_package_version_file( - "${TAICHI_C_API_NAME}ConfigVersion.cmake" - VERSION ${${TAICHI_C_API_NAME}_VERSION} + "TaichiConfigVersion.cmake" + VERSION ${TAICHI_VERSION} COMPATIBILITY SameMajorVersion ) # Install the config files -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${TAICHI_C_API_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${TAICHI_C_API_NAME}ConfigVersion.cmake" +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/TaichiConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/TaichiConfigVersion.cmake" DESTINATION - c_api/${CMAKE_INSTALL_LIBDIR}/cmake/${TAICHI_C_API_NAME} - ) - -# Install public headers for this target -# TODO: Replace files here with public headers when ready. -install(DIRECTORY - ${PROJECT_SOURCE_DIR}/c_api/include - DESTINATION c_api - FILES_MATCHING - PATTERN *.h - PATTERN *.hpp + c_api/${CMAKE_INSTALL_LIBDIR}/cmake/${TAICHI_C_API_NAME} ) if(TI_WITH_LLVM) diff --git a/cmake/TaichiCXXFlags.cmake b/cmake/TaichiCXXFlags.cmake index 51365afd59096..7f4a2171ec7a4 100644 --- a/cmake/TaichiCXXFlags.cmake +++ b/cmake/TaichiCXXFlags.cmake @@ -4,6 +4,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTI_ISE_NONE") option(BUILD_WITH_ADDRESS_SANITIZER "Build with clang address sanitizer" OFF) +include(CheckCXXCompilerFlag) # For `check_cxx_compiler_flag`. + if (BUILD_WITH_ADDRESS_SANITIZER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") diff --git a/cmake/TaichiConfig.cmake.in b/cmake/TaichiConfig.cmake.in new file mode 100644 index 0000000000000..a83f09440965f --- /dev/null +++ b/cmake/TaichiConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/TaichiTargets.cmake") + +check_required_components("@PROJECT_NAME@") diff --git a/cmake/taichi_c_apiConfig.cmake.in b/cmake/taichi_c_apiConfig.cmake.in deleted file mode 100644 index 6fef29530c3ec..0000000000000 --- a/cmake/taichi_c_apiConfig.cmake.in +++ /dev/null @@ -1,5 +0,0 @@ -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/taichi_c_apiTargets.cmake") - -check_required_components("@PROJECT_NAME@")