Skip to content

Commit 2fdec42

Browse files
committed
[FFI] Wheel packaging example
This PR add an example about wheel packaging. Also fixes various source packaging minor nits.
1 parent aa4c818 commit 2fdec42

File tree

12 files changed

+313
-12
lines changed

12 files changed

+313
-12
lines changed

ffi/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,9 @@ if (TVM_FFI_BUILD_PYTHON_MODULE)
239239
PATTERN "*.tmp" EXCLUDE
240240
)
241241
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/ DESTINATION src/ffi/)
242-
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils/ DESTINATION cmake/Utils/)
242+
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils/ DESTINATION cmake/Utils)
243243
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt DESTINATION .)
244-
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tvm_ffi-config.cmake DESTINATION lib/cmake/tvm_ffi/)
244+
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tvm_ffi-config.cmake DESTINATION cmake)
245245
endif()
246246

247247
########## Install the related for normal cmake library ##########

ffi/cmake/tvm_ffi-config.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ set_target_properties(
5454
tvm_ffi_shared PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
5555
"${tvm_ffi_INCLUDE_DIR};${tvm_ffi_DLPACK_INCLUDE_DIR}"
5656
)
57+
# extra cmake functions
58+
include(${CMAKE_CURRENT_LIST_DIR}/Utils/Library.cmake)

ffi/examples/get_started/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ that can be loaded in different environments.
2323
The example implements a simple "add one" operation that adds 1 to each element
2424
of an input tensor, showing how to create C++ functions callable from Python.
2525

26-
2726
You can run this quick start example by:
2827

