Skip to content

Commit

Permalink
[aot] FindTaichi CMake module to help outside project integration (#7168
Browse files Browse the repository at this point in the history
)

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} "$<TARGET_FILE_DIR:${EXAMPLE_NAME}>")
```
  • Loading branch information
PENGUINLIONG authored Jan 16, 2023
1 parent 21fdd2e commit 78dc51c
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 37 deletions.
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
172 changes: 172 additions & 0 deletions c_api/cmake/FindTaichi.cmake
Original file line number Diff line number Diff line change
@@ -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)
73 changes: 44 additions & 29 deletions cmake/TaichiCAPI.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -112,58 +128,57 @@ 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}
)

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)
Expand Down
2 changes: 2 additions & 0 deletions cmake/TaichiCXXFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
5 changes: 5 additions & 0 deletions cmake/TaichiConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/TaichiTargets.cmake")

check_required_components("@PROJECT_NAME@")
5 changes: 0 additions & 5 deletions cmake/taichi_c_apiConfig.cmake.in

This file was deleted.

0 comments on commit 78dc51c

Please sign in to comment.