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 ff7e3d4f [FIX] Select the C++ standard for the torch addon by torch 
version (#687)
ff7e3d4f is described below

commit ff7e3d4f6ece3ffcf48b7111932fd7b6bd77db5d
Author: Yaxing Cai <[email protected]>
AuthorDate: Mon Jul 27 06:04:35 2026 +0800

    [FIX] Select the C++ standard for the torch addon by torch version (#687)
    
    Torch 2.13 uses C++20 constructs in its public headers, such as
    designated initializers and default member initializers for bit-fields,
    and builds its own extensions with C++20 accordingly. The torch C-DLPack
    addon still compiled with C++17, which makes the Windows wheel job fail
    to compile:
    
    ```
    error C7582: default member initializers for bit-fields requires at least 
/std:c++20
    error C7555: use of designated initializers requires at least /std:c++20
    error C2139: 'torch::autograd::Node': an undefined class is not allowed as 
an argument to compiler intrinsic type trait '__is_base_of'
    ```
    
    GCC and Clang accept those constructs in C++17 mode as extensions and
    only warn about them, so Linux and macOS keep building while MSVC
    rejects them outright. That is why `main` has been red on Windows since
    torch 2.13.0 (released 2026-07-08) while the other platforms stayed
    green on the same commit.
    
    ### Changes
    
    - Select the C++ standard from the installed torch version rather than
    hard-coding it: C++20 for torch 2.13 and later, C++17 before that.
    Applied to both the Windows (`/std:`) and Linux/macOS (`-std=`) build
    paths.
    - The build script already reports compiler errors through its own
    stderr, but the tests discarded the child output and asserted on the
    exit code alone, so failures surfaced as a bare `exit status 1` and hid
    the diagnostics above. Capture that output and attach it to the
    assertion.
    
    ### Testing
    
    - `tests/python/test_optional_torch_c_dlpack.py` passes on Linux with
    torch 2.13.0, building the addon from a clean cache.
    - Version selection verified across torch 2.8.0, 2.12.1, 2.13.0, 2.13.1,
    2.14.0 and 3.0.0.
    - The Windows wheel job only runs on `main` (`ci_mainline_only.yml`) and
    installs torch 2.13 there, so it was validated by dispatching that
    workflow against this branch.
---
 .../utils/_build_optional_torch_c_dlpack.py        | 22 ++++++++++++++--
 tests/python/test_optional_torch_c_dlpack.py       | 29 +++++++++++++++++++---
 2 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/python/tvm_ffi/utils/_build_optional_torch_c_dlpack.py 
b/python/tvm_ffi/utils/_build_optional_torch_c_dlpack.py
index 7277568d..9e4f9a16 100644
--- a/python/tvm_ffi/utils/_build_optional_torch_c_dlpack.py
+++ b/python/tvm_ffi/utils/_build_optional_torch_c_dlpack.py
@@ -589,6 +589,24 @@ def parse_env_flags(env_var_name: str) -> list[str]:
     return []
 
 
+def get_cpp_standard() -> str:
+    """Get the C++ standard required to compile against the installed torch 
headers.
+
+    Torch 2.13 started using C++20 constructs such as designated initializers 
and
+    default member initializers for bit-fields in its public headers, and 
builds its
+    own extensions with C++20 accordingly. Older versions build with C++17.
+
+    Returns
+    -------
+    standard : str
+        Either ``"c++17"`` or ``"c++20"``.
+
+    """
+    if torch.__version__ >= torch.torch_version.TorchVersion("2.13.0"):
+        return "c++20"
+    return "c++17"
+
+
 def _run_build_on_linux_like(
     build_dir: Path,
     libname: str,
@@ -600,7 +618,7 @@ def _run_build_on_linux_like(
     """Build the module directly by invoking compiler commands (non-Windows 
only)."""
     from tvm_ffi.libinfo import find_dlpack_include_path  # noqa: PLC0415
 
-    default_cflags = ["-std=c++17", "-fPIC", "-O3", "-fvisibility=hidden"]
+    default_cflags = [f"-std={get_cpp_standard()}", "-fPIC", "-O3", 
"-fvisibility=hidden"]
     # Platform-specific linker flags
     if IS_DARWIN:
         # macOS uses @loader_path instead of $ORIGIN
@@ -650,7 +668,7 @@ def _generate_ninja_build_windows(
     from tvm_ffi.libinfo import find_dlpack_include_path  # noqa: PLC0415
 
     default_cflags = [
-        "/std:c++17",
+        f"/std:{get_cpp_standard()}",
         "/MD",
         "/wd4819",
         "/wd4251",
diff --git a/tests/python/test_optional_torch_c_dlpack.py 
b/tests/python/test_optional_torch_c_dlpack.py
index 2a27892d..398afdbb 100644
--- a/tests/python/test_optional_torch_c_dlpack.py
+++ b/tests/python/test_optional_torch_c_dlpack.py
@@ -110,6 +110,20 @@ def 
test_existing_torch_dlpack_api_is_preferred_on_rocm(monkeypatch: pytest.Monk
     assert _optional_torch_c_dlpack.load_torch_c_dlpack_extension() is None
 
 
+def _run_build(args: list[str]) -> None:
+    """Run the addon build script, surfacing its output when the build fails.
+
+    The build script reports compiler and linker errors through its own 
stderr, so
+    capture it and attach it to the failure instead of only reporting the exit 
code.
+    """
+    result = subprocess.run(args, capture_output=True, text=True, check=False)
+    if result.returncode != 0:
+        raise AssertionError(
+            f"Build failed with exit status {result.returncode}\n"
+            f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}"
+        )
+
+
 @pytest.mark.skipif(torch is None, reason="torch is not installed")
 def test_build_torch_c_dlpack_extension() -> None:
     assert torch is not None
@@ -132,7 +146,7 @@ def test_build_torch_c_dlpack_extension() -> None:
             args.append("--build-with-rocm")
         else:
             raise ValueError("Cannot determine whether to build with CUDA or 
ROCm.")
-    subprocess.run(args, check=True)
+    _run_build(args)
 
     lib_path = 
str(Path("./output-dir/libtorch_c_dlpack_addon_test.so").resolve())
     assert Path(lib_path).exists()
@@ -153,13 +167,20 @@ def test_parallel_build() -> None:
     processes = []
     for i in range(num_processes):
         p = subprocess.Popen(
-            [sys.executable, str(build_script), "--output-dir", output_dir, 
"--libname", libname]
+            [sys.executable, str(build_script), "--output-dir", output_dir, 
"--libname", libname],
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            text=True,
         )
         processes.append((p, output_dir))
 
     for p, output_dir in processes:
-        p.wait()
-        assert p.returncode == 0
+        stdout, stderr = p.communicate()
+        if p.returncode != 0:
+            raise AssertionError(
+                f"Build failed with exit status {p.returncode}\n"
+                f"stdout:\n{stdout}\nstderr:\n{stderr}"
+            )
     lib_path = str(Path(f"{output_dir}/{libname}").resolve())
     assert Path(lib_path).exists()
 

Reply via email to