Skip to content

Commit e0e2e51

Browse files
committed
update cmakelists.
Signed-off-by: yuchuan <yuchuan.7streams@gmail.com>
1 parent da5a5e4 commit e0e2e51

3 files changed

Lines changed: 126 additions & 52 deletions

File tree

cmake/Utils/Library.cmake

Lines changed: 88 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ endfunction ()
172172
# target_name
173173
# [LINK_SHARED ON|OFF] [LINK_HEADER ON|OFF] [DEBUG_SYMBOL ON|OFF] [MSVC_FLAGS ON|OFF]
174174
# [STUB_INIT ON|OFF] [STUB_DIR <dir>] [STUB_PKG <pkg>] [STUB_PREFIX <prefix>]
175-
# [STUB_TARGET python|rust]
175+
# [STUB_TARGET <backend>...] # one or more of: python rust
176+
# [STUB_DIR_PYTHON <dir>] [STUB_DIR_RUST <dir>]
176177
# )
177178
# Configure a target to integrate with TVM-FFI CMake utilities:
178179
# - Link against tvm_ffi::header and/or tvm_ffi::shared
@@ -195,11 +196,20 @@ endfunction ()
195196
# STUB_INIT: Whether to allow generating new directives. Default: OFF (ON/OFF-style)
196197
# STUB_PKG: Package name passed to stub generator (requires STUB_DIR and STUB_INIT=ON; default: ${SKBUILD_PROJECT_NAME} if set, otherwise target name)
197198
# STUB_PREFIX: Module prefix passed to stub generator (requires STUB_DIR and STUB_INIT=ON; default: "<STUB_PKG>.")
198-
# STUB_TARGET: Code generator backend: "python" (default) or "rust". Passed to the stub
199-
# generator as --target. With "rust", object bindings are emitted into a Rust
200-
# module tree under STUB_DIR (global functions are not generated for Rust).
201-
# To generate both Python and Rust stubs for one target, call this function
202-
# twice with different STUB_DIR/STUB_TARGET values.
199+
# STUB_TARGET: Code generator backend(s): a list of one or more of "python" (default) and
200+
# "rust" (e.g. STUB_TARGET python rust). Each listed backend is passed to the
201+
# stub generator as --target. With "rust", object bindings are emitted into a
202+
# Rust module tree under its STUB_DIR (global functions are not generated for Rust).
203+
# STUB_TARGET with multiple backends (e.g. STUB_TARGET python rust):
204+
# Generates stubs for each listed backend. Because each backend writes a
205+
# different file tree, supply per-backend STUB_DIR_PYTHON / STUB_DIR_RUST. One
206+
# post-build stub command is emitted per backend; the shared STUB_PKG / STUB_PREFIX
207+
# apply to every backend.
208+
# STUB_DIR_PYTHON / STUB_DIR_RUST:
209+
# Per-backend output directories, for listing several backends that each write a
210+
# different file tree. A listed backend with no directory (no STUB_DIR_<BACKEND>,
211+
# and no STUB_DIR for a single backend) is skipped. Relative paths resolve against
212+
# CMAKE_CURRENT_SOURCE_DIR, same as STUB_DIR.
203213
# ~~~
204214
function (tvm_ffi_configure_target target)
205215
if (NOT target)
@@ -225,9 +235,11 @@ function (tvm_ffi_configure_target target)
225235
STUB_DIR
226236
STUB_PKG
227237
STUB_PREFIX
228-
STUB_TARGET
238+
STUB_DIR_PYTHON
239+
STUB_DIR_RUST
229240
)
230-
set(tvm_ffi_arg_multiValueArgs)
241+
# STUB_TARGET is a list: one or more of `python` / `rust`.
242+
set(tvm_ffi_arg_multiValueArgs STUB_TARGET)
231243

