This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch jenkins-wheel-test-artifacts
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/jenkins-wheel-test-artifacts
by this push:
new d42a11f43f [CI] Install pinned FFI source alongside TVM test wheels
d42a11f43f is described below
commit d42a11f43f9d12fde50f907896a7949537aa8dc7
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Oct 15 02:12:23 2026 +0000
[CI] Install pinned FFI source alongside TVM test wheels
---
ci/jenkins/README.md | 11 ++++++++---
tests/scripts/task_python_install_wheels.sh | 24 +++++++++++++++++-------
2 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/ci/jenkins/README.md b/ci/jenkins/README.md
index 4391f32ff1..84f7d8962b 100644
--- a/ci/jenkins/README.md
+++ b/ci/jenkins/README.md
@@ -101,7 +101,7 @@ resolve runtime dependencies. CPU, ARM and Wasm host builds
request `all;cpptest
and run C++ tests in that same native tree before uploading anything. Python
consumers install the exact TVM wheel with `--no-deps --offline`, clear
checkout
path overrides, and verify the package and native-library paths. FFI comes from
-the image. GPU Java tests also receive their existing native runtime libraries;
+the checked-out submodule. GPU Java tests also receive their existing native
runtime libraries;
the separate runtime-only compile check and Emscripten runtime build remain.
Immediately before building, the same container and Python install the declared
@@ -114,8 +114,13 @@ modifying the image environment or exposing the build
overlay to test consumers.
`uv build` then runs offline without isolation.
The selected images must already provide compatible runtime and test
dependencies,
-including apache-tvm-ffi. Consumer wheel installation remains `--no-deps
--offline`;
-missing runtime dependencies are errors rather than permission to fetch
replacements.
+apart from apache-tvm-ffi. Consumers install the checkout's pinned FFI source
into
+the writable test environment with `--no-deps`, using its declared isolated
build
+requirements. They then install the transferred TVM wheel with `--no-deps
--offline`.
+The checkout remains available for tests and resources through `TVM_HOME`,
including
+Wasm assets under `web/dist`, without adding its Python package ahead of the
wheel. Provenance checks verify both TVM/native libraries and
+source-built FFI load from the test environment; other missing runtime
dependencies
+remain errors rather than permission to fetch replacements.
`CMAKE_BUILD_PARALLEL_LEVEL` is passed through Docker as an environment
variable.
An explicit value wins; otherwise builds use at least one CPU and divide the
diff --git a/tests/scripts/task_python_install_wheels.sh
b/tests/scripts/task_python_install_wheels.sh
index 0138187eac..ca580141e3 100644
--- a/tests/scripts/task_python_install_wheels.sh
+++ b/tests/scripts/task_python_install_wheels.sh
@@ -20,6 +20,8 @@
# Docker defaults PYTHONPATH to the checkout; never let it shadow the
artifacts.
unset PYTHONPATH TVM_LIBRARY_PATH TVM_FFI_LIBRARY_PATH
export PYTHONNOUSERSITE=1
+# Installed TVM still needs checkout resources such as web/dist for Wasm
linking.
+export TVM_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TVM_WHEEL_DIR="$(realpath "${TVM_WHEEL_DIR:-$(pwd)/build/wheels}")"
# Preserve the image's active environment (often itself a venv), including when
# local ci.py sources this setup again for a named test suite.
@@ -32,19 +34,25 @@ uv venv --offline --python "$TVM_IMAGE_PYTHON" --clear
"$VIRTUAL_ENV"
TVM_WHEEL_SITE="$("$VIRTUAL_ENV/bin/python3" -c 'import sysconfig;
print(sysconfig.get_path("purelib"))')"
printf '%s\n' "$TVM_IMAGE_SITE_PACKAGES" >
"$TVM_WHEEL_SITE/image-dependencies.pth"
export PATH="$VIRTUAL_ENV/bin:$PATH"
+# Keep the checkout available to tests and build its pinned FFI into this
environment.
+# FFI declares its own isolated build requirements; do not reuse TVM's build
overlay.
+export TVM_FFI_SOURCE="$TVM_HOME/3rdparty/tvm-ffi"
+uv pip install --python "$VIRTUAL_ENV/bin/python3" --no-deps --reinstall
"$TVM_FFI_SOURCE"
uv pip install --python "$VIRTUAL_ENV/bin/python3" --no-deps --offline
--reinstall \
"$TVM_WHEEL_DIR"/apache_tvm-*.whl
# Fail before pytest if a source/editable install or native override leaked in.
python3 - <<'PYTHON'
+import json
import os
import sys
-from importlib.metadata import requires, version
+from importlib.metadata import distribution, requires, version
from pathlib import Path
+from urllib.parse import unquote, urlparse
from packaging.requirements import Requirement
-# --no-deps leaves dependency ownership with the image. Check the wheel's own
-# requirements without invoking a resolver or accepting a stale hardcoded
floor.
+# FFI comes from pinned source; other runtime dependencies remain image-owned.
+# Check the wheel requirements without invoking a resolver or hardcoding a
floor.
for text in requires("apache-tvm") or []:
requirement = Requirement(text)
if requirement.marker and not requirement.marker.evaluate({"extra": ""}):
@@ -59,11 +67,13 @@ prefix = Path(sys.prefix).resolve()
path = Path(tvm.__file__).resolve()
assert path.is_relative_to(prefix), path
print(f"Installed tvm: {path}")
-# FFI is supplied by the image, not rebuilt or transferred with TVM.
-image_sites = [Path(p).resolve() for p in
os.environ["TVM_IMAGE_SITE_PACKAGES"].splitlines()]
+# Verify FFI was installed from this checkout and loads entirely from this
environment.
+source =
json.loads(distribution("apache-tvm-ffi").read_text("direct_url.json"))
+assert Path(unquote(urlparse(source["url"]).path)).resolve() ==
Path(os.environ["TVM_FFI_SOURCE"]).resolve()
+assert not source.get("dir_info", {}).get("editable", False), source
for path in (Path(tvm_ffi.__file__).resolve(),
Path(tvm_ffi.LIB._name).resolve()):
- assert any(path.is_relative_to(site) for site in image_sites), path
- print(f"Image FFI: {path}")
+ assert path.is_relative_to(prefix), path
+ print(f"Source-built FFI: {path}")
assert {"tvm_runtime", "tvm_compiler"} <= tvm.base._LOADED_LIBS.keys()
for name, library in tvm.base._LOADED_LIBS.items():
path = Path(library._name).resolve()