This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new eef7dc9b11 [CMake] Organize optional modules and build both runtime
libraries (#20728)
eef7dc9b11 is described below
commit eef7dc9b115412b4617d7cdbb759cc8c8beefaf8
Author: Tianqi Chen <[email protected]>
AuthorDate: Wed Oct 14 15:41:00 2026 -0400
[CMake] Organize optional modules and build both runtime libraries (#20728)
Keep core compiler/runtime source selection and target assembly in the
root CMakeLists.txt while moving optional runtime-extra assembly and C++
test setup into dedicated files. OpenCL collects wrapper sources
independently of Hexagon.
Build the shared runtime and `libtvm_runtime_static.a` together from
common runtime objects, with their respective TVM-FFI dependencies.
Remove the static-only option and update its callers and archive-linking
guidance while preserving existing shared-library and wheel layouts.
Remove the unused ABI-change debug option and its build definitions
while retaining normal Debug and RelWithDebInfo behavior.
---
CMakeLists.txt | 428 +++++++++++----------------------------
apps/cpp_rpc/CMakeLists.txt | 18 +-
cmake/config.cmake | 12 +-
cmake/modules/OpenCL.cmake | 3 +-
cmake/modules/RuntimeExtra.cmake | 103 ++++++++++
tests/cpp/CMakeLists.txt | 109 ++++++++++
6 files changed, 339 insertions(+), 334 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 27c636396b..329e04237d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -70,14 +70,12 @@ tvm_option(USE_RPC "Build with RPC" ON)
tvm_option(USE_THREADS "Build with thread support" ON)
tvm_option(USE_LLVM "Build with LLVM, can be set to specific llvm-config path"
OFF)
tvm_option(USE_OPENMP "Build with OpenMP thread pool implementation" OFF)
-tvm_option(TVM_DEBUG_WITH_ABI_CHANGE "Enable debug code that may cause ABI
changes" OFF)
tvm_option(TVM_LOG_BEFORE_THROW "Whether log before throw, for debugging
purposes" OFF)
tvm_option(USE_RTTI "Build with RTTI" ON)
tvm_option(USE_MSVC_MT "Build with MT" OFF)
tvm_option(INSTALL_DEV "Install compiler infrastructure" OFF)
tvm_option(HIDE_PRIVATE_SYMBOLS "Compile with -fvisibility=hidden." ON)
tvm_option(INDEX_DEFAULT_I64 "Defaults the index datatype to int64" ON)
-tvm_option(BUILD_STATIC_RUNTIME "Build static version of libtvm_runtime" OFF)
tvm_option(USE_GTEST "Use GoogleTest for C++ sanity tests" AUTO)
tvm_option(USE_CUSTOM_LOGGING "Use user-defined custom logging,
tvm::runtime::detail::LogFatalImpl and tvm::runtime::detail::LogMessageImpl
must be implemented" OFF)
tvm_option(USE_ALTERNATIVE_LINKER "Use 'mold' or 'lld' if found when invoking
compiler to link artifact" AUTO)
@@ -292,6 +290,7 @@ assign_source_group("Source" ${GROUP_SOURCE})
assign_source_group("Include" ${GROUP_INCLUDE})
# Source file lists
+# Core compiler sources, extended by the backend modules.
tvm_file_glob(GLOB_RECURSE COMPILER_SRCS
src/ir/*.cc
src/sym/*.cc
@@ -364,7 +363,7 @@ tvm_file_glob(GLOB CODEGEN_SRCS
)
list(APPEND COMPILER_SRCS ${CODEGEN_SRCS})
-
+# Core runtime sources, extended by the backend modules.
tvm_file_glob(GLOB RUNTIME_SRCS
src/runtime/*.cc
src/runtime/rpc/minrpc/*.cc
@@ -376,11 +375,15 @@ list(APPEND RUNTIME_SRCS ${RUNTIME_VM_SRCS})
# Note: src/backend/*/runtime sources move to per-backend DSOs.
set(TVM_RUNTIME_EXT_OBJS "")
+if(USE_RPC)
+ message(STATUS "Build with RPC support...")
+ tvm_file_glob(GLOB RUNTIME_RPC_SRCS src/runtime/rpc/*.cc)
+ list(APPEND RUNTIME_SRCS ${RUNTIME_RPC_SRCS})
+endif(USE_RPC)
+
if(BUILD_FOR_HEXAGON)
- if(NOT BUILD_STATIC_RUNTIME)
- # Allow undefined symbols (there will be some from libc).
- set(TVM_NO_UNDEFINED_SYMBOLS "")
- endif()
+ # Allow undefined symbols in the shared runtime (there will be some from
libc).
+ set(TVM_NO_UNDEFINED_SYMBOLS "")
add_definitions(-D_MACH_I32=int)
endif()
@@ -393,52 +396,6 @@ if(INDEX_DEFAULT_I64)
add_definitions(-DTVM_INDEX_DEFAULT_I64=1)
endif()
-if(USE_RPC)
- message(STATUS "Build with RPC support...")
- tvm_file_glob(GLOB RUNTIME_RPC_SRCS src/runtime/rpc/*.cc)
- list(APPEND RUNTIME_SRCS ${RUNTIME_RPC_SRCS})
-endif(USE_RPC)
-# Note: disco/**, NCCL, NVSHMEM, RCCL all move to libtvm_runtime_extra
-# (assembled inline below after all contrib cmake files).
-
-# Enable ctest if gtest is available
-if(USE_GTEST)
- # Check env var for backward compatibility. A better way to specify package
- # locations is to use CMAKE_PREFIX_PATH or other standard CMake mechanism
- # (see CMake documentation for `find_package`).
- set(GTEST_ROOT "$ENV{GTEST_LIB}")
- if("${USE_GTEST}" STREQUAL "AUTO")
- # If USE_GTEST is AUTO, treat GTest as optional: enable if found.
- find_package(GTest)
- elseif("${USE_GTEST}" MATCHES ${IS_TRUE_PATTERN})
- # USE_GTEST is set to ON, TRUE, etc. Treat GTest as a required package.
- find_package(GTest REQUIRED)
- endif()
- if(GTEST_FOUND)
- if(NOT TARGET GTest::gmock)
- # GMock is formally supported in CMake 3.20; for now, expect libgmock.a
in the same directory,
- # and require that folks compiling against GTest::gmock also link
against GTest::GTest
- # (for the includes dir).
- add_library(GTest::gmock STATIC IMPORTED GLOBAL)
- get_target_property(GTEST_LIB_PATH GTest::GTest IMPORTED_LOCATION)
- if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
- # CMake >= 3.20 makes GTest::GTest into a compatibility target. The
real import location is in
- # GTest::gtest.
- get_target_property(GTEST_LIB_PATH GTest::gtest IMPORTED_LOCATION)
- if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
- message(FATAL_ERROR "Neither GTest::GTest nor GTest::gtest targets
defined IMPORTED_LOCATION")
- endif()
- endif()
- get_filename_component(GTEST_LIB_DIR "${GTEST_LIB_PATH}" DIRECTORY)
- set_target_properties(GTest::gmock PROPERTIES
- IMPORTED_LOCATION "${GTEST_LIB_DIR}/libgmock.a")
- endif()
-
- enable_testing()
- include(CTest)
- endif()
-endif()
-
if(USE_KALLOC_ALIGNMENT)
message(STATUS "Build Alloc alignment set to ${USE_KALLOC_ALIGNMENT}")
add_definitions(-DTVM_KALLOC_ALIGNMENT=${USE_KALLOC_ALIGNMENT})
@@ -479,139 +436,107 @@ include(cmake/modules/contrib/ExampleNPU.cmake)
include(cmake/modules/contrib/vllm.cmake)
include(cmake/modules/Git.cmake)
-# ---- libtvm_runtime_extra assembly ----
-# Disco core sources.
-tvm_file_glob(GLOB _disco_core_srcs src/runtime/extra/disco/*.cc)
-add_library(tvm_disco_objs OBJECT ${_disco_core_srcs})
-target_link_libraries(tvm_disco_objs PRIVATE tvm_runtime_extra_defs)
-target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_objs)
+include(cmake/modules/RuntimeExtra.cmake)
+add_subdirectory(3rdparty/tvm-ffi)
+include(GNUInstallDirs)
-# Distributed disco (disabled for Hexagon cross-compile).
-if(NOT BUILD_FOR_HEXAGON)
- tvm_file_glob(GLOB _disco_dist_srcs src/runtime/extra/disco/distributed/*.cc)
- add_library(tvm_disco_distributed_objs OBJECT ${_disco_dist_srcs})
- target_link_libraries(tvm_disco_distributed_objs PRIVATE
tvm_runtime_extra_defs)
- target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_distributed_objs)
-endif()
-
-# NCCL / cuda_ipc — requires CUDA + NCCL.
-if(USE_CUDA AND USE_NCCL)
- find_nccl(${USE_NCCL})
- include_directories(SYSTEM ${NCCL_INCLUDE_DIR})
- tvm_file_glob(GLOB _nccl_srcs src/runtime/extra/disco/nccl/*.cc
src/runtime/extra/disco/cuda_ipc/*.cc 3rdparty/tensorrt_llm/*.cu)
- set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES
COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=0")
- add_library(tvm_nccl_objs OBJECT ${_nccl_srcs})
- target_link_libraries(tvm_nccl_objs PRIVATE tvm_runtime_extra_defs)
- find_library(LIBRT rt)
- target_link_libraries(tvm_runtime_extra PRIVATE tvm_nccl_objs nccl ${LIBRT})
-endif()
-
-# NVSHMEM.
-if(USE_CUDA AND USE_NVSHMEM)
- find_nvshmem(${USE_NVSHMEM})
- if(NOT NVSHMEM_FOUND)
- message(FATAL_ERROR "Cannot find NVSHMEM, USE_NVSHMEM=" ${USE_NVSHMEM})
- endif()
- set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
- set(CMAKE_POSITION_INDEPENDENT_CODE ON)
- tvm_file_glob(GLOB _nvshmem_srcs src/runtime/extra/contrib/nvshmem/*.cc
src/runtime/extra/contrib/nvshmem/*.cu)
- add_library(tvm_nvshmem_objs OBJECT ${_nvshmem_srcs})
- target_link_libraries(tvm_nvshmem_objs PRIVATE tvm_runtime_extra_defs)
- target_include_directories(tvm_nvshmem_objs PUBLIC ${NVSHMEM_INCLUDE_DIR})
- # CUDA 13 moved libcu++ under include/cccl. NVSHMEM's headers include
- # <cuda/std/...>, which nvcc resolves on its own -- the host compiler
- # building this target's .cc sources does not, so name the directory.
- if(EXISTS "${CUDA_TOOLKIT_ROOT_DIR}/include/cccl")
- target_include_directories(tvm_nvshmem_objs SYSTEM PUBLIC
- "${CUDA_TOOLKIT_ROOT_DIR}/include/cccl")
- endif()
- find_library(NVSHMEM_HOST nvshmem_host ${NVSHMEM_LIB_DIR})
- find_library(NVSHMEM_DEVICE nvshmem_device ${NVSHMEM_LIB_DIR})
- target_link_libraries(tvm_runtime_extra PRIVATE tvm_nvshmem_objs
${NVSHMEM_HOST} ${NVSHMEM_DEVICE})
- set_target_properties(tvm_runtime_extra PROPERTIES
CUDA_SEPARABLE_COMPILATION ON)
+if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
+ message(STATUS "Build with thread support...")
+ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+ find_package(Threads REQUIRED)
endif()
-# RCCL.
-if(USE_ROCM AND USE_RCCL)
- find_rccl(${USE_RCCL})
- include_directories(SYSTEM ${RCCL_INCLUDE_DIR})
- tvm_file_glob(GLOB _rccl_srcs src/runtime/extra/disco/nccl/*.cc)
- set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES
COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=1")
- add_library(tvm_rccl_objs OBJECT ${_rccl_srcs})
- target_link_libraries(tvm_rccl_objs PRIVATE tvm_runtime_extra_defs)
- target_link_libraries(tvm_runtime_extra PRIVATE tvm_rccl_objs rccl)
+set(TVM_IS_DEBUG_BUILD OFF)
+if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL
"RelWithDebInfo" OR CMAKE_CXX_FLAGS MATCHES "-g")
+ set(TVM_IS_DEBUG_BUILD ON)
+ set(FILE_PREFIX_MAP_FLAG "-ffile-prefix-map=..=${CMAKE_CURRENT_SOURCE_DIR}")
+ CHECK_CXX_COMPILER_FLAG("${FILE_PREFIX_MAP_FLAG}" FILE_PREFIX_MAP_SUPPORTED)
endif()
-target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime)
-
-# If disco/cuda_ipc is included, link the CUDA DSO.
-if(USE_CUDA)
- target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime_cuda)
- target_link_libraries(tvm_runtime_extra PRIVATE ${CUDA_CUDART_LIBRARY}
${CUDA_CUDA_LIBRARY})
+# Core runtime objects are shared by the dynamic and static libraries.
+add_library(tvm_runtime_objs OBJECT ${RUNTIME_SRCS})
+target_link_libraries(tvm_runtime_objs PUBLIC tvm_ffi_header)
+if(TVM_VISIBILITY_FLAG)
+ target_compile_options(tvm_runtime_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
endif()
-
-if(USE_ROCM)
- target_link_libraries(tvm_runtime_extra PRIVATE ${ROCM_HIPHCC_LIBRARY})
+if(MSVC)
+ # Runtime objects export only runtime/FFI symbols, never compiler symbols.
+ target_compile_definitions(tvm_runtime_objs PRIVATE TVM_RUNTIME_EXPORTS
TVM_FFI_EXPORTS)
endif()
-# CUTLASS fpA_intB_gemm and flash_attn are separate shared libs.
-if(USE_CUDA AND USE_CUTLASS)
- target_link_libraries(tvm_runtime_extra PRIVATE fpA_intB_gemm
fpA_intB_gemm_tvm)
- target_link_libraries(tvm_runtime_extra PRIVATE -Wl,--no-as-needed
flash_attn)
+# Loaded with RTLD_GLOBAL so downstream runtime modules can resolve its
symbols.
+add_library(tvm_runtime SHARED
+ $<TARGET_OBJECTS:tvm_runtime_objs>
+ ${TVM_RUNTIME_EXT_OBJS}
+)
+target_link_libraries(tvm_runtime PUBLIC tvm_ffi_shared)
+set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS
"${TVM_NO_UNDEFINED_SYMBOLS}")
+set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS
"${TVM_VISIBILITY_FLAG}")
+
+# Static consumers must retain registration objects from both archives, with
+# tvm_ffi_static before tvm_runtime_static so FFI type attributes initialize
first:
+# -Wl,--whole-archive tvm_ffi_static tvm_runtime_static
-Wl,--no-whole-archive
+# Use the corresponding archive-retention flags on other platforms.
+add_library(tvm_runtime_static STATIC
+ $<TARGET_OBJECTS:tvm_runtime_objs>
+ ${TVM_RUNTIME_EXT_OBJS}
+)
+target_link_libraries(tvm_runtime_static PUBLIC tvm_ffi_static)
+if(MSVC)
+ # Static consumers reference ordinary symbols rather than DLL import stubs.
+ target_compile_definitions(tvm_runtime_static INTERFACE
+ TVM_RUNTIME_DLL= TVM_RUNTIME_DLL_EXPORT= TVM_FFI_DLL= TVM_FFI_DLL_EXPORT=)
endif()
-if(TVM_VISIBILITY_FLAG)
- set_property(TARGET tvm_runtime_extra APPEND PROPERTY LINK_OPTIONS
"${TVM_VISIBILITY_FLAG}")
+foreach(runtime_target tvm_runtime tvm_runtime_static)
+ target_include_directories(${runtime_target} PUBLIC
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
+ target_link_libraries(${runtime_target} PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
+ if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
+ target_link_libraries(${runtime_target} PUBLIC Threads::Threads)
+ endif()
+endforeach()
+
+set_target_properties(tvm_runtime tvm_runtime_static PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+)
+if(MSVC)
+ foreach(config_type Release RELEASE Debug DEBUG RelWithDebInfo
RELWITHDEBINFO MinSizeRel MINSIZEREL)
+ set_target_properties(tvm_runtime tvm_runtime_static PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
+ LIBRARY_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
+ RUNTIME_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
+ )
+ endforeach()
endif()
-tvm_configure_target_library(tvm_runtime_extra RUNTIME_MODULE)
+if(TVM_IS_DEBUG_BUILD AND FILE_PREFIX_MAP_SUPPORTED)
+ target_compile_options(tvm_runtime PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
+ target_compile_options(tvm_runtime_objs PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
+endif()
+tvm_ffi_add_apple_dsymutil(tvm_runtime)
+tvm_configure_target_library(tvm_runtime)
+add_custom_target(runtime DEPENDS tvm_runtime tvm_runtime_static)
+install(TARGETS tvm_runtime DESTINATION lib${LIB_SUFFIX})
+# Keep wheel contents unchanged; the archive is available to native consumers.
+if(NOT TVM_BUILD_PYTHON_MODULE)
+ install(TARGETS tvm_runtime_static DESTINATION lib${LIB_SUFFIX})
+endif()
add_library(tvm_objs OBJECT ${COMPILER_SRCS})
-add_library(tvm_runtime_objs OBJECT ${RUNTIME_SRCS})
target_link_libraries(tvm_objs PUBLIC tvm_ffi_header)
-target_link_libraries(tvm_runtime_objs PUBLIC tvm_ffi_header)
if(TARGET tvm_llvm_header)
target_link_libraries(tvm_objs PUBLIC tvm_llvm_header)
endif()
-
-include(GNUInstallDirs)
-
-# Runtime library: built from runtime sources only. Loaded with RTLD_GLOBAL on
-# Linux/macOS so its symbols are exposed to downstream loads (e.g. NVRTC
kernels
-# and other dynamically loaded modules that resolve runtime symbols at link
-# time).
-if(BUILD_STATIC_RUNTIME)
- add_library(tvm_runtime STATIC
- $<TARGET_OBJECTS:tvm_runtime_objs>
- ${TVM_RUNTIME_EXT_OBJS}
- )
- set(NOTICE_MULTILINE
- "You have build static version of the TVM runtime library. Make "
- "sure to use --whole-archive when linking it into your project.")
- string(CONCAT NOTICE ${NOTICE_MULTILINE})
- add_custom_command(TARGET tvm_runtime POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --yellow --bold ${NOTICE})
- target_link_libraries(tvm_runtime PUBLIC tvm_ffi_static)
-else()
- add_library(tvm_runtime SHARED
- $<TARGET_OBJECTS:tvm_runtime_objs>
- ${TVM_RUNTIME_EXT_OBJS}
- )
- set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS
"${TVM_NO_UNDEFINED_SYMBOLS}")
- target_link_libraries(tvm_runtime PUBLIC tvm_ffi_shared)
-endif()
-
-target_include_directories(tvm_runtime PUBLIC
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
-set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS
"${TVM_VISIBILITY_FLAG}")
-# ``-fvisibility=hidden`` only affects symbol export when applied at COMPILE
-# time. Setting it as a link option (above) is preserved for back-compat but
-# is effectively a no-op for visibility — the per-TU compile flag is what
-# actually hides symbols. Apply it to the OBJECT libs that feed both shared
-# libraries.
if(TVM_VISIBILITY_FLAG)
- target_compile_options(tvm_runtime_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
target_compile_options(tvm_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
endif()
+if(MSVC)
+ # Compiler objects import runtime symbols from the separate runtime DLL.
+ target_compile_definitions(tvm_objs PRIVATE TVM_EXPORTS TVM_FFI_EXPORTS)
+endif()
# Compiler library: built from compiler-only sources.
# Links against tvm_runtime (and tvm_ffi_shared transitively). Loaded with
@@ -643,14 +568,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT
"${USE_LLVM}" MATCHES ${IS_FALSE_P
set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS
"-Wl,--as-needed")
endif()
-# Place runtime/compiler/allvisible artifacts under build/lib/ to mirror the
-# tvm-ffi layout and make tvm_ffi.libinfo.load_lib_ctypes(package="tvm") able
-# to discover them in dev / editable builds.
-set_target_properties(tvm_runtime PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
-)
set_target_properties(tvm_compiler PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
@@ -658,11 +575,6 @@ set_target_properties(tvm_compiler PROPERTIES
)
if(MSVC)
foreach(config_type Release RELEASE Debug DEBUG RelWithDebInfo
RELWITHDEBINFO MinSizeRel MINSIZEREL)
- set_target_properties(tvm_runtime PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
- RUNTIME_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
- )
set_target_properties(tvm_compiler PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY_${config_type} "${CMAKE_BINARY_DIR}/lib"
@@ -671,6 +583,22 @@ if(MSVC)
endforeach()
endif()
+if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
+ target_link_libraries(tvm_compiler PUBLIC Threads::Threads)
+endif()
+target_link_libraries(tvm_compiler PRIVATE ${TVM_LINKER_LIBS}
${TVM_RUNTIME_LINKER_LIBS})
+
+if(TVM_IS_DEBUG_BUILD)
+ target_compile_options(tvm_compiler PRIVATE "${FILE_PREFIX_MAP_FLAG}")
+ if(FILE_PREFIX_MAP_SUPPORTED)
+ target_compile_options(tvm_compiler PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
+ target_compile_options(tvm_objs PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
+ endif()
+endif()
+
+tvm_ffi_add_apple_dsymutil(tvm_compiler)
+tvm_configure_target_library(tvm_compiler)
+install(TARGETS tvm_compiler DESTINATION lib${LIB_SUFFIX})
# logging option for libbacktrace
include(cmake/modules/Logging.cmake)
@@ -687,95 +615,9 @@ if(USE_IOS_RPC)
add_subdirectory("apps/ios_rpc")
endif()
-add_subdirectory(3rdparty/tvm-ffi)
-
-if(TVM_DEBUG_WITH_ABI_CHANGE)
- message(STATUS "Building with debug code that may cause ABI changes...")
- target_compile_definitions(tvm_objs PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
- target_compile_definitions(tvm_runtime_objs PRIVATE
"TVM_DEBUG_WITH_ABI_CHANGE")
-endif(TVM_DEBUG_WITH_ABI_CHANGE)
-
-if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
- message(STATUS "Build with thread support...")
- set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
- set(THREADS_PREFER_PTHREAD_FLAG TRUE)
- find_package(Threads REQUIRED)
- target_link_libraries(tvm_compiler PUBLIC Threads::Threads)
- target_link_libraries(tvm_runtime PUBLIC Threads::Threads)
-endif()
-
-target_link_libraries(tvm_compiler PRIVATE ${TVM_LINKER_LIBS})
-
-target_link_libraries(tvm_compiler PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
-target_link_libraries(tvm_runtime PRIVATE ${TVM_RUNTIME_LINKER_LIBS})
-
# Set flags for clang
include(cmake/modules/ClangFlags.cmake)
-set(TVM_TEST_LIBRARY_NAME tvm_compiler)
-
-# Create the `cpptest` target if we can find GTest. If not, we create dummy
-# targets that give the user an informative error message.
-if(GTEST_FOUND)
- tvm_file_glob(GLOB_RECURSE TEST_SRCS tests/cpp/*.cc)
- add_executable(cpptest ${TEST_SRCS})
- # include runtime files for unit testing
- target_link_libraries(cpptest PRIVATE ${TVM_TEST_LIBRARY_NAME} GTest::GTest
GTest::Main GTest::gmock pthread dl)
- if(DEFINED LLVM_LIBS)
- # The TVM library is linked with LLVM libraries. If the LLVM libraries are
- # static and the symbols are not hidden, then don't link them again into
- # cpptest since cpptest is itself linked against the TVM library. If static
- # LLVM libraries are linked in twice, it can cause issues with global
- # variable initialization (cl::opt).
- # If the LLVM libraries are dynamic, we have to link them again, since the
- # TVM library will not contain any LLVM definitions.
- unset(LLVM_SO)
- foreach(L IN LISTS LLVM_LIBS)
- if(L MATCHES "libLLVM.*\.so")
- set(LLVM_SO TRUE)
- break()
- endif()
- endforeach()
- if(DEFINED LLVM_SO OR HIDE_PRIVATE_SYMBOLS)
- target_link_libraries(cpptest PRIVATE ${LLVM_LIBS})
- endif()
- endif()
- set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_ALL 1)
- set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
- # cpptest is built into ${CMAKE_BINARY_DIR} but the TVM shared libs it
- # links against (libtvm_compiler.so / libtvm_runtime.so) now live in
- # ${CMAKE_BINARY_DIR}/lib. CMake's default behaviour bakes the
- # absolute path of build/lib/ into the binary's RUNPATH, which works in tree
- # but is not relocatable. Set $ORIGIN/lib (or @loader_path/lib on macOS)
- # explicitly so the test binary finds its TVM libs relative to its own
- # location, mirroring the install-time RPATH setup.
- if(APPLE)
- set_target_properties(cpptest PROPERTIES
- BUILD_RPATH "@loader_path/lib"
- INSTALL_RPATH "@loader_path/lib"
- )
- elseif(UNIX)
- set_target_properties(cpptest PROPERTIES
- BUILD_RPATH "\$ORIGIN/lib"
- INSTALL_RPATH "\$ORIGIN/lib"
- )
- endif()
- target_compile_definitions(cpptest PRIVATE "NDEBUG")
- if(TVM_DEBUG_WITH_ABI_CHANGE)
- target_compile_definitions(cpptest PRIVATE "TVM_DEBUG_WITH_ABI_CHANGE")
- endif(TVM_DEBUG_WITH_ABI_CHANGE)
-
- # For some reason, compile definitions are not propagated correctly, so we
manually add them here
- target_compile_definitions(cpptest PUBLIC
$<TARGET_PROPERTY:tvm_compiler,INTERFACE_COMPILE_DEFINITIONS>)
- gtest_discover_tests(cpptest)
-endif()
-
-# Custom targets
-add_custom_target(runtime DEPENDS tvm_runtime)
-
# Installation rules
-install(TARGETS tvm_compiler DESTINATION lib${LIB_SUFFIX})
-install(TARGETS tvm_runtime DESTINATION lib${LIB_SUFFIX})
-
if (INSTALL_DEV)
install(
DIRECTORY "include/" DESTINATION "include"
@@ -812,42 +654,6 @@ install(
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
-# More target definitions
-if(MSVC)
- # tvm_objs builds libtvm_compiler.dll → TVM_DLL=dllexport,
- # but TVM_RUNTIME_DLL=dllimport (runtime symbols come from
libtvm_runtime.dll).
- target_compile_definitions(tvm_objs PRIVATE -DTVM_EXPORTS -DTVM_FFI_EXPORTS)
- # tvm_runtime_objs builds libtvm_runtime.dll → TVM_RUNTIME_DLL=dllexport.
- # No TVM_EXPORTS here: the runtime side never defines compiler-exported
- # symbols, so leaving TVM_DLL as dllimport correctly fails any accidental
- # use of compiler-side ``TVM_DLL`` symbols from a runtime TU.
- target_compile_definitions(tvm_runtime_objs PRIVATE -DTVM_RUNTIME_EXPORTS
-DTVM_FFI_EXPORTS)
-endif()
-
-set(TVM_IS_DEBUG_BUILD OFF)
-if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL
"RelWithDebInfo" OR CMAKE_CXX_FLAGS MATCHES "-g")
- set(TVM_IS_DEBUG_BUILD ON)
-endif()
-
-# Change relative paths in backtrace to absolute ones
-if(TVM_IS_DEBUG_BUILD)
- set(FILE_PREFIX_MAP_FLAG "-ffile-prefix-map=..=${CMAKE_CURRENT_SOURCE_DIR}")
- target_compile_options(tvm_compiler PRIVATE "${FILE_PREFIX_MAP_FLAG}")
- CHECK_CXX_COMPILER_FLAG("${FILE_PREFIX_MAP_FLAG}" FILE_PREFIX_MAP_SUPPORTED)
- if(FILE_PREFIX_MAP_SUPPORTED)
- target_compile_options(tvm_compiler PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
- target_compile_options(tvm_objs PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
- target_compile_options(tvm_runtime PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
- target_compile_options(tvm_runtime_objs PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${FILE_PREFIX_MAP_FLAG}>)
- endif()
-endif()
-
-tvm_ffi_add_apple_dsymutil(tvm_compiler)
-# Only run dsymutil on shared libraries, not static libraries
-if(NOT BUILD_STATIC_RUNTIME)
- tvm_ffi_add_apple_dsymutil(tvm_runtime)
-endif()
-
if(BUILD_FOR_HEXAGON)
# Wrap pthread_create to allow setting custom stack size.
set_property(TARGET tvm_runtime APPEND PROPERTY LINK_FLAGS
@@ -856,7 +662,8 @@ if(BUILD_FOR_HEXAGON)
# as a part of the "runtime" target.
if(USE_HEXAGON_RPC)
target_link_libraries(
- hexagon_rpc_skel -Wl,--whole-archive tvm_runtime tvm_ffi_static
-Wl,--no-whole-archive)
+ hexagon_rpc_skel -Wl,--whole-archive tvm_ffi_static tvm_runtime_static
-Wl,--no-whole-archive)
+ target_link_options(hexagon_rpc_skel PRIVATE "-Wl,--wrap=pthread_create")
add_dependencies(runtime hexagon_rpc_skel)
endif()
endif()
@@ -873,23 +680,20 @@ if(USE_CUDA AND USE_CUTLASS)
install(TARGETS fpA_intB_gemm EXPORT ${PROJECT_NAME}Targets DESTINATION
lib${LIB_SUFFIX})
install(TARGETS flash_attn EXPORT ${PROJECT_NAME}Targets DESTINATION
lib${LIB_SUFFIX})
# fpA_intB_gemm, fpA_intB_gemm_tvm, and flash_attn are linked by
- # tvm_runtime_extra (see the inline assembly block above); no link needed
here.
+ # tvm_runtime_extra (see RuntimeExtra.cmake); no link needed here.
endif()
if(USE_CUDA AND USE_NVTX)
add_compile_definitions(TVM_NVTX_ENABLED=1)
endif()
-# Note: NCCL, NVSHMEM, RCCL target_link_libraries are handled in the inline
-# libtvm_runtime_extra assembly block above.
-
-# Keep the core shared libraries relocatable. A relative rpath
-# ($ORIGIN / @loader_path) is correct in any build because the sibling runtime
-# DSOs are installed next to each other, so apply it unconditionally rather
than
-# only when building the Python wheel. (tvm_runtime_extra already gets its
rpath
-# where it is defined above.)
-tvm_configure_target_library(tvm_compiler)
-tvm_configure_target_library(tvm_runtime)
+# Tests inherit the final project linker flags and compile definitions.
+add_subdirectory(tests/cpp)
+if(GTEST_FOUND)
+ # CTest must also be enabled at the project root for subdirectory discovery.
+ enable_testing()
+ include(CTest)
+endif()
# Python package installation configuration
# This section ensures that all necessary files are installed for the Python
wheel
diff --git a/apps/cpp_rpc/CMakeLists.txt b/apps/cpp_rpc/CMakeLists.txt
index f8e0a05690..e24c1c9ccb 100644
--- a/apps/cpp_rpc/CMakeLists.txt
+++ b/apps/cpp_rpc/CMakeLists.txt
@@ -61,22 +61,10 @@ if (BUILD_FOR_ANDROID AND USE_HEXAGON)
list(APPEND TVM_RPC_LINKER_LIBS cdsprpc log)
endif()
-if(BUILD_STATIC_RUNTIME)
- foreach(lib ${TVM_RUNTIME_BACKEND_LIBS})
- if(MSVC)
- list(APPEND TVM_RPC_LINKER_LIBS "/WHOLEARCHIVE:$<TARGET_FILE:${lib}>")
- elseif(APPLE)
- list(APPEND TVM_RPC_LINKER_LIBS "-Wl,-force_load,$<TARGET_FILE:${lib}>")
- else()
- list(APPEND TVM_RPC_LINKER_LIBS "-Wl,--whole-archive" "${lib}"
"-Wl,--no-whole-archive")
- endif()
- endforeach()
+if(NOT MSVC AND NOT APPLE)
+ list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime "-Wl,--no-as-needed"
${TVM_RUNTIME_BACKEND_LIBS} "-Wl,--as-needed")
else()
- if(NOT MSVC AND NOT APPLE)
- list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime "-Wl,--no-as-needed"
${TVM_RUNTIME_BACKEND_LIBS} "-Wl,--as-needed")
- else()
- list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime ${TVM_RUNTIME_BACKEND_LIBS})
- endif()
+ list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime ${TVM_RUNTIME_BACKEND_LIBS})
endif()
target_link_libraries(tvm_rpc PRIVATE ${TVM_RPC_LINKER_LIBS})
diff --git a/cmake/config.cmake b/cmake/config.cmake
index 83e81aa137..247b00d319 100644
--- a/cmake/config.cmake
+++ b/cmake/config.cmake
@@ -241,17 +241,17 @@ set(USE_HEXAGON_ARCH "v68")
# Whether to use QHL library
set(USE_HEXAGON_QHL OFF)
-# Whether to build static libtvm_runtime.a, the default is to build the dynamic
-# version: libtvm_runtime.so.
+# Both libtvm_runtime.so and libtvm_runtime_static.a are built by default.
#
-# The static runtime library needs to be linked into executables with the
linker
-# option --whole-archive (or its equivalent). The reason is that the TVM
registry
-# mechanism relies on global constructors being executed at program startup.
+# Link both static archives with tvm_ffi_static before tvm_runtime_static so
+# FFI type attributes initialize before runtime registrations. Retain both with
+# --whole-archive (or its equivalent), for example:
+# -Wl,--whole-archive -ltvm_ffi_static -ltvm_runtime_static
-Wl,--no-whole-archive
+# The TVM registry relies on global constructors being executed at program
startup.
# Global constructors alone are not sufficient for the linker to consider a
# library member to be used, and some of such library members (object files)
may
# not be included in the final executable. This would make the corresponding
# runtime functions to be unavailable to the program.
-set(BUILD_STATIC_RUNTIME OFF)
# Caches the build so that building is faster when switching between branches.
# If you switch branches, build and then encounter a linking error, you may
diff --git a/cmake/modules/OpenCL.cmake b/cmake/modules/OpenCL.cmake
index becbfa7a1d..4a398ae79f 100644
--- a/cmake/modules/OpenCL.cmake
+++ b/cmake/modules/OpenCL.cmake
@@ -21,9 +21,10 @@ if(USE_OPENCL)
set(_opencl_libs "")
if(${USE_OPENCL} MATCHES ${IS_TRUE_PATTERN})
message(STATUS "Enabled runtime search for OpenCL library location")
- file_glob_append(RUNTIME_OPENCL_SRCS
+ tvm_file_glob(GLOB OPENCL_WRAPPER_SRCS
"src/backend/opencl/runtime/opencl_wrapper/opencl_wrapper.cc"
)
+ list(APPEND RUNTIME_OPENCL_SRCS ${OPENCL_WRAPPER_SRCS})
set(_opencl_include_dirs
"${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/OpenCL-Headers")
else()
find_opencl(${USE_OPENCL})
diff --git a/cmake/modules/RuntimeExtra.cmake b/cmake/modules/RuntimeExtra.cmake
new file mode 100644
index 0000000000..a1bcb50174
--- /dev/null
+++ b/cmake/modules/RuntimeExtra.cmake
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+# Assemble the runtime-extra target declared before the backend modules.
+# Disco core sources.
+tvm_file_glob(GLOB _disco_core_srcs src/runtime/extra/disco/*.cc)
+add_library(tvm_disco_objs OBJECT ${_disco_core_srcs})
+target_link_libraries(tvm_disco_objs PRIVATE tvm_runtime_extra_defs)
+target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_objs)
+
+# Distributed disco (disabled for Hexagon cross-compile).
+if(NOT BUILD_FOR_HEXAGON)
+ tvm_file_glob(GLOB _disco_dist_srcs src/runtime/extra/disco/distributed/*.cc)
+ add_library(tvm_disco_distributed_objs OBJECT ${_disco_dist_srcs})
+ target_link_libraries(tvm_disco_distributed_objs PRIVATE
tvm_runtime_extra_defs)
+ target_link_libraries(tvm_runtime_extra PRIVATE tvm_disco_distributed_objs)
+endif()
+
+# NCCL / cuda_ipc — requires CUDA + NCCL.
+if(USE_CUDA AND USE_NCCL)
+ find_nccl(${USE_NCCL})
+ include_directories(SYSTEM ${NCCL_INCLUDE_DIR})
+ tvm_file_glob(GLOB _nccl_srcs src/runtime/extra/disco/nccl/*.cc
src/runtime/extra/disco/cuda_ipc/*.cc 3rdparty/tensorrt_llm/*.cu)
+ set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES
COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=0")
+ add_library(tvm_nccl_objs OBJECT ${_nccl_srcs})
+ target_link_libraries(tvm_nccl_objs PRIVATE tvm_runtime_extra_defs)
+ find_library(LIBRT rt)
+ target_link_libraries(tvm_runtime_extra PRIVATE tvm_nccl_objs nccl ${LIBRT})
+endif()
+
+# NVSHMEM.
+if(USE_CUDA AND USE_NVSHMEM)
+ find_nvshmem(${USE_NVSHMEM})
+ if(NOT NVSHMEM_FOUND)
+ message(FATAL_ERROR "Cannot find NVSHMEM, USE_NVSHMEM=" ${USE_NVSHMEM})
+ endif()
+ set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+ tvm_file_glob(GLOB _nvshmem_srcs src/runtime/extra/contrib/nvshmem/*.cc
src/runtime/extra/contrib/nvshmem/*.cu)
+ add_library(tvm_nvshmem_objs OBJECT ${_nvshmem_srcs})
+ target_link_libraries(tvm_nvshmem_objs PRIVATE tvm_runtime_extra_defs)
+ target_include_directories(tvm_nvshmem_objs PUBLIC ${NVSHMEM_INCLUDE_DIR})
+ # CUDA 13 moved libcu++ under include/cccl. NVSHMEM's headers include
+ # <cuda/std/...>, which nvcc resolves on its own -- the host compiler
+ # building this target's .cc sources does not, so name the directory.
+ if(EXISTS "${CUDA_TOOLKIT_ROOT_DIR}/include/cccl")
+ target_include_directories(tvm_nvshmem_objs SYSTEM PUBLIC
+ "${CUDA_TOOLKIT_ROOT_DIR}/include/cccl")
+ endif()
+ find_library(NVSHMEM_HOST nvshmem_host ${NVSHMEM_LIB_DIR})
+ find_library(NVSHMEM_DEVICE nvshmem_device ${NVSHMEM_LIB_DIR})
+ target_link_libraries(tvm_runtime_extra PRIVATE tvm_nvshmem_objs
${NVSHMEM_HOST} ${NVSHMEM_DEVICE})
+ set_target_properties(tvm_runtime_extra PROPERTIES
CUDA_SEPARABLE_COMPILATION ON)
+endif()
+
+# RCCL.
+if(USE_ROCM AND USE_RCCL)
+ find_rccl(${USE_RCCL})
+ include_directories(SYSTEM ${RCCL_INCLUDE_DIR})
+ tvm_file_glob(GLOB _rccl_srcs src/runtime/extra/disco/nccl/*.cc)
+ set_source_files_properties(src/runtime/extra/disco/nccl/nccl.cc PROPERTIES
COMPILE_DEFINITIONS "TVM_NCCL_RCCL_SWITCH=1")
+ add_library(tvm_rccl_objs OBJECT ${_rccl_srcs})
+ target_link_libraries(tvm_rccl_objs PRIVATE tvm_runtime_extra_defs)
+ target_link_libraries(tvm_runtime_extra PRIVATE tvm_rccl_objs rccl)
+endif()
+
+target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime)
+
+# If disco/cuda_ipc is included, link the CUDA DSO.
+if(USE_CUDA)
+ target_link_libraries(tvm_runtime_extra PUBLIC tvm_runtime_cuda)
+ target_link_libraries(tvm_runtime_extra PRIVATE ${CUDA_CUDART_LIBRARY}
${CUDA_CUDA_LIBRARY})
+endif()
+
+if(USE_ROCM)
+ target_link_libraries(tvm_runtime_extra PRIVATE ${ROCM_HIPHCC_LIBRARY})
+endif()
+
+# CUTLASS fpA_intB_gemm and flash_attn are separate shared libs.
+if(USE_CUDA AND USE_CUTLASS)
+ target_link_libraries(tvm_runtime_extra PRIVATE fpA_intB_gemm
fpA_intB_gemm_tvm)
+ target_link_libraries(tvm_runtime_extra PRIVATE -Wl,--no-as-needed
flash_attn)
+endif()
+
+if(TVM_VISIBILITY_FLAG)
+ set_property(TARGET tvm_runtime_extra APPEND PROPERTY LINK_OPTIONS
"${TVM_VISIBILITY_FLAG}")
+endif()
+
+tvm_configure_target_library(tvm_runtime_extra RUNTIME_MODULE)
diff --git a/tests/cpp/CMakeLists.txt b/tests/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..35c9fadb9e
--- /dev/null
+++ b/tests/cpp/CMakeLists.txt
@@ -0,0 +1,109 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+# Enable ctest if gtest is available
+if(USE_GTEST)
+ # Check env var for backward compatibility. A better way to specify package
+ # locations is to use CMAKE_PREFIX_PATH or other standard CMake mechanism
+ # (see CMake documentation for `find_package`).
+ set(GTEST_ROOT "$ENV{GTEST_LIB}")
+ if("${USE_GTEST}" STREQUAL "AUTO")
+ # If USE_GTEST is AUTO, treat GTest as optional: enable if found.
+ find_package(GTest)
+ elseif("${USE_GTEST}" MATCHES ${IS_TRUE_PATTERN})
+ # USE_GTEST is set to ON, TRUE, etc. Treat GTest as a required package.
+ find_package(GTest REQUIRED)
+ endif()
+ if(GTEST_FOUND)
+ if(NOT TARGET GTest::gmock)
+ # GMock is formally supported in CMake 3.20; for now, expect libgmock.a
in the same directory,
+ # and require that folks compiling against GTest::gmock also link
against GTest::GTest
+ # (for the includes dir).
+ add_library(GTest::gmock STATIC IMPORTED GLOBAL)
+ get_target_property(GTEST_LIB_PATH GTest::GTest IMPORTED_LOCATION)
+ if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
+ # CMake >= 3.20 makes GTest::GTest into a compatibility target. The
real import location is in
+ # GTest::gtest.
+ get_target_property(GTEST_LIB_PATH GTest::gtest IMPORTED_LOCATION)
+ if("${GTEST_LIB_PATH}" STREQUAL "GTEST_LIB_PATH-NOTFOUND")
+ message(FATAL_ERROR "Neither GTest::GTest nor GTest::gtest targets
defined IMPORTED_LOCATION")
+ endif()
+ endif()
+ get_filename_component(GTEST_LIB_DIR "${GTEST_LIB_PATH}" DIRECTORY)
+ set_target_properties(GTest::gmock PROPERTIES
+ IMPORTED_LOCATION "${GTEST_LIB_DIR}/libgmock.a")
+ endif()
+
+ enable_testing()
+ include(GoogleTest)
+ set(GTEST_FOUND TRUE PARENT_SCOPE)
+ endif()
+endif()
+
+# Create the `cpptest` target when GTest is available.
+if(GTEST_FOUND)
+ tvm_file_glob(GLOB_RECURSE TEST_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*.cc")
+ add_executable(cpptest ${TEST_SRCS})
+ # Preserve the executable location used before this became a subdirectory.
+ set_target_properties(cpptest PROPERTIES RUNTIME_OUTPUT_DIRECTORY
"${PROJECT_BINARY_DIR}")
+ # include runtime files for unit testing
+ target_link_libraries(cpptest PRIVATE tvm_compiler GTest::GTest GTest::Main
GTest::gmock pthread dl)
+ if(DEFINED LLVM_LIBS)
+ # The TVM library is linked with LLVM libraries. If the LLVM libraries are
+ # static and the symbols are not hidden, then don't link them again into
+ # cpptest since cpptest is itself linked against the TVM library. If static
+ # LLVM libraries are linked in twice, it can cause issues with global
+ # variable initialization (cl::opt).
+ # If the LLVM libraries are dynamic, we have to link them again, since the
+ # TVM library will not contain any LLVM definitions.
+ unset(LLVM_SO)
+ foreach(L IN LISTS LLVM_LIBS)
+ if(L MATCHES "libLLVM.*\.so")
+ set(LLVM_SO TRUE)
+ break()
+ endif()
+ endforeach()
+ if(DEFINED LLVM_SO OR HIDE_PRIVATE_SYMBOLS)
+ target_link_libraries(cpptest PRIVATE ${LLVM_LIBS})
+ endif()
+ endif()
+ set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_ALL 1)
+ set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
+ # cpptest is built into ${CMAKE_BINARY_DIR} but the TVM shared libs it
+ # links against (libtvm_compiler.so / libtvm_runtime.so) now live in
+ # ${CMAKE_BINARY_DIR}/lib. CMake's default behaviour bakes the
+ # absolute path of build/lib/ into the binary's RUNPATH, which works in tree
+ # but is not relocatable. Set $ORIGIN/lib (or @loader_path/lib on macOS)
+ # explicitly so the test binary finds its TVM libs relative to its own
+ # location, mirroring the install-time RPATH setup.
+ if(APPLE)
+ set_target_properties(cpptest PROPERTIES
+ BUILD_RPATH "@loader_path/lib"
+ INSTALL_RPATH "@loader_path/lib"
+ )
+ elseif(UNIX)
+ set_target_properties(cpptest PROPERTIES
+ BUILD_RPATH "\$ORIGIN/lib"
+ INSTALL_RPATH "\$ORIGIN/lib"
+ )
+ endif()
+ target_compile_definitions(cpptest PRIVATE "NDEBUG")
+
+ # For some reason, compile definitions are not propagated correctly, so we
manually add them here
+ target_compile_definitions(cpptest PUBLIC
$<TARGET_PROPERTY:tvm_compiler,INTERFACE_COMPILE_DEFINITIONS>)
+ gtest_discover_tests(cpptest WORKING_DIRECTORY "${PROJECT_BINARY_DIR}")
+endif()