232244
cmake_parse_arguments(
233245
tvm_ffi_arg_ "${tvm_ffi_arg_options}" "${tvm_ffi_arg_oneValueArgs}"
@@ -243,25 +255,35 @@ function (tvm_ffi_configure_target target)
243255
if (NOT DEFINED tvm_ffi_arg__STUB_INIT)
244256
set(tvm_ffi_arg__STUB_INIT OFF)
245257
endif ()
246-
if (NOT DEFINED tvm_ffi_arg__STUB_TARGET)
258+
if (NOT DEFINED tvm_ffi_arg__STUB_TARGET OR NOT tvm_ffi_arg__STUB_TARGET)
247259
set(tvm_ffi_arg__STUB_TARGET "python")
248260
endif ()
249261

250-
# Validation
251-
if (NOT tvm_ffi_arg__STUB_TARGET MATCHES "^(python|rust)$")
252-
message(
253-
FATAL_ERROR
254-
"tvm_ffi_configure_target(${target}): STUB_TARGET must be 'python' or 'rust', got '${tvm_ffi_arg__STUB_TARGET}'."
255-
)
256-
endif ()
257-
if ((NOT DEFINED tvm_ffi_arg__STUB_DIR) OR (NOT tvm_ffi_arg__STUB_DIR))
258-
if (DEFINED tvm_ffi_arg__STUB_PKG OR DEFINED tvm_ffi_arg__STUB_PREFIX)
262+
list(LENGTH tvm_ffi_arg__STUB_TARGET tvm_ffi_stub_target_count)
263+
264+
# Validation: every requested backend must be 'python' or 'rust'.
265+
foreach (tvm_ffi_b IN LISTS tvm_ffi_arg__STUB_TARGET)
266+
if (NOT tvm_ffi_b MATCHES "^(python|rust)$")
259267
message(
260268
FATAL_ERROR
261-
"tvm_ffi_configure_target(${target}): STUB_PKG/STUB_PREFIX require STUB_DIR to be set."
269+
"tvm_ffi_configure_target(${target}): STUB_TARGET entries must be 'python' or 'rust', got '${tvm_ffi_b}'."
262270
)
263271
endif ()
272+
endforeach ()
273+
274+
# A stub directory may be given globally (STUB_DIR) or, when STUB_TARGET lists several backends
275+
# that each write a different file tree, per backend (STUB_DIR_PYTHON / STUB_DIR_RUST).
276+
set(tvm_ffi_has_stub_dir OFF)
277+
if (DEFINED tvm_ffi_arg__STUB_DIR AND tvm_ffi_arg__STUB_DIR)
278+
set(tvm_ffi_has_stub_dir ON)
264279
endif ()
280+
foreach (tvm_ffi_B IN ITEMS PYTHON RUST)
281+
if (DEFINED tvm_ffi_arg__STUB_DIR_${tvm_ffi_B} AND tvm_ffi_arg__STUB_DIR_${tvm_ffi_B})
282+
set(tvm_ffi_has_stub_dir ON)
283+
endif ()
284+
endforeach ()
285+
286+
# Validation
265287
if (NOT tvm_ffi_arg__STUB_INIT)
266288
if (DEFINED tvm_ffi_arg__STUB_PKG OR DEFINED tvm_ffi_arg__STUB_PREFIX)
267289
message(
@@ -270,15 +292,16 @@ function (tvm_ffi_configure_target target)
270292
)
271293
endif ()
272294
else ()
273-
if (NOT DEFINED tvm_ffi_arg__STUB_DIR OR NOT tvm_ffi_arg__STUB_DIR)
295+
if (NOT tvm_ffi_has_stub_dir)
274296
message(
275-
FATAL_ERROR "tvm_ffi_configure_target(${target}): STUB_INIT=ON requires STUB_DIR to be set."
297+
FATAL_ERROR
298+
"tvm_ffi_configure_target(${target}): STUB_INIT=ON requires a stub directory (STUB_DIR, or STUB_DIR_PYTHON/STUB_DIR_RUST)."
276299
)
277300
endif ()
278301
endif ()
279302

280-
# STUB_PKG and STUB_PREFIX defaults
281-
if (tvm_ffi_arg__STUB_INIT AND tvm_ffi_arg__STUB_DIR)
303+
# STUB_PKG and STUB_PREFIX defaults (shared across all listed backends)
304+
if (tvm_ffi_arg__STUB_INIT AND tvm_ffi_has_stub_dir)
282305
if (NOT DEFINED tvm_ffi_arg__STUB_PKG)
283306
if (DEFINED SKBUILD_PROJECT_NAME AND SKBUILD_PROJECT_NAME)
284307
set(tvm_ffi_arg__STUB_PKG "${SKBUILD_PROJECT_NAME}")
@@ -352,39 +375,53 @@ function (tvm_ffi_configure_target target)
352375
endif ()
353376
endif ()
354377

355-
if (DEFINED tvm_ffi_arg__STUB_DIR AND tvm_ffi_arg__STUB_DIR)
356-
get_filename_component(
357-
tvm_ffi_arg__STUB_DIR_ABS "${tvm_ffi_arg__STUB_DIR}" ABSOLUTE BASE_DIR
358-
"${CMAKE_CURRENT_SOURCE_DIR}"
359-
)
378+
if (tvm_ffi_has_stub_dir)
360379
find_package(
361380
Python3
362381
COMPONENTS Interpreter
363382
REQUIRED
364383
)
365-
set(tvm_ffi_stub_cli_args "${tvm_ffi_arg__STUB_DIR_ABS}" --dlls $<TARGET_FILE:${target}>
366-
--target "${tvm_ffi_arg__STUB_TARGET}"
367-
)
368-
if (tvm_ffi_arg__STUB_INIT)
369-
list(
370-
APPEND
371-
tvm_ffi_stub_cli_args
372-
--init-lib
373-
${target}
374-
--init-pypkg
375-
"${tvm_ffi_arg__STUB_PKG}"
376-
--init-prefix
377-
"${tvm_ffi_arg__STUB_PREFIX}"
378-
)
379-
endif ()
380-
add_custom_command(
381-
TARGET ${target}
382-
POST_BUILD
383-
COMMAND ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli ${tvm_ffi_stub_cli_args}
384-
COMMENT
385-
"[COMMAND] Running: ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli ${tvm_ffi_stub_cli_args}"
386-
VERBATIM
387-
)
384+
# One post-build stub command per backend. Each backend writes to its own STUB_DIR_<BACKEND>; a
385+
# single backend may instead use the shared STUB_DIR. A listed backend with no directory is
386+
# skipped.
387+
foreach (tvm_ffi_b IN LISTS tvm_ffi_arg__STUB_TARGET)
388+
string(TOUPPER "${tvm_ffi_b}" tvm_ffi_B)
389+
set(tvm_ffi_stub_dir "")
390+
if (DEFINED tvm_ffi_arg__STUB_DIR_${tvm_ffi_B} AND tvm_ffi_arg__STUB_DIR_${tvm_ffi_B})
391+
set(tvm_ffi_stub_dir "${tvm_ffi_arg__STUB_DIR_${tvm_ffi_B}}")
392+
elseif (tvm_ffi_stub_target_count EQUAL 1)
393+
set(tvm_ffi_stub_dir "${tvm_ffi_arg__STUB_DIR}")
394+
endif ()
395+
if (tvm_ffi_stub_dir)
396+
get_filename_component(
397+
tvm_ffi_arg__STUB_DIR_ABS "${tvm_ffi_stub_dir}" ABSOLUTE BASE_DIR
398+
"${CMAKE_CURRENT_SOURCE_DIR}"
399+
)
400+
set(tvm_ffi_stub_cli_args "${tvm_ffi_arg__STUB_DIR_ABS}" --dlls $<TARGET_FILE:${target}>
401+
--target "${tvm_ffi_b}"
402+
)
403+
if (tvm_ffi_arg__STUB_INIT)
404+
list(
405+
APPEND
406+
tvm_ffi_stub_cli_args
407+
--init-lib
408+
${target}
409+
--init-pypkg
410+
"${tvm_ffi_arg__STUB_PKG}"
411+
--init-prefix
412+
"${tvm_ffi_arg__STUB_PREFIX}"
413+
)
414+
endif ()
415+
add_custom_command(
416+
TARGET ${target}
417+
POST_BUILD
418+
COMMAND ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli ${tvm_ffi_stub_cli_args}
419+
COMMENT
420+
"[COMMAND] Running: ${Python3_EXECUTABLE} -m tvm_ffi.stub.cli ${tvm_ffi_stub_cli_args}"
421+
VERBATIM
422+
)
423+
endif ()
424+
endforeach ()
388425
endif ()
389426
endfunction ()
390427

docs/packaging/cpp_tooling.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ and optionally runs :ref:`stub generation <sec-stubgen>` as a post-build step.
9797
[STUB_DIR <dir> ]
9898
[STUB_PKG <pkg> ]
9999
[STUB_PREFIX <prefix>]
100+
[STUB_TARGET python rust] # one or more backends
101+
# When STUB_TARGET lists multiple backends, use these instead of STUB_DIR:
102+
[STUB_DIR_PYTHON <dir>] [STUB_DIR_RUST <dir>]
100103
)
101104
102105
:LINK_SHARED: (default: ON) Link against the TVM-FFI shared library
@@ -115,6 +118,12 @@ and optionally runs :ref:`stub generation <sec-stubgen>` as a post-build step.
115118
and ``STUB_INIT=ON``.
116119
:STUB_PREFIX: (default: "") Module prefix passed to the stub generator. Requires
117120
``STUB_DIR`` and ``STUB_INIT=ON``.
121+
:STUB_TARGET: (default: ``python``) Code generator backend(s): a list of one or more of
122+
``python`` and ``rust`` (e.g. ``STUB_TARGET python rust``). When more than one backend is
123+
listed, stubs are generated for each; because each backend writes a different file tree,
124+
give the output directories per backend via ``STUB_DIR_PYTHON`` / ``STUB_DIR_RUST``
125+
(instead of ``STUB_DIR``). The shared ``STUB_PKG`` / ``STUB_PREFIX`` apply to every
126+
listed backend.
118127