2928
```bash
30-
# ensure you installed tvm-ffi first once
29+
# ensure you installed tvm-ffi first
3130
pip install -e ../..
3231

3332
# Build and run the complete example
@@ -49,8 +48,8 @@ in Python and C++.
4948

5049
## Compile without CMake
5150

52-
You can also compile the modules directly using using
53-
flags provided by the `tvm-ffi-config` tool
51+
You can also compile the modules directly using
52+
flags provided by the `tvm-ffi-config` tool.
5453

5554
```bash
5655
g++ -shared -fPIC `tvm-ffi-config --cxxflags` \
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
cmake_minimum_required(VERSION 3.18)
19+
project(tvm_ffi_extension)
20+
21+
option(TVM_FFI_EXT_FROM_SOURCE "Build tvm_ffi from source, useful for cross compilation." ON)
22+
option(TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS "Ship debug symbols" ON)
23+
24+
# There are two ways to include tvm_ffi
25+
#
26+
# 1. Build tvm_ffi from source, which is reasonably cheap since tvm ffi is small
27+
# 2. Use the pre-built tvm_ffi shipped from the pip
28+
#
29+
# This example shows both options, you only need to pick a specific one.
30+
#
31+
# - For common build cases, using pre-built and link tvm_ffi_shared is sufficient.
32+
# - For cases where you may want to cross-compile or bundle part of tvm_ffi_objects directly
33+
# into your project, opt for building tvm_ffi from source path.
34+
# Note that it is always safe to build from source and extra cost of building tvm_ffi is small.
35+
# So when in doubt, you can always choose to the building tvm_ffi from source route.
36+
#
37+
# In python or other cases when we dynamically load libtvm_ffi_shared. Even when you build
38+
# from source, you do not need to ship libtvm_ffi_shared.so built here as they are only
39+
# used to supply the linking information.
40+
# first find python related components
41+
find_package(Python COMPONENTS Interpreter REQUIRED)
42+
if (TVM_FFI_BUILD_FROM_SOURCE)
43+
execute_process(
44+
COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --sourcedir
45+
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
46+
message(STATUS "Building tvm_ffi from source: ${tvm_ffi_ROOT}")
47+
add_subdirectory(${tvm_ffi_ROOT} tvm_ffi)
48+
else()
49+
# call tvm_ffi.config to get the cmake directory and set it to tvm_ffi_ROOT
50+
execute_process(
51+
COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --cmakedir
52+
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
53+
find_package(tvm_ffi CONFIG REQUIRED)
54+
endif()
55+
56+
# use the projects as usual
57+
add_library(tvm_ffi_extension SHARED src/extension.cc)
58+
target_link_libraries(tvm_ffi_extension tvm_ffi_header)
59+
target_link_libraries(tvm_ffi_extension tvm_ffi_shared)
60+
61+
# show as tvm_ffi_extension.so
62+
set_target_properties(
63+
tvm_ffi_extension PROPERTIES PREFIX ""
64+
)
65+
66+
if (TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS)
67+
# ship debugging symbols for backtrace on macos
68+
tvm_ffi_add_prefix_map(tvm_ffi_extension ${CMAKE_CURRENT_SOURCE_DIR})
69+
tvm_ffi_add_apple_dsymutil(tvm_ffi_extension)
70+
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION . FILES_MATCHING PATTERN "*.dSYM")
71+
endif()
72+
73+
install(TARGETS tvm_ffi_extension DESTINATION .)

ffi/examples/packaging/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
2+
<!--- or more contributor license agreements. See the NOTICE file -->
3+
<!--- distributed with this work for additional information -->
4+
<!--- regarding copyright ownership. The ASF licenses this file -->
5+
<!--- to you under the Apache License, Version 2.0 (the -->
6+
<!--- "License"); you may not use this file except in compliance -->
7+
<!--- with the License. You may obtain a copy of the License at -->
8+
9+
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
10+
11+
<!--- Unless required by applicable law or agreed to in writing, -->
12+
<!--- software distributed under the License is distributed on an -->
13+
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
14+
<!--- KIND, either express or implied. See the License for the -->
15+
<!--- specific language governing permissions and limitations -->
16+
<!--- under the License. -->
17+
18+
# TVM FFI Packaging Example
19+
20+
This is an example project that packages a tvm-ffi based library
21+
into a Python ABI-agnostic wheel.
22+
23+
This example can also serve as a guideline for general
24+
packaging as well.
25+
26+
- Source-level build for cross-compilation support in CMake
27+
- Registration via global function table
28+
29+
## Install the wheel
30+
31+
```bash
32+
pip install .
33+
```
34+
35+
### Note on build and auditwheel
36+
37+
Note: When running the auditwheel process, make sure to skip
38+
`libtvm_ffi_shared.so` as they are shipped via the tvm_ffi package.
39+
40+
## Run the example
41+
42+
After installing the `tvm_ffi_extension` example package, you can run the following example
43+
that invokes the `add_one` function exposed.
44+
45+
```bash
46+
python run_example.py add_one
47+
```
48+
49+
You can also run the following command to see how error is raised and propagated
50+
across the language boundaries.
51+
52+
```python
53+
python run_example.py raise_error
54+
```
55+
56+
When possible, tvm_ffi will try to preserve traceback across language boundary. You will see traceback like
57+
```
58+
File "src/extension.cc", line 45, in void tvm_ffi_extension::RaiseError(tvm::ffi::String)
59+
```
60+
If you are in an IDE like VSCode, you can click and jump to the C++ lines of error when
61+
the debug symbols are preserved.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
[project]
19+
name = "tvm-ffi-extension"
20+
version = "0.1.0"
21+
22+
readme = "README.md"
23+
license = { text = "Apache 2.0" }
24+
classifiers = [
25+
"License :: OSI Approved :: Apache Software License",
26+
"Development Status :: 4 - Beta",
27+
"Intended Audience :: Developers",
28+
"Intended Audience :: Education",
29+
"Intended Audience :: Science/Research",
30+
]
31+
keywords = ["machine learning", "inference"]
32+
requires-python = ">=3.9"
33+
34+
dependencies = ["apache-tvm-ffi"]
35+
36+
[build-system]
37+
requires = ["scikit-build-core>=0.10.0", "apache-tvm-ffi"]
38+
build-backend = "scikit_build_core.build"
39+
40+
[tool.scikit-build]
41+
# the wheel is abi agnostic
42+
wheel.py-api = "py3"
43+
minimum-version = "build-system.requires"
44+
45+
# Build configuration
46+
build-dir = "build"
47+
build.verbose = true
48+
49+
# CMake configuration
50+
cmake.version = "CMakeLists.txt"
51+
cmake.build-type = "RelWithDebugInfo"
52+
53+
# Logging
54+
logging.level = "INFO"
55+
56+
# Wheel configuration
57+
wheel.packages = ["python/tvm_ffi_extension"]
58+
wheel.install-dir = "tvm_ffi_extension"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations.
16+
from .base import _LIB
17+
from . import _ffi_api
18+
19+
20+
def add_one(x, y):
21+
"""
22+
Adds one to the input tensor.
23+
24+
Parameters
25+
----------
26+
x : Tensor
27+
The input tensor.
28+
y : Tensor
29+
The output tensor.
30+
"""
31+
return _LIB.add_one(x, y)
32+
33+
34+
def raise_error(msg):
35+
"""
36+
Raises an error with the given message.
37+
38+
Parameters
39+
----------
40+
msg : str
41+
The message to raise the error with.
42+
43+
Raises
44+
------
45+
RuntimeError
46+
The error raised by the function.
47+
"""
48+
return _ffi_api.raise_error(msg)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations.
16+
17+
import tvm_ffi
18+
19+
# make sure lib is loaded first
20+
from .base import _LIB
21+
22+
# this is a short cut to register all the global functions
23+
# prefixed by `tvm_ffi_extension.` to this module
24+
tvm_ffi._init_api("tvm_ffi_extension", __name__)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations.
16+
# Base logic to load library for extension package
17+
import tvm_ffi
18+
import os
19+
import sys
20+
21+
22+
def _load_lib():
23+
# first look at the directory of the current file
24+
file_dir = os.path.dirname(os.path.realpath(__file__))
25+
26+
if sys.platform.startswith("win32"):
27+
lib_dll_name = "tvm_ffi_extension.dll"
28+
elif sys.platform.startswith("darwin"):
29+
lib_dll_name = "tvm_ffi_extension.dylib"
30+
else:
31+
lib_dll_name = "tvm_ffi_extension.so"
32+
33+
lib_path = os.path.join(file_dir, lib_dll_name)
34+
return tvm_ffi.load_module(lib_path)
35+
36+
37+
_LIB = _load_lib()

ffi/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
[project]
1919
name = "apache-tvm-ffi"
20-
version = "0.1.0a3"
20+
version = "0.1.0a5"
2121
description = "tvm ffi"
2222

2323
authors = [{ name = "TVM FFI team" }]

0 commit comments

Comments
 (0)