This is an automated email from the ASF dual-hosted git repository.

junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new ccd19f8  feat(cmake): Introduce `tvm_ffi_configure_target` and 
`tvm_ffi_install` (#351)
ccd19f8 is described below

commit ccd19f8202a980bd03501a62600e338fa883f80c
Author: Junru Shao <[email protected]>
AuthorDate: Sat Dec 20 10:17:56 2025 -0800

    feat(cmake): Introduce `tvm_ffi_configure_target` and `tvm_ffi_install` 
(#351)
    
    Similar to
    
[`pybind11-add-module`](https://pybind11.readthedocs.io/en/stable/compiling.html#pybind11-add-module)
    and
    
[`nanobind_add_module`](https://nanobind.readthedocs.io/en/latest/api_cmake.html#command:nanobind_add_module),
    this PR introduces two convenient CMake methods to help integrate CMake
    targets with TVM-FFI.
---
 cmake/Utils/Library.cmake                          | 262 ++++++++++++++++++++-
 examples/packaging/CMakeLists.txt                  |  52 +---
 .../packaging/python/my_ffi_extension/_ffi_api.py  |   2 +-
 3 files changed, 263 insertions(+), 53 deletions(-)

diff --git a/cmake/Utils/Library.cmake b/cmake/Utils/Library.cmake
index 73817e9..012b3ca 100644
--- a/cmake/Utils/Library.cmake
+++ b/cmake/Utils/Library.cmake
@@ -14,7 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
 # ~~~
 # tvm_ffi_add_prefix_map(target_name, prefix_path)
 # Add a compile prefix map so absolute paths under `prefix_path` are remapped 
to a stable,
@@ -34,14 +33,14 @@ endfunction ()
 # ~~~
 # tvm_ffi_add_apple_dsymutil(target_name)
 # On Apple platforms, run `dsymutil` post-build to generate debug symbols for 
better backtraces.
-# No-ops on non-Apple or when libbacktrace is disabled.
+# No-ops on non-Apple platforms.
 #
 # Parameters:
 #   target_name: CMake target to attach post-build step
 # ~~~
 function (tvm_ffi_add_apple_dsymutil target_name)
   # running dsymutil on macos to generate debugging symbols for backtraces
-  if (APPLE AND TVM_FFI_USE_LIBBACKTRACE)
+  if (APPLE)
     find_program(DSYMUTIL dsymutil)
     mark_as_advanced(DSYMUTIL)
     add_custom_command(
@@ -137,3 +136,260 @@ function (tvm_ffi_add_target_from_obj target_name 
obj_target_name)
   tvm_ffi_add_apple_dsymutil(${target_name}_shared)
   tvm_ffi_add_apple_dsymutil(${target_name}_testing)
 endfunction ()
+
+# cmake-lint: disable=C0301,R0912,R0915
+# ~~~
+# tvm_ffi_configure_target(
+#   target_name
+#   [LINK_SHARED ON|OFF] [LINK_HEADER ON|OFF] [DEBUG_SYMBOL ON|OFF] 
[MSVC_FLAGS ON|OFF]
+#   [STUB_INIT ON|OFF] [STUB_DIR <dir>] [STUB_PKG <pkg>] [STUB_PREFIX <prefix>]
+# )
+# Configure a target to integrate with TVM-FFI CMake utilities:
+#   - Optionally link against tvm_ffi_header and/or tvm_ffi_shared
+#   - Always apply tvm_ffi_add_prefix_map(target_name <current source dir>)
+#   - Optionally enable Apple dSYM generation via 
tvm_ffi_add_apple_dsymutil(target_name)
+#   - Optionally apply MSVC-specific flags via 
tvm_ffi_add_msvc_flags(target_name)
+#
+# Parameters:
+#   target_name: Existing CMake target to modify (positional, required)
+#
+# Keyword parameters:
+#   LINK_SHARED:  Whether to link tvm_ffi_shared into the target (default: ON; 
ON/OFF-style)
+#   LINK_HEADER:  Whether to link tvm_ffi_header into the target (default: ON; 
ON/OFF-style)
+#   DEBUG_SYMBOL: Whether to enable debug symbol post-processing hooks.
+#                 On Apple this calls tvm_ffi_add_apple_dsymutil(target_name) 
(default: ON; ON/OFF-style)
+#                 On non-Apple platforms this is currently a no-op unless you 
extend it. (default: ON)
+#   MSVC_FLAGS:   Whether to call tvm_ffi_add_msvc_flags(target_name) to apply 
MSVC-specific flags (default: ON; ON/OFF-style)
+#   STUB_DIR:     Stub generation runs when this is set. Directory to generate 
Python stubs. Relative paths resolve against CMAKE_CURRENT_SOURCE_DIR.
+#   STUB_INIT:    Whether to allow generating new directives. Default: OFF 
(ON/OFF-style)
+#   STUB_PKG:     Package name passed to stub generator (requires STUB_DIR and 
STUB_INIT=ON; default: ${SKBUILD_PROJECT_NAME} if set, otherwise target name)
+#   STUB_PREFIX:  Module prefix passed to stub generator (requires STUB_DIR 
and STUB_INIT=ON; default: "<STUB_PKG>.")
+# ~~~
+function (tvm_ffi_configure_target target)
+  if (NOT target)
+    message(
+      FATAL_ERROR
+        "tvm_ffi_configure_target: missing target name. "
+        "Usage: tvm_ffi_configure_target(<target> [LINK_SHARED ON|OFF] 
[LINK_HEADER ON|OFF] [DEBUG_SYMBOL ON|OFF] [MSVC_FLAGS ON|OFF] [STUB_INIT 
ON|OFF] [STUB_DIR <dir>] [STUB_PKG <pkg>] [STUB_PREFIX <prefix>])"
+    )
+  endif ()
+
+  if (NOT TARGET "${target}")
+    message(FATAL_ERROR "tvm_ffi_configure_target: '${target}' is not an 
existing CMake target.")
+  endif ()
+
+  # Parse keyword args after the positional target name.
+  set(tvm_ffi_arg_options) # none; require explicit ON/OFF style values
+  set(tvm_ffi_arg_oneValueArgs
+      LINK_SHARED
+      LINK_HEADER
+      DEBUG_SYMBOL
+      MSVC_FLAGS
+      STUB_INIT
+      STUB_DIR
+      STUB_PKG
+      STUB_PREFIX
+  )
+  set(tvm_ffi_arg_multiValueArgs)
+
+  cmake_parse_arguments(
+    tvm_ffi_arg_ "${tvm_ffi_arg_options}" "${tvm_ffi_arg_oneValueArgs}"
+    "${tvm_ffi_arg_multiValueArgs}" ${ARGN}
+  )
+
+  # Defaults
+  foreach (arg IN ITEMS LINK_SHARED LINK_HEADER DEBUG_SYMBOL MSVC_FLAGS)
+    if (NOT DEFINED tvm_ffi_arg__${arg})
+      set(tvm_ffi_arg__${arg} ON)
+    endif ()
+  endforeach ()
+  if (NOT DEFINED tvm_ffi_arg__STUB_INIT)
+    set(tvm_ffi_arg__STUB_INIT OFF)
+  endif ()
+
+  # Validation
+  if ((NOT DEFINED tvm_ffi_arg__STUB_DIR) OR (NOT tvm_ffi_arg__STUB_DIR))
+    if (DEFINED tvm_ffi_arg__STUB_PKG OR DEFINED tvm_ffi_arg__STUB_PREFIX)
+      message(
+        FATAL_ERROR
+          "tvm_ffi_configure_target(${target}): STUB_PKG/STUB_PREFIX require 
STUB_DIR to be set."
+      )
+    endif ()
+  endif ()
+  if (NOT tvm_ffi_arg__STUB_INIT)
+    if (DEFINED tvm_ffi_arg__STUB_PKG OR DEFINED tvm_ffi_arg__STUB_PREFIX)
+      message(
+        FATAL_ERROR
+          "tvm_ffi_configure_target(${target}): STUB_PKG/STUB_PREFIX cannot be 
set when STUB_INIT is OFF."
+      )
+    endif ()
+  else ()
+    if (NOT DEFINED tvm_ffi_arg__STUB_DIR OR NOT tvm_ffi_arg__STUB_DIR)
+      message(
+        FATAL_ERROR "tvm_ffi_configure_target(${target}): STUB_INIT=ON 
requires STUB_DIR to be set."
+      )
+    endif ()
+  endif ()
+
+  # STUB_PKG and STUB_PREFIX defaults
+  if (tvm_ffi_arg__STUB_INIT AND tvm_ffi_arg__STUB_DIR)
+    if (NOT DEFINED tvm_ffi_arg__STUB_PKG)
+      if (DEFINED SKBUILD_PROJECT_NAME AND SKBUILD_PROJECT_NAME)
+        set(tvm_ffi_arg__STUB_PKG "${SKBUILD_PROJECT_NAME}")
+      else ()
+        set(tvm_ffi_arg__STUB_PKG "${target}")
+      endif ()
+    endif ()
+    if (NOT DEFINED tvm_ffi_arg__STUB_PREFIX)
+      set(tvm_ffi_arg__STUB_PREFIX "${tvm_ffi_arg__STUB_PKG}.")
+    endif ()
+  endif ()
+
+  # Always-on prefix map
+  if (COMMAND tvm_ffi_add_prefix_map)
+    tvm_ffi_add_prefix_map("${target}" "${CMAKE_CURRENT_SOURCE_DIR}")
+  else ()
+    message(
+      FATAL_ERROR
+        "tvm_ffi_configure_target(${target}): required function 
'tvm_ffi_add_prefix_map' is not defined/included."
+    )
+  endif ()
+
+  # LINK_HEADER
+  if (tvm_ffi_arg__LINK_HEADER)
+    if (TARGET tvm_ffi_header)
+      target_link_libraries("${target}" PRIVATE tvm_ffi_header)
+    else ()
+      message(
+        FATAL_ERROR
+          "tvm_ffi_configure_target(${target}): LINK_HEADER requested but 
target 'tvm_ffi_header' does not exist."
+      )
+    endif ()
+  endif ()
+
+  # LINK_SHARED
+  if (tvm_ffi_arg__LINK_SHARED)
+    if (TARGET tvm_ffi_shared)
+      target_link_libraries("${target}" PRIVATE tvm_ffi_shared)
+    else ()
+      message(
+        FATAL_ERROR
+          "tvm_ffi_configure_target(${target}): LINK_SHARED requested but 
target 'tvm_ffi_shared' does not exist."
+      )
+    endif ()
+  endif ()
+
+  # DEBUG_SYMBOL (default ON). Apple behavior only (hook only; installation 
handled by
+  # tvm_ffi_install()).
+  if (tvm_ffi_arg__DEBUG_SYMBOL)
+    if (APPLE)
+      if (COMMAND tvm_ffi_add_apple_dsymutil)
+        tvm_ffi_add_apple_dsymutil("${target}")
+      else ()
+        message(
+          FATAL_ERROR
+            "tvm_ffi_configure_target(${target}): DEBUG_SYMBOL=ON but 
'tvm_ffi_add_apple_dsymutil' is not defined/included."
+        )
+      endif ()
+    endif ()
+  endif ()
+
+  # Optional: MSVC flags
+  if (tvm_ffi_arg__MSVC_FLAGS)
+    if (COMMAND tvm_ffi_add_msvc_flags)
+      tvm_ffi_add_msvc_flags("${target}")
+    else ()
+      message(
+        FATAL_ERROR
+          "tvm_ffi_configure_target(${target}): MSVC_FLAGS=ON but 
'tvm_ffi_add_msvc_flags' is not defined/included."
+      )
+    endif ()
+  endif ()
+
+  if (DEFINED tvm_ffi_arg__STUB_DIR AND tvm_ffi_arg__STUB_DIR)
+    get_filename_component(
+      tvm_ffi_arg__STUB_DIR_ABS "${tvm_ffi_arg__STUB_DIR}" ABSOLUTE BASE_DIR
+      "${CMAKE_CURRENT_SOURCE_DIR}"
+    )
+    find_package(
+      Python3
+      COMPONENTS Interpreter
+      REQUIRED
+    )
+    set(tvm_ffi_stub_cli_args "${tvm_ffi_arg__STUB_DIR_ABS}" --dlls 
$<TARGET_FILE:${target}>)
+    if (tvm_ffi_arg__STUB_INIT)
+      list(
+        APPEND
+        tvm_ffi_stub_cli_args
+        --init-lib
+        ${target}
+        --init-pypkg
+        "${tvm_ffi_arg__STUB_PKG}"
+        --init-prefix
+        "${tvm_ffi_arg__STUB_PREFIX}"
+      )
+    endif ()
+    add_custom_command(
+      TARGET ${target}
+      POST_BUILD
+      COMMAND ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli 
${tvm_ffi_stub_cli_args}
+      COMMENT
+        "[COMMAND] Running: ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli 
${tvm_ffi_stub_cli_args}"
+      VERBATIM
+    )
+  endif ()
+endfunction ()
+
+# ~~~
+# tvm_ffi_install(target_name [DESTINATION <dir>])
+# Install TVM-FFI related artifacts for a configured target.
+#
+# Parameters:
+#   target_name: Existing CMake target whose artifacts should be installed
+#
+# Keyword parameters:
+#   DESTINATION: Install destination directory relative to 
CMAKE_INSTALL_PREFIX (default: ".")
+#
+# Behavior:
+#   - On Apple, installs the target's dSYM bundle if it exists.
+#     This uses generator expressions and OPTIONAL so it does not fail if the 
dSYM is absent.
+#   - On non-Apple platforms, currently no-op (extend as needed for PDB/DWARF 
packaging).
+#
+# Notes:
+#   - This function does not create dSYMs; it only installs them if present.
+#     Pair it with tvm_ffi_configure_target(... DEBUG_SYMBOL ON) to enable 
dSYM generation hooks.
+# ~~~
+function (tvm_ffi_install target)
+  if (NOT target)
+    message(
+      FATAL_ERROR
+        "tvm_ffi_install: missing target name. Usage: tvm_ffi_install(<target> 
[DESTINATION <dir>])"
+    )
+  endif ()
+
+  if (NOT TARGET "${target}")
+    message(FATAL_ERROR "tvm_ffi_install: '${target}' is not an existing CMake 
target.")
+  endif ()
+
+  set(tvm_ffi_install_options) # none
+  set(tvm_ffi_install_oneValueArgs DESTINATION)
+  set(tvm_ffi_install_multiValueArgs)
+
+  cmake_parse_arguments(
+    tvm_ffi_install_ "${tvm_ffi_install_options}" 
"${tvm_ffi_install_oneValueArgs}"
+    "${tvm_ffi_install_multiValueArgs}" ${ARGN}
+  )
+
+  if (NOT DEFINED tvm_ffi_install__DESTINATION)
+    set(tvm_ffi_install__DESTINATION ".")
+  endif ()
+
+  if (APPLE)
+    # Install target dSYM bundle if present.
+    install(
+      DIRECTORY "$<TARGET_FILE:${target}>.dSYM"
+      DESTINATION "${tvm_ffi_install__DESTINATION}"
+      OPTIONAL
+    )
+  endif ()
+endfunction ()
diff --git a/examples/packaging/CMakeLists.txt 
b/examples/packaging/CMakeLists.txt
index 3648da6..9b9fa80 100644
--- a/examples/packaging/CMakeLists.txt
+++ b/examples/packaging/CMakeLists.txt
@@ -14,62 +14,16 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
 cmake_minimum_required(VERSION 3.18)
 project(my_ffi_extension)
 
-option(TVM_FFI_EXT_FROM_SOURCE "Build tvm_ffi from source, useful for cross 
compilation." ON)
-option(TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS "Ship debug symbols" ON)
-
-# There are two ways to include tvm_ffi
-#
-# 1. Build tvm_ffi from source, which is reasonably cheap since tvm ffi is 
small
-# 2. Use the pre-built tvm_ffi shipped from the pip
-#
-# This example shows both options, you only need to pick a specific one.
-#
-# * For common build cases, using pre-built and link tvm_ffi_shared is 
sufficient.
-# * For cases where you may want to cross-compile or bundle part of 
tvm_ffi_objects directly into
-#   your project, opt for building tvm_ffi from source path. Note that it is 
always safe to build
-#   from source and extra cost of building tvm_ffi is small. So when in doubt, 
you can always choose
-#   to the building tvm_ffi from source route.
-#
-# In python or other cases when we dynamically load libtvm_ffi_shared. Even 
when you build from
-# source, you do not need to ship libtvm_ffi.so built here as they are only 
used to supply the
-# linking information. first find python related components
 find_package(
   Python
   COMPONENTS Interpreter
   REQUIRED
 )
-if (TVM_FFI_BUILD_FROM_SOURCE)
-  execute_process(
-    COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --sourcedir
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    OUTPUT_VARIABLE tvm_ffi_ROOT
-  )
-  message(STATUS "Building tvm_ffi from source: ${tvm_ffi_ROOT}")
-  add_subdirectory(${tvm_ffi_ROOT} tvm_ffi)
-else ()
-  # tvm_ffi is installed via pip. Try to find tvm_ffi automatically
-  find_package(tvm_ffi CONFIG REQUIRED)
-endif ()
-
-# use the projects as usual
+find_package(tvm_ffi CONFIG REQUIRED)
 add_library(my_ffi_extension SHARED src/extension.cc)
-target_link_libraries(my_ffi_extension tvm_ffi_header)
-target_link_libraries(my_ffi_extension tvm_ffi_shared)
-
-if (TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS)
-  # ship debugging symbols for backtrace on macos
-  tvm_ffi_add_prefix_map(my_ffi_extension ${CMAKE_CURRENT_SOURCE_DIR})
-  tvm_ffi_add_apple_dsymutil(my_ffi_extension)
-  install(
-    DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/
-    DESTINATION .
-    FILES_MATCHING
-    PATTERN "*.dSYM"
-  )
-endif ()
-
+tvm_ffi_configure_target(my_ffi_extension STUB_DIR "./python" STUB_INIT ON)
 install(TARGETS my_ffi_extension DESTINATION .)
+tvm_ffi_install(my_ffi_extension)
diff --git a/examples/packaging/python/my_ffi_extension/_ffi_api.py 
b/examples/packaging/python/my_ffi_extension/_ffi_api.py
index 887b991..be25187 100644
--- a/examples/packaging/python/my_ffi_extension/_ffi_api.py
+++ b/examples/packaging/python/my_ffi_extension/_ffi_api.py
@@ -28,7 +28,7 @@ if TYPE_CHECKING:
 # fmt: on
 # tvm-ffi-stubgen(end)
 # tvm-ffi-stubgen(import-object): 
tvm_ffi.libinfo.load_lib_module;False;_FFI_LOAD_LIB
-LIB = _FFI_LOAD_LIB("my-ffi-extension", "my_ffi_extension")
+LIB = _FFI_LOAD_LIB("my_ffi_extension", "my_ffi_extension")
 # tvm-ffi-stubgen(begin): global/my_ffi_extension
 # fmt: off
 _FFI_INIT_FUNC("my_ffi_extension", __name__)

Reply via email to