119128
See :ref:`sec-stubgen-cmake` for a detailed explanation of each ``STUB_*`` option
120129
and the generation modes they control.

docs/packaging/stubgen.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,18 @@ This runs stub generation automatically after each build.
4949
[STUB_INIT ON|OFF]
5050
[STUB_PKG <pkg>]
5151
[STUB_PREFIX <prefix>]
52-
[STUB_TARGET python|rust]
52+
[STUB_TARGET python rust] # one or more backends
53+
)
54+
55+
# Or, to generate Python and Rust stubs together (each backend writes a
56+
# different tree, so the output directories are given per backend):
57+
tvm_ffi_configure_target(<target>
58+
STUB_TARGET python rust
59+
STUB_DIR_PYTHON <python-dir>
60+
STUB_DIR_RUST <rust-dir>
61+
[STUB_INIT ON|OFF]
62+
[STUB_PKG <pkg>]
63+
[STUB_PREFIX <prefix>]
5364
)
5465
5566
From the example's
@@ -275,6 +286,23 @@ To generate Rust stubs, pass ``STUB_TARGET rust`` to ``tvm_ffi_configure_target`
275286
(see :ref:`sec-stubgen-cmake`) or ``--target rust`` on the command line
276287
(see :ref:`sec-stubgen-cli`).
277288

289+
To generate Python and Rust stubs from a single target, list both backends in
290+
``STUB_TARGET``. Because each backend writes a different file tree, give the output
291+
directories per backend via ``STUB_DIR_PYTHON`` and ``STUB_DIR_RUST`` (instead of
292+
``STUB_DIR``):
293+
294+
.. code-block:: cmake
295+
296+
tvm_ffi_configure_target(my_ffi_extension
297+
STUB_TARGET python rust
298+
STUB_INIT ON
299+
STUB_DIR_PYTHON "./python"
300+
STUB_DIR_RUST "./rust/src/generated")
301+
302+
This is equivalent to invoking stub generation once per listed backend (with
303+
``--target python`` and ``--target rust``). The shared ``STUB_PKG`` / ``STUB_PREFIX``
304+
apply to every listed backend.
305+
278306
Key Features
279307
~~~~~~~~~~~~
280308

0 commit comments

Comments
 (0)