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-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new 90162dd  doc: Export Functions and Classes (#436)
90162dd is described below

commit 90162ddc42c81bbe2913ada3fe1734d4805f741e
Author: Junru Shao <[email protected]>
AuthorDate: Sun Feb 8 04:14:19 2026 -0800

    doc: Export Functions and Classes (#436)
---
 docs/concepts/func_module.rst       |  36 +++++
 docs/get_started/quickstart.rst     |  47 +++++-
 docs/get_started/stable_c_abi.rst   |  33 +++-
 docs/guides/compiler_integration.md |  40 +----
 docs/guides/export_func_cls.rst     | 308 ++++++++++++++++++++++++++++++++++++
 docs/index.rst                      |   1 +
 docs/packaging/python_packaging.rst | 185 +---------------------
 7 files changed, 429 insertions(+), 221 deletions(-)

diff --git a/docs/concepts/func_module.rst b/docs/concepts/func_module.rst
index 300110a..10fa7ec 100644
--- a/docs/concepts/func_module.rst
+++ b/docs/concepts/func_module.rst
@@ -395,6 +395,42 @@ a symbol during static initialization:
    program lifetime. For dynamic loading with the ability to unload, use 
shared library modules instead.
 
 
+.. _sec:custom-modules:
+
+Custom Modules
+~~~~~~~~~~~~~~
+
+While the standard shared library and system library modules cover most use
+cases, some scenarios require a **custom module** that wraps a 
platform-specific
+driver API — for example, using ``cuModuleLoad`` to load generated PTX code and
+expose each kernel as a :cpp:class:`tvm::ffi::Function`.
+
+To create a custom module, subclass :cpp:class:`tvm::ffi::ModuleObj` and
+implement the following:
+
+- :cpp:func:`~tvm::ffi::ModuleObj::kind` — return a unique string identifying
+  the module type (e.g., ``"cuda"``).
+- :cpp:func:`~tvm::ffi::ModuleObj::GetPropertyMask` — return a bitmask
+  indicating the module's capabilities:
+
+  - ``ffi::Module::kRunnable`` if the module can execute functions.
+  - ``ffi::Module::kBinarySerializable`` if the module supports
+    serialization to and from bytes.
+
+- :cpp:func:`~tvm::ffi::ModuleObj::GetFunction` — look up a function by name
+  within the module.
+- If the module is serializable, override
+  :cpp:func:`~tvm::ffi::ModuleObj::SaveToBytes` and register a global function
+  ``ffi.Module.load_from_bytes.<kind>`` so the module can be reconstructed from
+  its serialized form.
+
+.. seealso::
+
+   :ref:`Embedded Binary Data <export-embedded-binary-data>` in the export 
guide describes
+   the ``__tvm_ffi__library_bin`` binary layout used to serialize composite
+   modules that contain custom sub-modules.
+
+
 Further Reading
 ---------------
 
diff --git a/docs/get_started/quickstart.rst b/docs/get_started/quickstart.rst
index f4ded6a..cd9adce 100644
--- a/docs/get_started/quickstart.rst
+++ b/docs/get_started/quickstart.rst
@@ -95,6 +95,16 @@ The class :cpp:class:`tvm::ffi::TensorView` enables 
zero-copy interop with tenso
 
 Finally, :cpp:func:`TVMFFIEnvGetStream` can be used in the CUDA code to launch 
kernels on the caller's stream.
 
+.. seealso::
+
+   - :doc:`../guides/export_func_cls`: All three export mechanisms
+     (C symbols, global functions, classes) with complete examples.
+   - :doc:`../guides/kernel_library_guide`: Production-grade CUDA kernel
+     patterns including input validation, device guard, stream handling, and
+     dtype dispatch.
+   - :doc:`../concepts/tensor`: Tensor concepts,
+     :cpp:class:`~tvm::ffi::TensorView` API, and DLPack interop details.
+
 .. _sec-cpp-compile-with-tvm-ffi:
 
 Compile with TVM-FFI
@@ -164,6 +174,12 @@ TVM-FFI integrates with CMake via ``find_package`` as 
demonstrated below:
 - Languages, including C++, Python, Rust, or any other language that can 
interop with the C ABI;
 - ML frameworks, such as PyTorch, JAX, PaddlePaddle, NumPy, CuPy, or any array 
library that implements the standard :external+data-api:doc:`DLPack protocol 
<design_topics/data_interchange>`.
 
+.. seealso::
+
+   :doc:`../packaging/cpp_tooling` for the full build toolchain guide covering
+   CMake integration, raw compiler commands, and cross-platform library
+   distribution.
+
 .. _sec-use-across-framework:
 
 Ship Across ML Frameworks
@@ -181,6 +197,12 @@ TVM-FFI's Python package provides 
:py:func:`tvm_ffi.load_module` to load either
 ``mod.add_one_cpu`` retrieves a callable :py:class:`tvm_ffi.Function` that 
accepts tensors from host frameworks
 directly. This is zero-copy, requires no boilerplate code, and adds very 
little overhead.
 
+.. seealso::
+
+   :ref:`sec:module` in :doc:`../concepts/func_module` for details on the 
module
+   system, function retrieval, and the calling convention that enables
+   cross-language interop.
+
 We can then use these functions in the following ways:
 
 .. _ship-to-pytorch:
@@ -308,7 +330,8 @@ Compile and run it with:
   :cpp:class:`tvm::ffi::Function` from the exported symbol, or directly use
   :cpp:func:`tvm::ffi::Function::InvokeExternC` to invoke the function.
 
-  This feature can be useful on iOS, or when the exported module is generated 
by another DSL compiler targeting the ABI.
+  This feature can be useful on iOS, or when the exported module is generated
+  by another DSL compiler targeting the ABI.
 
   .. code-block:: cpp
 
@@ -363,7 +386,21 @@ Troubleshooting
 Further Reading
 ---------------
 
-- :doc:`Python Packaging <../packaging/python_packaging>` provides details on 
ABI-agnostic Python wheel builds and on
-  exposing functions, classes, and C symbols from TVM-FFI modules.
-- :doc:`Stable C ABI <stable_c_abi>` explains the ABI in depth and the 
stability guarantees it enables. Its C examples demonstrate
-  how to interoperate through the stable C ABI from both the callee and caller 
sides.
+- :doc:`stable_c_abi`: The stable C ABI layout, calling convention, and 
end-to-end
+  C examples from both the callee and caller sides.
+- :doc:`../guides/export_func_cls`: Export C symbols, global functions, and 
classes
+  across C, C++, and Python.
+- :doc:`../guides/kernel_library_guide`: Production-grade CUDA kernel patterns
+  (validation, device guard, stream, dtype dispatch).
+- :doc:`../concepts/func_module`: Calling convention, module system, and global
+  registry concepts.
+- :doc:`../concepts/tensor`: Tensor representation, DLPack interop, and stream
+  handling.
+- :doc:`../concepts/abi_overview`: Low-level ABI specification for all TVM-FFI 
types.
+- :doc:`../concepts/exception_handling`: Throwing, catching, and propagating
+  exceptions across language boundaries.
+- :doc:`../packaging/python_packaging`: Packaging extensions as ABI-agnostic 
Python
+  wheels.
+- :doc:`../packaging/cpp_tooling`: Build toolchain, CMake integration, and 
library
+  distribution.
+- :doc:`../packaging/stubgen`: Generating Python type stubs from C++ metadata.
diff --git a/docs/get_started/stable_c_abi.rst 
b/docs/get_started/stable_c_abi.rst
index 0f6dbd5..413b478 100644
--- a/docs/get_started/stable_c_abi.rst
+++ b/docs/get_started/stable_c_abi.rst
@@ -127,6 +127,19 @@ Stability and Interoperability
 
 **Cross-framework.** TVM-FFI uses standard data structures such as 
:external+data-api:doc:`DLPack tensors <design_topics/data_interchange>` to 
represent arrays, so compiled functions can be used from any array framework 
that implements the DLPack protocol (NumPy, PyTorch, TensorFlow, CuPy, JAX, 
PaddlePaddle, and others).
 
+.. seealso::
+
+   - :doc:`../concepts/any`: Full guide on ``Any`` type semantics, ownership, 
and
+     conversions.
+   - :doc:`../concepts/func_module`: Function and module concepts, including 
the
+     :ref:`calling convention <sec:function-calling-convention>` and
+     :ref:`module system <sec:module>`.
+   - :doc:`../concepts/tensor`: Tensor representation and DLPack interop.
+   - :doc:`../concepts/object_and_class`: Object system, type hierarchy, and
+     reference counting.
+   - :doc:`../concepts/abi_overview`: Complete low-level ABI specification for 
all
+     TVM-FFI types.
+
 
 Stable ABI in C Code
 --------------------
@@ -184,6 +197,14 @@ Build it with either approach:
 - Type checking: check input types via :cpp:member:`TVMFFIAny::type_index`, 
then marshal inputs from :cpp:class:`TVMFFIAny` to the desired types;
 - Error handling: return 0 on success, or a non-zero code on failure. When an 
error occurs, set an error message via :cpp:func:`TVMFFIErrorSetRaisedFromCStr` 
or :cpp:func:`TVMFFIErrorSetRaisedFromCStrParts`.
 
+.. seealso::
+
+   - :ref:`sec-exception-handling` for full details on exception propagation 
across language boundaries.
+   - :doc:`../guides/export_func_cls`: Export C symbols, global functions, and
+     classes from C++ with higher-level macros and reflection helpers.
+   - :doc:`../guides/compiler_integration`: Integrating DSL compilers, graph
+     compilers, and runtime state management with TVM-FFI.
+
 **C vs. C++.** Compared to the :ref:`C++ example <cpp_add_one_kernel>`, there 
are a few key differences:
 
 - The explicit marshalling in **Step 1** is only needed in C. In C++, 
templates hide these details.
@@ -250,4 +271,14 @@ What's Next
 
 **Convenient compiler target.** The stable C ABI is a simple, portable codegen 
target for DSL compilers. Emit C that follows this ABI to integrate with 
TVM-FFI and call the result from multiple languages and frameworks. See 
:doc:`../concepts/abi_overview`.
 
-**Rich and extensible type system.** TVM-FFI supports a rich set of types in 
the stable C ABI: primitive types (integers, floats), DLPack tensors, strings, 
built-in reference-counted objects (functions, arrays, maps), and user-defined 
reference-counted objects. See :doc:`../guides/cpp_lang_guide`.
+**Rich and extensible type system.** TVM-FFI supports a rich set of types in 
the stable C ABI: primitive types (integers, floats), DLPack tensors, strings, 
built-in reference-counted objects (functions, arrays, maps), and user-defined 
reference-counted objects. See :doc:`../concepts/object_and_class`.
+
+**Export higher-level APIs.** Beyond C symbols, TVM-FFI provides global 
function registration and class reflection for structured cross-language APIs. 
See :doc:`../guides/export_func_cls`.
+
+**Ship kernels.** For production-grade CUDA kernel patterns including 
validation, device guard, stream handling, and dtype dispatch, see 
:doc:`../guides/kernel_library_guide`.
+
+**Package and distribute.** Package extensions as Python wheels with type 
stubs:
+
+- :doc:`../packaging/python_packaging`: ABI-agnostic Python wheel builds.
+- :doc:`../packaging/cpp_tooling`: Build toolchain, CMake integration, and 
library distribution.
+- :doc:`../packaging/stubgen`: Generating Python type stubs from C++ metadata.
diff --git a/docs/guides/compiler_integration.md 
b/docs/guides/compiler_integration.md
index a9b816a..2054709 100644
--- a/docs/guides/compiler_integration.md
+++ b/docs/guides/compiler_integration.md
@@ -169,38 +169,8 @@ common states like **streams** and **memory allocators** 
through environment fun
 allowing kernels to access these without managing their own. However, for any 
unique state required by your compiler,
 the global function registration approach is the most suitable method.
 
-## Advanced: Custom Modules
-
-While the standard dynamic library module is sufficient for many use cases,
-sometimes it may be helpful to package a custom runtime module that wraps over 
a driver API.
-For example, using `cuModuleLoad` explicitly to load generated PTX code and 
expose it as an {cpp:class}`tvm::ffi::Function`.
-The {cpp:class}`tvm::ffi::ModuleObj` interface provides a way to support this 
need.
-Generally, the steps include subclassing the {cpp:class}`tvm::ffi::ModuleObj`:
-
-- Provide a specific {cpp:func}`tvm::ffi::ModuleObj::kind` string to identify 
the module type
-- Override {cpp:func}`tvm::ffi::ModuleObj::GetPropertyMask` to indicate:
-  - The module is `ffi::Module::kRunnable` (executable)
-  - If binary serialization is supported, also add 
`ffi::Module::kBinarySerializable`
-- Override {cpp:func}`tvm::ffi::ModuleObj::GetFunction` to specify how 
functions loaded
-- Register binary serialization/deserialization 
{cpp:func}`tvm::ffi::ModuleObj::SaveToBytes` and register a global
-  function `ffi.Module.load_from_bytes.<kind>`
-
-### Enable Export and Loading
-
-We also support export and loading of modules that import custom modules.
-We allow libraries to embed a binary symbol `__tvm_ffi__library_bin` in the 
following binary layout:
-
-- `<nbytes : u64> <import_tree> <key0: str> [val0: bytes] <key1: str> [val1: 
bytes] ...`
-- `nbytes` indicates the total number of bytes following the nbytes header
-- `<import_tree>` uses CSR sparse array format: `<indptr: vec<u64>> 
<child_indices: vec<u64>>`
-  to store child indices of each node (each node is a Module instance)
-- `<key>` stores the module kind, or can be `_lib`:
-  - `_lib` indicates the module corresponds to the dynamic library itself
-  - For other cases, `val: bytes` contains the serialized bytes from the 
custom module
-- Both `bytes` and `str` are serialized as `<size: u64> <content>`
-
-This information allows us to deserialize the custom modules by calling 
`ffi.Module.load_from_bytes.<kind>` and then reconstruct
-the overall import relations from `<import_tree>` and return the final 
composed modules back to the user.
-As long as the compiler generates the `__tvm_ffi__library_bin` in the above 
format, {py:func}`tvm_ffi.load_module` will correctly
-handle the loading and recover the original module. Note that we will need the 
custom module class definition to be available
-during loading, either by importing another runtime DLL, or embedding it in 
the generated library.
+```{seealso}
+For creating custom runtime modules that wrap platform-specific driver APIs
+(e.g., ``cuModuleLoad`` for PTX), see {ref}`sec:custom-modules` in
+{doc}`../concepts/func_module`.
+```
diff --git a/docs/guides/export_func_cls.rst b/docs/guides/export_func_cls.rst
new file mode 100644
index 0000000..5123049
--- /dev/null
+++ b/docs/guides/export_func_cls.rst
@@ -0,0 +1,308 @@
+.. 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.
+
+Export Functions and Classes
+============================
+
+TVM-FFI provides three mechanisms to make functions and classes available 
across
+C, C++, and Python. Each targets a different use case:
+
+.. list-table::
+   :header-rows: 1
+   :widths: 18 42 40
+
+   * - Mechanism
+     - When to use
+     - How it works
+   * - :ref:`C Symbols <export-c-symbols>`
+     - Kernel libraries, compiler codegen
+     - Export ``__tvm_ffi_<name>`` in a shared library; load via
+       :py:func:`tvm_ffi.load_module`
+   * - :ref:`Global Functions <export-global-functions>`
+     - Application-level APIs, cross-language callbacks
+     - Register by string name; retrieve from any language
+   * - :ref:`Classes <export-classes>`
+     - Structured data with fields and methods
+     - Define a C++ :cpp:class:`~tvm::ffi::Object` subclass; use from Python
+       as a dataclass
+
+Include the umbrella header to access all C++ APIs used in this guide:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/tvm_ffi.h>
+
+Metadata (type signatures, field names, docstrings) is captured automatically
+and can be turned into Python type hints via stub generation.
+
+.. seealso::
+
+   - All C++ examples in this guide are under
+     `examples/python_packaging/ 
<https://github.com/apache/tvm-ffi/tree/main/examples/python_packaging>`_;
+     ANSI C examples are under
+     `examples/stable_c_abi/ 
<https://github.com/apache/tvm-ffi/tree/main/examples/stable_c_abi>`_.
+   - :doc:`../concepts/func_module`: Calling convention, module system, and
+     global registry concepts.
+   - :doc:`../get_started/stable_c_abi`: Low-level C ABI walkthrough.
+   - :doc:`../packaging/python_packaging`: Packaging extensions as Python 
wheels.
+   - :doc:`../packaging/stubgen`: Generating Python type stubs from C++ 
metadata.
+
+
+.. _export-c-symbols:
+
+C Symbols
+---------
+
+C symbols are the most direct export mechanism. A function is compiled into a
+shared library with a ``__tvm_ffi_<name>`` symbol, then loaded dynamically at
+runtime. This is the recommended approach for kernel libraries and compiler
+codegen because it keeps the language boundary thin.
+
+.. tip::
+
+   For exporting and calling C symbols from pure ANSI C code, see
+   :doc:`../get_started/stable_c_abi`.
+
+
+Export and Look up in C++
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Export.** Use :c:macro:`TVM_FFI_DLL_EXPORT_TYPED_FUNC` to export a C++ 
function
+as a C symbol that follows the
+:ref:`TVM-FFI calling convention <sec:function-calling-convention>`:
+
+.. literalinclude:: ../../examples/python_packaging/src/extension.cc
+   :language: cpp
+   :start-after: [tvm_ffi_abi.begin]
+   :end-before: [tvm_ffi_abi.end]
+
+This creates a symbol ``__tvm_ffi_add_two`` in the shared library. The macro
+handles argument unmarshalling and error propagation automatically.
+
+**Look up.** Use :cpp:func:`tvm::ffi::Module::LoadFromFile` to load a shared
+library and retrieve functions by name:
+
+.. code-block:: cpp
+
+   namespace ffi = tvm::ffi;
+
+   ffi::Module mod = ffi::Module::LoadFromFile("path/to/library.so");
+   ffi::Function func = mod->GetFunction("add_two").value();
+   int result = func(40).cast<int>();  // -> 42
+
+
+Load from Python
+~~~~~~~~~~~~~~~~
+
+Use :py:func:`tvm_ffi.load_module` to load the shared library and call its
+functions by name:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   mod = tvm_ffi.load_module("path/to/library.so")
+   result = mod.add_two(40)  # -> 42
+
+.. seealso::
+
+   For DSO loading at Python package level, see :ref:`sec-load-the-library` in
+   the Python packaging guide.
+
+.. _export-embedded-binary-data:
+
+Embedded Binary Data
+~~~~~~~~~~~~~~~~~~~~
+
+Shared libraries can embed a binary symbol ``__tvm_ffi__library_bin`` alongside
+function symbols to support **composite modules** — modules that import custom
+sub-modules (e.g., a PTX module loaded via ``cuModuleLoad``). The binary layout
+is:
+
+.. code-block:: text
+
+   <nbytes: u64> <import_tree> <key0: str> [val0: bytes] <key1: str> [val1: 
bytes] ...
+
+- ``nbytes``: total byte count following this header.
+- ``import_tree``: a CSR sparse array
+  (``<indptr: vec<u64>> <child_indices: vec<u64>>``) encoding the parent–child
+  relationships among module nodes.
+- Each ``key`` is a module kind string, or the special value ``_lib`` for the
+  host dynamic library itself. For non-\ ``_lib`` entries, ``val`` contains the
+  serialized bytes of the custom sub-module.
+- Both ``str`` and ``bytes`` values are length-prefixed: ``<size: u64> 
<content>``.
+
+When :py:func:`tvm_ffi.load_module` opens a library containing this symbol, it
+deserializes each sub-module by calling ``ffi.Module.load_from_bytes.<kind>``,
+reconstructs the import tree, and returns the composed module. The custom 
module
+class must be available at load time — either by importing its runtime library
+beforehand or by embedding the class definition in the generated library.
+See :ref:`Custom Modules <sec:custom-modules>` in 
:doc:`../concepts/func_module`
+for details on custom module subclassing.
+
+
+.. _export-global-functions:
+
+Global Functions
+----------------
+
+Global functions are registered by string name in a shared registry, making 
them
+accessible from any language without loading a specific module. This is useful
+for application-level APIs and cross-language callbacks.
+
+
+Register and Retrieve in C++
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Register.** Use :cpp:class:`tvm::ffi::reflection::GlobalDef` inside a
+:c:macro:`TVM_FFI_STATIC_INIT_BLOCK` to register a function during library
+initialization:
+
+.. literalinclude:: ../../examples/python_packaging/src/extension.cc
+   :language: cpp
+   :start-after: [global_function.begin]
+   :end-before: [global_function.end]
+
+The function becomes available by its string name
+(``my_ffi_extension.add_one``) from any language once the library is loaded.
+
+**Retrieve.** Use :cpp:func:`tvm::ffi::Function::GetGlobal` (returns
+``Optional``) or :cpp:func:`tvm::ffi::Function::GetGlobalRequired` (throws if
+missing):
+
+.. code-block:: cpp
+
+   namespace ffi = tvm::ffi;
+
+   // Optional retrieval
+   ffi::Optional<ffi::Function> maybe_func =
+       ffi::Function::GetGlobal("my_ffi_extension.add_one");
+   if (maybe_func.has_value()) {
+     int result = maybe_func.value()(3).cast<int>();
+   }
+
+   // Required retrieval (throws if not found)
+   ffi::Function func =
+       ffi::Function::GetGlobalRequired("my_ffi_extension.add_one");
+   int result = func(3).cast<int>();  // -> 4
+
+
+Register and Retrieve in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Register.** Use the :py:func:`tvm_ffi.register_global_func` decorator:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ffi_extension.add_one")
+   def add_one(x: int) -> int:
+       return x + 1
+
+**Retrieve.** Use :py:func:`tvm_ffi.get_global_func` to look up a function by
+name:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   add_one = tvm_ffi.get_global_func("my_ffi_extension.add_one")
+   result = add_one(3)  # -> 4
+
+.. seealso::
+
+   For packaged extensions, :ref:`stub generation <sec-stubgen>` produces
+   type-annotated bindings so that users can call global functions directly
+   (e.g. ``my_ffi_extension.add_one(3)``) with full IDE support.
+
+.. note::
+
+   Global functions can also be retrieved via 
:cpp:func:`TVMFFIFunctionGetGlobal`
+   in C.
+
+
+.. _export-classes:
+
+Classes
+-------
+
+Any class derived from :cpp:class:`tvm::ffi::Object` can be registered, 
exported,
+and instantiated from Python. The reflection helper
+:cpp:class:`tvm::ffi::reflection::ObjectDef` makes it easy to expose:
+
+- **Fields**: immutable via
+  :cpp:func:`ObjectDef::def_ro <tvm::ffi::reflection::ObjectDef::def_ro>`,
+  mutable via
+  :cpp:func:`ObjectDef::def_rw <tvm::ffi::reflection::ObjectDef::def_rw>`
+- **Methods**: instance via
+  :cpp:func:`ObjectDef::def <tvm::ffi::reflection::ObjectDef::def>`,
+  static via
+  :cpp:func:`ObjectDef::def_static 
<tvm::ffi::reflection::ObjectDef::def_static>`
+- **Constructors** via :cpp:class:`tvm::ffi::reflection::init`
+
+
+Register in C++
+~~~~~~~~~~~~~~~
+
+Define a class that inherits from :cpp:class:`tvm::ffi::Object`, then register
+it with :cpp:class:`tvm::ffi::reflection::ObjectDef` inside a
+:c:macro:`TVM_FFI_STATIC_INIT_BLOCK`:
+
+.. literalinclude:: ../../examples/python_packaging/src/extension.cc
+   :language: cpp
+   :start-after: [object.begin]
+   :end-before: [object.end]
+
+Key elements:
+
+- :c:macro:`TVM_FFI_DECLARE_OBJECT_INFO_FINAL` declares the type with a unique
+  string key (``my_ffi_extension.IntPair``), the class name, and parent class.
+- ``static constexpr bool _type_mutable = true`` allows field modification from
+  Python. Omit this (or set to ``false``) for immutable objects.
+
+
+Use in Python
+~~~~~~~~~~~~~
+
+After importing the extension, the class is available with property access and
+method calls:
+
+.. code-block:: python
+
+   import my_ffi_extension
+
+   pair = my_ffi_extension.IntPair(1, 2)
+   print(pair.a)      # -> 1
+   print(pair.b)      # -> 2
+   print(pair.sum())  # -> 3
+
+.. seealso::
+
+   For packaged extensions, :ref:`stub generation <sec-stubgen>` produces
+   type-annotated Python classes with full IDE support.
+
+
+Further Reading
+---------------
+
+- :doc:`../get_started/stable_c_abi`: End-to-end C ABI walkthrough with callee 
and caller examples
+- :doc:`../concepts/func_module`: Calling convention, module system, and 
global registry concepts
+- :doc:`../concepts/object_and_class`: Object system, type hierarchy, and 
reference counting
+- :doc:`../packaging/python_packaging`: Packaging extensions as Python wheels 
with stub generation
+- :doc:`../packaging/cpp_tooling`: Build toolchain, CMake integration, and 
library distribution
+- :doc:`cpp_lang_guide`: Full C++ API guide covering Any, Function, 
containers, and more
diff --git a/docs/index.rst b/docs/index.rst
index 62768c7..4955811 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -47,6 +47,7 @@ Table of Contents
    :maxdepth: 1
    :caption: Guides
 
+   guides/export_func_cls.rst
    guides/kernel_library_guide.rst
    guides/compiler_integration.md
    guides/cubin_launcher.rst
diff --git a/docs/packaging/python_packaging.rst 
b/docs/packaging/python_packaging.rst
index 3fd1335..c3c828f 100644
--- a/docs/packaging/python_packaging.rst
+++ b/docs/packaging/python_packaging.rst
@@ -129,6 +129,8 @@ we can safely exclude this dependency from the final wheel.
    # Windows
    delvewheel repair --exclude tvm_ffi.dll -w dist dist\\*.whl
 
+.. _sec-load-the-library:
+
 Load the Library
 ~~~~~~~~~~~~~~~~
 
@@ -158,186 +160,9 @@ The parameters are:
   * macOS: ``lib{target_name}.dylib``
   * Windows: ``{target_name}.dll``
 
-Export C++ to Python
---------------------
-
-Include the umbrella header to access the core TVM-FFI C++ API.
-
-.. code-block:: cpp
-
-   #include <tvm/ffi/tvm_ffi.h>
-
-TVM-FFI offers three ways to expose code:
-
-- C symbols in the TVM-FFI ABI: export code as plain C symbols. This is the 
recommended way for
-  most use cases because it keeps the boundary thin and works well with 
compiler codegen;
-- Functions: expose functions via the global registry;
-- Classes: register C++ classes derived from :cpp:class:`tvm::ffi::Object` as 
Python dataclasses.
-
-Metadata is captured automatically and later turned into Python type hints for 
LSP support.
-The examples below show C++ code and its Python usage. The "Python 
(Generated)" tab
-shows code produced by the stub generation tool (see :ref:`sec-stubgen`).
-
-TVM-FFI ABI (Recommended)
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you prefer to export plain C symbols, TVM-FFI provides helpers to make them 
accessible
-from Python. This option keeps the boundary thin and works well with 
LLVM-based compilers where
-C symbols are easier to call.
-
-.. tabs::
-
-  .. group-tab:: C++
-
-    Macro :c:macro:`TVM_FFI_DLL_EXPORT_TYPED_FUNC` exports the function 
``AddTwo`` as
-    a C symbol ``__tvm_ffi_add_two`` inside the shared library.
-
-    .. literalinclude:: ../../examples/python_packaging/src/extension.cc
-      :language: cpp
-      :start-after: [tvm_ffi_abi.begin]
-      :end-before: [tvm_ffi_abi.end]
-
-  .. group-tab:: Python (User)
-
-    Symbol ``__tvm_ffi_add_two`` is made available via ``LIB.add_two`` to 
users.
-
-    .. code-block:: python
-
-      import my_ffi_extension
-      my_ffi_extension.LIB.add_two(1)  # -> 3
-
-  .. group-tab:: Python (Generated)
-
-    The shared library is loaded by :py:func:`tvm_ffi.libinfo.load_lib_module`.
-
-    .. code-block:: python
-
-      # File: my_ffi_extension/_ffi_api.py
-
-      LIB = tvm_ffi.libinfo.load_lib_module(
-        package="my-ffi-extension",
-        target_name="my_ffi_extension",
-      )
-
-
-Global Function
-~~~~~~~~~~~~~~~
-
-This example registers a function in the global registry and then calls it 
from Python.
-The registry handles type translation, error handling, and metadata.
-
-.. tabs::
-
-  .. group-tab:: C++
-
-    C++ function ``AddOne`` is registered with name 
``my_ffi_extension.add_one``
-    in the global registry using :cpp:class:`tvm::ffi::reflection::GlobalDef`.
-
-    .. literalinclude:: ../../examples/python_packaging/src/extension.cc
-      :language: cpp
-      :start-after: [global_function.begin]
-      :end-before: [global_function.end]
-
-  .. group-tab:: Python (User)
-
-    The global function is accessible after importing the extension,
-    and the import path matches the registered name, i.e. 
``my_ffi_extension.add_one``.
-
-    .. code-block:: python
-
-      import my_ffi_extension
-
-      my_ffi_extension.add_one(3)  # -> 4
-
-  .. group-tab:: Python (Generated)
-
-    Under the hood, the shared library is loaded by 
:py:func:`tvm_ffi.init_ffi_api`
-    during package initialization.
-
-    .. code-block:: python
-
-      # File: my_ffi_extension/_ffi_api.py
-
-      tvm_ffi.init_ffi_api(
-        namespace="my_ffi_extension",
-        target_module_name=__name__,
-      )
-
-      def add_one(x: int) -> int: ...
-
-
-.. note::
-
-  Global functions can be retrieved via :py:func:`tvm_ffi.get_global_func` in 
Python, :cpp:func:`TVMFFIFunctionGetGlobal` in C,
-  or :cpp:func:`tvm::ffi::Function::GetGlobal` in C++.
-
-  .. code-block:: python
-
-    func = tvm_ffi.get_global_func("my_ffi_extension.add_one")
-    func(3)  # -> 4
-
-
-Class
-~~~~~
-
-Any class derived from :cpp:class:`tvm::ffi::Object` can be registered, 
exported, and
-instantiated from Python. The reflection helper 
:cpp:class:`tvm::ffi::reflection::ObjectDef`
-makes it easy to expose:
-
-- Fields
-
-  * Immutable field via :cpp:func:`ObjectDef::def_ro 
<tvm::ffi::reflection::ObjectDef::def_ro>`;
-  * Mutable field via :cpp:func:`ObjectDef::def_rw 
<tvm::ffi::reflection::ObjectDef::def_rw>`;
-
-- Methods
-
-  * Member method via :cpp:func:`ObjectDef::def 
<tvm::ffi::reflection::ObjectDef::def>`.
-  * Static method via :cpp:func:`ObjectDef::def_static 
<tvm::ffi::reflection::ObjectDef::def_static>`;
-  * Constructors via :cpp:class:`tvm::ffi::reflection::init`.
-
-
-.. tabs::
-
-  .. group-tab:: C++
-
-    The example below defines a class ``my_ffi_extension.IntPair`` with
-
-    - two integer fields ``a``, ``b``,
-    - a constructor, and
-    - a method ``Sum`` that returns the sum of the two fields.
-
-    .. literalinclude:: ../../examples/python_packaging/src/extension.cc
-      :language: cpp
-      :start-after: [object.begin]
-      :end-before: [object.end]
-
-  .. group-tab:: Python (User)
-
-    The class is available immediately after importing the extension,
-    with the import path matching the registered name, i.e. 
``my_ffi_extension.IntPair``.
-
-    .. code-block:: python
-
-      import my_ffi_extension
-
-      pair = my_ffi_extension.IntPair(1, 2)
-      pair.sum()  # -> 3
-
-  .. group-tab:: Python (Generated)
-
-    Type hints are generated for both fields and methods.
-
-    .. code-block:: python
-
-      # File: my_ffi_extension/_ffi_api.py (auto generated)
-
-      @tvm_ffi.register_object("my_ffi_extension.IntPair")
-      class IntPair(tvm_ffi.Object):
-          a: int
-          b: int
-
-          def __init__(self, a: int, b: int) -> None: ...
-          def sum(self) -> int: ...
+Once the library is loaded, functions and classes can be exported from C++ and
+called from Python. See :doc:`../guides/export_func_cls` for the three export
+mechanisms (C symbols, global functions, and classes) with complete examples.
 
 
 Stub Generation

Reply via email to