pytorch - ✅(Solved) Fix [RFC] Decouple `torch.utils.cpp_extension` from setuptools and align with the scikit-build-core build backend [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
pytorch/pytorch#180624Fetched 2026-04-17 08:25:57
View on GitHub
Comments
0
Participants
1
Timeline
21
Reactions
0
Author
Participants
Timeline (top)
mentioned ×7subscribed ×7labeled ×6cross-referenced ×1

With PyTorch's own build backend migration to scikit-build-core (see #157807), this RFC proposes to refactor torch.utils.cpp_extension so that PyTorch no longer carries a runtime dependency on setuptools, and to clarify the long-term story for downstream projects that build C++/CUDA/SYCL extensions against PyTorch.

The proposal is deliberately non-disruptive in the short term: cpp_extension's public API is preserved, and today's setup.py-based downstream projects keep working. The changes are a module split, a data/adapter decoupling, and documentation work to make find_package(Torch) the first-class path for modern binary build backends.

Root Cause

With PyTorch's own build backend migration to scikit-build-core (see #157807), this RFC proposes to refactor torch.utils.cpp_extension so that PyTorch no longer carries a runtime dependency on setuptools, and to clarify the long-term story for downstream projects that build C++/CUDA/SYCL extensions against PyTorch.

The proposal is deliberately non-disruptive in the short term: cpp_extension's public API is preserved, and today's setup.py-based downstream projects keep working. The changes are a module split, a data/adapter decoupling, and documentation work to make find_package(Torch) the first-class path for modern binary build backends.

PR fix notes

PR #180707: Improve cpp_extension and drop setuptools runtime requirement

Description (problem / solution / changelog)

This implements the changes proposed in #180624, clarifying the different facets of torch.utils.cpp_extension and removing setuptools as a runtime requirement.

Depends on the stack #177641--#180250.

Closes #180624.

Changed files

  • test/test_cpp_extensions_imports.py (added, +130/-0)
  • tools/metadata/dependencies.py (added, +70/-0)
  • torch/utils/cpp_extension.py (removed, +0/-3203)
  • torch/utils/cpp_extension/__init__.py (added, +119/-0)
  • torch/utils/cpp_extension/_discovery.py (added, +896/-0)
  • torch/utils/cpp_extension/_jit.py (added, +1728/-0)
  • torch/utils/cpp_extension/setuptools.py (added, +1120/-0)

Code Example

torch/utils/cpp_extension/
    __init__.py        # re-exports; imports nothing from setuptools
    _discovery.py      # CUDA_HOME / ROCM_HOME / SYCL_HOME / HIP_HOME,
                       # include_paths, library_paths, ABI checks,
                       # ninja discovery, compiler helpers, version maps
    _jit.py            # load, load_inline, _jit_compile,
                       # _write_ninja_file*, _run_ninja_build, PCH helpers
    setuptools.py      # BuildExtension + *.to_setuptools() adapters;
                       # the ONLY module that imports setuptools
RAW_BUFFERClick to expand / collapse

Summary

With PyTorch's own build backend migration to scikit-build-core (see #157807), this RFC proposes to refactor torch.utils.cpp_extension so that PyTorch no longer carries a runtime dependency on setuptools, and to clarify the long-term story for downstream projects that build C++/CUDA/SYCL extensions against PyTorch.

The proposal is deliberately non-disruptive in the short term: cpp_extension's public API is preserved, and today's setup.py-based downstream projects keep working. The changes are a module split, a data/adapter decoupling, and documentation work to make find_package(Torch) the first-class path for modern binary build backends.

Motivation

torch/utils/cpp_extension.py is 3,203 lines and conflates three independent concerns:

  1. A setuptools bridgeCppExtension / CUDAExtension / SyclExtension return setuptools.Extension, and BuildExtension subclasses setuptools.command.build_ext.
  2. A JIT compile pathload() / load_inline() drive ninja directly and have nothing to do with setuptools.
  3. Query helpersinclude_paths(), library_paths(), CUDA_HOME, ROCM_HOME, SYCL_HOME, IS_HIP_EXTENSION, get_compiler_abi_compatibility_and_version(), etc. — usable by any binary build tool.

Top-level import setuptools statements (at torch/utils/cpp_extension.py:10 and :30) make setuptools an effective runtime dependency of PyTorch purely to serve facet 1. With the scikit-build-core migration complete, downstream users who already want to move off setuptools have no reason to be forced through it by the toolchain they consume.

In parallel, cpp_extension duplicates knowledge that CMake now owns authoritatively: library names (torch, c10, torch_cpu, torch_python, torch_cuda, c10_xpu, …), include paths, C++ standard, ABI flags, whole-archive rules. TorchConfig.cmake / Caffe2Targets.cmake already export this via the imported torch target. For downstream projects built with scikit-build-core or meson-python, find_package(Torch) is the natural path and obviates the *Extension factories entirely.

cpp_extension is not broken by the scikit-build-core migration — the on-disk wheel layout (torch/lib/, torch/include/, torch/share/cmake/{Torch,Caffe2}/) is preserved, torch.version.* is now generated by CMake, and pyproject.toml explicitly carves out [tool.scikit-build.install] strip = false "for torch.utils.cpp_extension, ABI checks in CI". This RFC is a cleanup, not a triage fire.

Downstream user archetypes

Downstream projectBuild backendWhat they need from PyTorch
Pure Python, no binariespoetry, hatchlingNothing from cpp_extension at package-build time. May still use load() at runtime.
Binary, setuptoolssetuptoolsCppExtension / BuildExtension — the facet 1 compat surface.
Binary, scikit-build-coreCMakefind_package(Torch) — should not go through cpp_extension.
Binary, meson-pythonMesonMeson dependency discovery — should not go through cpp_extension.
JIT / runtime compileanytorch.utils.cpp_extension.load() / load_inline().
Anyone discovering paths/flags from CMake/MesonanyQuery helpers (include_paths(), CUDA_HOME, …).

The key observation is that scikit-build-core and meson-python users should not be consumers of facet 1 — the whole point of a native binary build backend is that CMake/Meson have richer target models than a Python-level Extension object. The "replacement of cpp_extension" for those users is not a new Python module; it's a hardened, documented find_package(Torch).

Proposal

Phase 1 — In-tree module split with lazy setuptools import

Convert torch/utils/cpp_extension.py into a package:

torch/utils/cpp_extension/
    __init__.py        # re-exports; imports nothing from setuptools
    _discovery.py      # CUDA_HOME / ROCM_HOME / SYCL_HOME / HIP_HOME,
                       # include_paths, library_paths, ABI checks,
                       # ninja discovery, compiler helpers, version maps
    _jit.py            # load, load_inline, _jit_compile,
                       # _write_ninja_file*, _run_ninja_build, PCH helpers
    setuptools.py      # BuildExtension + *.to_setuptools() adapters;
                       # the ONLY module that imports setuptools

Rules:

  • __init__.py, _discovery.py, _jit.py contain no import setuptools. Enforced by a CI test that imports each with sys.modules["setuptools"] = None.
  • The full public API at torch/utils/cpp_extension.py:101-103 is re-exported from __init__.py. Module-level constants (CUDA_HOME, ROCM_HOME, IS_HIP_EXTENSION) that are consumed by in-tree tests but not in __all__ today are promoted to __all__.
  • PyTorch's runtime dependency metadata drops setuptools.

Backwards compatibility: 100% source-level compatibility for documented public API.

Note that downstream packages in need of setuptools adapter are all but guaranteed to have setuptools as a build requirement so that pytorch not adding it as a requirement will not break their build process.

Phase 2 — Extract setuptools adapter to a separate PyPI package

Publish a small companion package (name TBD — e.g. torch-extension-setuptools) owned by the PyTorch team, re-exporting BuildExtension and the .to_setuptools() adapters. Setuptools-based downstream users pip install it alongside torch.

In PyTorch itself, torch.utils.cpp_extension.setuptools becomes a thin forwarder emitting a DeprecationWarning that points at the external package, still functional during the deprecation window.

Benefits:

  • The adapter can iterate with setuptools on its own release cadence.
  • Deprecation messaging is concrete — it's a different package.
  • PyTorch's codebase stops growing setuptools-specific paths.

Phase 3 — Remove in-tree setuptools adapter

After the documented deprecation window, delete torch/utils/cpp_extension/setuptools.py. PyTorch is fully out of the setuptools business. The external companion package continues to serve projects that still need it.

Parallel track — Harden the CMake downstream path

This is what scikit-build-core and Meson users actually need; no Python module will replace it.

  • Audit cmake/TorchConfig.cmake.in: it currently exports TORCH_INCLUDE_DIRS, TORCH_LIBRARIES, TORCH_CXX_FLAGS, and an imported torch target with INTERFACE_INCLUDE_DIRECTORIES + CXX_STANDARD 20. Verify downstream extensions receive the same ABI / define set that PyTorch's own targets use — in particular GLIBCXX_USE_CXX11_ABI, TORCH_API visibility, and the CUDA flag set that cpp_extension's COMMON_NVCC_FLAGS currently injects manually.
  • Add a downstream example project docs/examples/cpp_extension_skbuild/ — minimal pyproject.toml + CMakeLists.txt + pybind11 module, building via scikit-build-core against the installed torch wheel.
  • Evaluate shipping a Meson dependency() adapter / pkg-config .pc file for meson-python downstream users. (Open question — see below.)
  • Restructure docs/source/cpp_extension.{md,rst} to lead with the CMake example and relegate setuptools to a clearly-marked "legacy" section.

Impact and backwards compatibility

  • Setuptools AOT users (facet 1): zero-impact in phase 1, soft deprecation in phase 2, must pip install torch-extension-setuptools at phase 3. No source-level API changes at any phase.
  • JIT users (facet 2): zero impact. load() / load_inline() are untouched.
  • Query-helper users (facet 3): zero impact. Same import paths.
  • scikit-build-core / meson-python users: net positive — a first-class, documented CMake path and an example project. No Python-level migration needed.
  • PyTorch install footprint: drops setuptools from runtime deps after phase 1.

Alternatives considered

  • Leave cpp_extension as-is. Works, but perpetuates the setuptools dependency and keeps 3,000+ lines of duplicated build knowledge in Python. Not sustainable as CMake continues to be the source of truth.
  • Rewrite load() / load_inline() on top of CMake (generate a tiny CMakeLists.txt and invoke cmake+ninja per extension). Plausible but not motivated — the current ninja path works, has a large installed base, and is not the source of the setuptools coupling. Deferred as a possible follow-up.
  • Delete cpp_extension outright. Too disruptive — the ecosystem (apex, torch-scatter, xformers, etc.) depends on the current surface. The phased deprecation path in this RFC is less painful.

Out of scope

  • The actual authoring of the external torch-extension-setuptools package (follow-up work in phase 2).
  • Replacing the JIT implementation with a CMake-backed one.
  • Editable-install (pip install -e .) verification for cpp_extension under the scikit-build-core redirect mode — worth an empirical check but orthogonal to this refactor.
  • Changes to the hipify pipeline or CUDA arch detection beyond what's needed to keep the existing tests passing.

Open questions

  1. External package name. torch-extension-setuptools? pytorch-setuptools-ext? Something else? Should it live under the pytorch GitHub org?
  2. Deprecation window length. Proposal: one minor release emits DeprecationWarning from the in-tree adapter, the following minor release removes it. Is that too aggressive given the ecosystem?
  3. Meson / pkg-config support. Should PyTorch ship a Meson dependency file or pkg-config .pc alongside the existing CMake exports, or is that left to the community?
  4. Promotion of CUDA_HOME / ROCM_HOME / IS_HIP_EXTENSION to __all__. They are de-facto public (used in-tree at test/cpp_extensions/setup.py and test/test_cpp_extensions_jit.py). Formalize them as part of this RFC, or leave implicit?

References

  • #157807 — scikit-build-core migration RFC (context and predecessor work).
  • cmake/TorchConfig.cmake.in — current CMake export surface for downstream find_package(Torch).
  • torch/utils/cpp_extension.py — the module this RFC proposes to split.
  • pyproject.toml:47-50 — the strip = false carve-out that acknowledges cpp_extension's current role.

cc @malfet @seemethere @janeyx99, @seemethere, @albanD, @atalman

extent analysis

TL;DR

Refactor torch.utils.cpp_extension to remove the runtime dependency on setuptools by splitting the module into separate components and introducing a companion package for setuptools adapters.

Guidance

  • Split torch/utils/cpp_extension.py into separate modules for setuptools bridge, JIT compile path, and query helpers to reduce coupling and dependencies.
  • Introduce a companion package (e.g., torch-extension-setuptools) to provide setuptools adapters for downstream projects, allowing PyTorch to drop its runtime dependency on setuptools.
  • Update documentation to lead with the CMake example and relegate setuptools to a "legacy" section, ensuring a smooth transition for scikit-build-core and meson-python users.
  • Audit and harden the CMake downstream path to ensure consistency and accuracy of exported targets and variables.

Example

# torch/utils/cpp_extension/__init__.py
from . import _discovery
from . import _jit
from . import setuptools

__all__ = [
    # Re-export public API
    'CppExtension',
    'CUDAExtension',
    'SyclExtension',
    # ...
]

Notes

The proposed refactor aims to reduce the complexity and dependencies of torch.utils.cpp_extension while maintaining backwards compatibility. However, the deprecation window length and external package name are still open questions that require further discussion.

Recommendation

Apply the proposed refactor in phases, starting with the module split and introduction of the companion package, to ensure a smooth transition for downstream projects and minimize disruptions to the ecosystem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

pytorch - ✅(Solved) Fix [RFC] Decouple `torch.utils.cpp_extension` from setuptools and align with the scikit-build-core build backend [1 pull requests, 1 participants]