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

yongwww 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 4ec17095d5 [FFI][DOCS] Wheel Packaging (#18256)
4ec17095d5 is described below

commit 4ec17095d5498546ac7efeaa805b8860b613e10c
Author: Tianqi Chen <[email protected]>
AuthorDate: Sat Aug 30 23:12:45 2025 -0400

    [FFI][DOCS] Wheel Packaging (#18256)
    
    [FFI] Wheel packaging example
    
    This PR add an example about wheel packaging.
    Also fixes various source packaging minor nits.
---
 ffi/CMakeLists.txt                                 |  4 +-
 ffi/cmake/tvm_ffi-config.cmake                     |  2 +
 ffi/examples/get_started/README.md                 |  7 +--
 ffi/examples/packaging/CMakeLists.txt              | 73 ++++++++++++++++++++++
 ffi/examples/packaging/README.md                   | 61 ++++++++++++++++++
 ffi/examples/packaging/pyproject.toml              | 58 +++++++++++++++++
 .../packaging/python/tvm_ffi_extension/__init__.py | 48 ++++++++++++++
 .../packaging/python/tvm_ffi_extension/_ffi_api.py | 24 +++++++
 .../packaging/python/tvm_ffi_extension/base.py     | 37 +++++++++++
 ffi/pyproject.toml                                 |  2 +-
 ffi/python/tvm_ffi/cython/function.pxi             |  7 +--
 ffi/python/tvm_ffi/libinfo.py                      |  2 +-
 12 files changed, 313 insertions(+), 12 deletions(-)

diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt
index f40313636a..90f1f89cbb 100644
--- a/ffi/CMakeLists.txt
+++ b/ffi/CMakeLists.txt
@@ -239,9 +239,9 @@ if (TVM_FFI_BUILD_PYTHON_MODULE)
     PATTERN "*.tmp" EXCLUDE
   )
   install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/ DESTINATION src/ffi/)
-  install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils/ DESTINATION 
cmake/Utils/)
+  install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils/ DESTINATION 
cmake/Utils)
   install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt DESTINATION .)
-  install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tvm_ffi-config.cmake 
DESTINATION lib/cmake/tvm_ffi/)
+  install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tvm_ffi-config.cmake 
DESTINATION cmake)
 endif()
 
 ########## Install the related for normal cmake library ##########
diff --git a/ffi/cmake/tvm_ffi-config.cmake b/ffi/cmake/tvm_ffi-config.cmake
index 003d6dd1e3..01f60ca10b 100644
--- a/ffi/cmake/tvm_ffi-config.cmake
+++ b/ffi/cmake/tvm_ffi-config.cmake
@@ -54,3 +54,5 @@ set_target_properties(
   tvm_ffi_shared PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
   "${tvm_ffi_INCLUDE_DIR};${tvm_ffi_DLPACK_INCLUDE_DIR}"
 )
+# extra cmake functions
+include(${CMAKE_CURRENT_LIST_DIR}/Utils/Library.cmake)
diff --git a/ffi/examples/get_started/README.md 
b/ffi/examples/get_started/README.md
index 746d24ae91..002d4375a6 100644
--- a/ffi/examples/get_started/README.md
+++ b/ffi/examples/get_started/README.md
@@ -23,11 +23,10 @@ that can be loaded in different environments.
 The example implements a simple "add one" operation that adds 1 to each element
 of an input tensor, showing how to create C++ functions callable from Python.
 
-
 You can run this quick start example by:
 
 ```bash
-# ensure you installed tvm-ffi first once
+# ensure you installed tvm-ffi first
 pip install -e ../..
 
 # Build and run the complete example
@@ -49,8 +48,8 @@ in Python and C++.
 
 ## Compile without CMake
 
-You can also compile the modules directly using using
-flags provided by the `tvm-ffi-config` tool
+You can also compile the modules directly using
+flags provided by the `tvm-ffi-config` tool.
 
 ```bash
 g++ -shared -fPIC `tvm-ffi-config --cxxflags`  \
diff --git a/ffi/examples/packaging/CMakeLists.txt 
b/ffi/examples/packaging/CMakeLists.txt
new file mode 100644
index 0000000000..47e5040a0d
--- /dev/null
+++ b/ffi/examples/packaging/CMakeLists.txt
@@ -0,0 +1,73 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.18)
+project(tvm_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_shared.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()
+  # call tvm_ffi.config to get the cmake directory and set it to tvm_ffi_ROOT
+  execute_process(
+    COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --cmakedir
+    OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
+  find_package(tvm_ffi CONFIG REQUIRED)
+endif()
+
+# use the projects as usual
+add_library(tvm_ffi_extension SHARED src/extension.cc)
+target_link_libraries(tvm_ffi_extension tvm_ffi_header)
+target_link_libraries(tvm_ffi_extension tvm_ffi_shared)
+
+# show as tvm_ffi_extension.so
+set_target_properties(
+  tvm_ffi_extension PROPERTIES PREFIX ""
+)
+
+if (TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS)
+  # ship debugging symbols for backtrace on macos
+  tvm_ffi_add_prefix_map(tvm_ffi_extension ${CMAKE_CURRENT_SOURCE_DIR})
+  tvm_ffi_add_apple_dsymutil(tvm_ffi_extension)
+  install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION . FILES_MATCHING 
PATTERN "*.dSYM")
+endif()
+
+install(TARGETS tvm_ffi_extension DESTINATION .)
diff --git a/ffi/examples/packaging/README.md b/ffi/examples/packaging/README.md
new file mode 100644
index 0000000000..9535581af6
--- /dev/null
+++ b/ffi/examples/packaging/README.md
@@ -0,0 +1,61 @@
+<!--- 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. -->
+
+# TVM FFI Packaging Example
+
+This is an example project that packages a tvm-ffi based library
+into a Python ABI-agnostic wheel.
+
+This example can also serve as a guideline for general
+packaging as well.
+
+- Source-level build for cross-compilation support in CMake
+- Registration via global function table
+
+## Install the wheel
+
+```bash
+pip install .
+```
+
+### Note on build and auditwheel
+
+Note: When running the auditwheel process, make sure to skip
+`libtvm_ffi_shared.so` as they are shipped via the tvm_ffi package.
+
+## Run the example
+
+After installing the `tvm_ffi_extension` example package, you can run the 
following example
+that invokes the `add_one` function exposed.
+
+```bash
+python run_example.py add_one
+```
+
+You can also run the following command to see how error is raised and 
propagated
+across the language boundaries.
+
+```python
+python run_example.py raise_error
+```
+
+When possible, tvm_ffi will try to preserve traceback across language 
boundary. You will see traceback like
+```
+File "src/extension.cc", line 45, in void 
tvm_ffi_extension::RaiseError(tvm::ffi::String)
+```
+If you are in an IDE like VSCode, you can click and jump to the C++ lines of 
error when
+the debug symbols are preserved.
diff --git a/ffi/examples/packaging/pyproject.toml 
b/ffi/examples/packaging/pyproject.toml
new file mode 100644
index 0000000000..e38ebeccff
--- /dev/null
+++ b/ffi/examples/packaging/pyproject.toml
@@ -0,0 +1,58 @@
+# 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.
+
+[project]
+name = "tvm-ffi-extension"
+version = "0.1.0"
+
+readme = "README.md"
+license = { text = "Apache 2.0" }
+classifiers = [
+  "License :: OSI Approved :: Apache Software License",
+  "Development Status :: 4 - Beta",
+  "Intended Audience :: Developers",
+  "Intended Audience :: Education",
+  "Intended Audience :: Science/Research",
+]
+keywords = ["machine learning", "inference"]
+requires-python = ">=3.9"
+
+dependencies = ["apache-tvm-ffi"]
+
+[build-system]
+requires = ["scikit-build-core>=0.10.0", "apache-tvm-ffi"]
+build-backend = "scikit_build_core.build"
+
+[tool.scikit-build]
+# the wheel is abi agnostic
+wheel.py-api = "py3"
+minimum-version = "build-system.requires"
+
+# Build configuration
+build-dir = "build"
+build.verbose = true
+
+# CMake configuration
+cmake.version = "CMakeLists.txt"
+cmake.build-type = "RelWithDebugInfo"
+
+# Logging
+logging.level = "INFO"
+
+# Wheel configuration
+wheel.packages = ["python/tvm_ffi_extension"]
+wheel.install-dir = "tvm_ffi_extension"
diff --git a/ffi/examples/packaging/python/tvm_ffi_extension/__init__.py 
b/ffi/examples/packaging/python/tvm_ffi_extension/__init__.py
new file mode 100644
index 0000000000..4cd4207df1
--- /dev/null
+++ b/ffi/examples/packaging/python/tvm_ffi_extension/__init__.py
@@ -0,0 +1,48 @@
+# 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.
+from .base import _LIB
+from . import _ffi_api
+
+
+def add_one(x, y):
+    """
+    Adds one to the input tensor.
+
+    Parameters
+    ----------
+    x : Tensor
+      The input tensor.
+    y : Tensor
+      The output tensor.
+    """
+    return _LIB.add_one(x, y)
+
+
+def raise_error(msg):
+    """
+    Raises an error with the given message.
+
+    Parameters
+    ----------
+    msg : str
+        The message to raise the error with.
+
+    Raises
+    ------
+    RuntimeError
+        The error raised by the function.
+    """
+    return _ffi_api.raise_error(msg)
diff --git a/ffi/examples/packaging/python/tvm_ffi_extension/_ffi_api.py 
b/ffi/examples/packaging/python/tvm_ffi_extension/_ffi_api.py
new file mode 100644
index 0000000000..1ab9abd765
--- /dev/null
+++ b/ffi/examples/packaging/python/tvm_ffi_extension/_ffi_api.py
@@ -0,0 +1,24 @@
+# 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.
+
+import tvm_ffi
+
+# make sure lib is loaded first
+from .base import _LIB
+
+# this is a short cut to register all the global functions
+# prefixed by `tvm_ffi_extension.` to this module
+tvm_ffi._init_api("tvm_ffi_extension", __name__)
diff --git a/ffi/examples/packaging/python/tvm_ffi_extension/base.py 
b/ffi/examples/packaging/python/tvm_ffi_extension/base.py
new file mode 100644
index 0000000000..ed73193770
--- /dev/null
+++ b/ffi/examples/packaging/python/tvm_ffi_extension/base.py
@@ -0,0 +1,37 @@
+# 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.
+# Base logic to load library for extension package
+import tvm_ffi
+import os
+import sys
+
+
+def _load_lib():
+    # first look at the directory of the current file
+    file_dir = os.path.dirname(os.path.realpath(__file__))
+
+    if sys.platform.startswith("win32"):
+        lib_dll_name = "tvm_ffi_extension.dll"
+    elif sys.platform.startswith("darwin"):
+        lib_dll_name = "tvm_ffi_extension.dylib"
+    else:
+        lib_dll_name = "tvm_ffi_extension.so"
+
+    lib_path = os.path.join(file_dir, lib_dll_name)
+    return tvm_ffi.load_module(lib_path)
+
+
+_LIB = _load_lib()
diff --git a/ffi/pyproject.toml b/ffi/pyproject.toml
index 3efa1d9455..8ed9e275e2 100644
--- a/ffi/pyproject.toml
+++ b/ffi/pyproject.toml
@@ -17,7 +17,7 @@
 
 [project]
 name = "apache-tvm-ffi"
-version = "0.1.0a3"
+version = "0.1.0a5"
 description = "tvm ffi"
 
 authors = [{ name = "TVM FFI team" }]
diff --git a/ffi/python/tvm_ffi/cython/function.pxi 
b/ffi/python/tvm_ffi/cython/function.pxi
index dcd300c9b0..00a0bb3515 100644
--- a/ffi/python/tvm_ffi/cython/function.pxi
+++ b/ffi/python/tvm_ffi/cython/function.pxi
@@ -56,10 +56,7 @@ def load_torch_get_current_cuda_stream():
         return fallback_get_current_cuda_stream
 
 
-if torch is not None:
-    # when torch is available, jit compile the get_current_cuda_stream function
-    # the torch caches the extension so second loading is faster
-    torch_get_current_cuda_stream = load_torch_get_current_cuda_stream()
+torch_get_current_cuda_stream = None
 
 
 cdef inline object make_ret_small_str(TVMFFIAny result):
@@ -149,6 +146,8 @@ cdef inline int make_args(tuple py_args, TVMFFIAny* out, 
list temp_args,
             if is_cuda and ctx_dev_type != NULL and ctx_dev_type[0] == -1:
                 ctx_dev_type[0] = temp_dltensor.device.device_type
                 ctx_dev_id[0] = temp_dltensor.device.device_id
+                if torch_get_current_cuda_stream is None:
+                    torch_get_current_cuda_stream = 
load_torch_get_current_cuda_stream()
                 temp_ptr = 
torch_get_current_cuda_stream(temp_dltensor.device.device_id)
                 ctx_stream[0] = <TVMFFIStreamHandle>temp_ptr
             temp_args.append(arg)
diff --git a/ffi/python/tvm_ffi/libinfo.py b/ffi/python/tvm_ffi/libinfo.py
index 8974574fe9..b449bc1abc 100644
--- a/ffi/python/tvm_ffi/libinfo.py
+++ b/ffi/python/tvm_ffi/libinfo.py
@@ -95,7 +95,7 @@ def find_source_path():
 def find_cmake_path():
     """Find the preferred cmake path."""
     candidates = [
-        os.path.join(os.path.dirname(os.path.realpath(__file__)), "lib", 
"cmake"),
+        os.path.join(os.path.dirname(os.path.realpath(__file__)), "cmake"),
         os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", 
"cmake"),
     ]
     for candidate in candidates:

Reply via email to