Replace setup.py bdist_wheel with python -m build --wheel (#156712)

Previously we already replaced most use of `python setup.py develop/install`.

This PR also replaces the use of `setup.py bdist_wheel` with the modern `python -m build --wheel` alternative.

Pull Request resolved: https://github.com/pytorch/pytorch/pull/156712
Approved by: https://github.com/atalman
ghstack dependencies: #156711
This commit is contained in:
Klaus Zimmermann
2025-09-29 10:37:15 +02:00
committed by PyTorch MergeBot
parent c332d58184
commit 50d418f69f
22 changed files with 61 additions and 54 deletions

View File

@ -372,7 +372,7 @@ if __name__ == "__main__":
else: else:
print("build pytorch without mkldnn backend") print("build pytorch without mkldnn backend")
os.system(f"cd /pytorch; {build_vars} python3 setup.py bdist_wheel") os.system(f"cd /pytorch; {build_vars} python3 -m build --wheel --no-isolation")
if enable_cuda: if enable_cuda:
print("Updating Cuda Dependency") print("Updating Cuda Dependency")
filename = os.listdir("/pytorch/dist/") filename = os.listdir("/pytorch/dist/")

View File

@ -442,7 +442,7 @@ def build_torchvision(
if host.using_docker(): if host.using_docker():
build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000" build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000"
host.run_cmd(f"cd vision && {build_vars} python3 setup.py bdist_wheel") host.run_cmd(f"cd vision && {build_vars} python3 -m build --wheel --no-isolation")
vision_wheel_name = host.list_dir("vision/dist")[0] vision_wheel_name = host.list_dir("vision/dist")[0]
embed_libgomp(host, use_conda, os.path.join("vision", "dist", vision_wheel_name)) embed_libgomp(host, use_conda, os.path.join("vision", "dist", vision_wheel_name))
@ -497,7 +497,7 @@ def build_torchdata(
if host.using_docker(): if host.using_docker():
build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000" build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000"
host.run_cmd(f"cd data && {build_vars} python3 setup.py bdist_wheel") host.run_cmd(f"cd data && {build_vars} python3 -m build --wheel --no-isolation")
wheel_name = host.list_dir("data/dist")[0] wheel_name = host.list_dir("data/dist")[0]
embed_libgomp(host, use_conda, os.path.join("data", "dist", wheel_name)) embed_libgomp(host, use_conda, os.path.join("data", "dist", wheel_name))
@ -553,7 +553,7 @@ def build_torchtext(
if host.using_docker(): if host.using_docker():
build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000" build_vars += " CMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=0x10000"
host.run_cmd(f"cd text && {build_vars} python3 setup.py bdist_wheel") host.run_cmd(f"cd text && {build_vars} python3 -m build --wheel --no-isolation")
wheel_name = host.list_dir("text/dist")[0] wheel_name = host.list_dir("text/dist")[0]
embed_libgomp(host, use_conda, os.path.join("text", "dist", wheel_name)) embed_libgomp(host, use_conda, os.path.join("text", "dist", wheel_name))
@ -614,7 +614,7 @@ def build_torchaudio(
host.run_cmd( host.run_cmd(
f"cd audio && export FFMPEG_ROOT=$(pwd)/third_party/ffmpeg && export USE_FFMPEG=1 \ f"cd audio && export FFMPEG_ROOT=$(pwd)/third_party/ffmpeg && export USE_FFMPEG=1 \
&& ./packaging/ffmpeg/build.sh \ && ./packaging/ffmpeg/build.sh \
&& {build_vars} python3 setup.py bdist_wheel" && {build_vars} python3 -m build --wheel --no-isolation"
) )
wheel_name = host.list_dir("audio/dist")[0] wheel_name = host.list_dir("audio/dist")[0]
@ -726,7 +726,7 @@ def start_build(
print("Building PyTorch wheel") print("Building PyTorch wheel")
build_opts = "" build_opts = ""
if pytorch_build_number is not None: if pytorch_build_number is not None:
build_opts += f" --build-number {pytorch_build_number}" build_opts += f" -C--build-option=--build-number={pytorch_build_number}"
# Breakpad build fails on aarch64 # Breakpad build fails on aarch64
build_vars = "USE_BREAKPAD=0 " build_vars = "USE_BREAKPAD=0 "
if branch == "nightly": if branch == "nightly":
@ -747,7 +747,8 @@ def start_build(
print("build pytorch with mkldnn+acl backend") print("build pytorch with mkldnn+acl backend")
build_vars += " USE_MKLDNN=ON USE_MKLDNN_ACL=ON" build_vars += " USE_MKLDNN=ON USE_MKLDNN_ACL=ON"
host.run_cmd( host.run_cmd(
f"cd $HOME/pytorch && export ACL_ROOT_DIR=$HOME/ComputeLibrary && {build_vars} python3 setup.py bdist_wheel{build_opts}" f"cd $HOME/pytorch && export ACL_ROOT_DIR=$HOME/ComputeLibrary && "
f"{build_vars} python3 -m build --wheel --no-isolation{build_opts}"
) )
print("Repair the wheel") print("Repair the wheel")
pytorch_wheel_name = host.list_dir("pytorch/dist")[0] pytorch_wheel_name = host.list_dir("pytorch/dist")[0]
@ -763,7 +764,7 @@ def start_build(
else: else:
print("build pytorch without mkldnn backend") print("build pytorch without mkldnn backend")
host.run_cmd( host.run_cmd(
f"cd pytorch && {build_vars} python3 setup.py bdist_wheel{build_opts}" f"cd pytorch && {build_vars} python3 -m build --wheel --no-isolation{build_opts}"
) )
print("Deleting build folder") print("Deleting build folder")

View File

@ -452,12 +452,3 @@ elif [ "$HAS_TRITON" = "yes" ]; then
echo "expecting triton to not be installed, but it is" echo "expecting triton to not be installed, but it is"
exit 1 exit 1
fi fi
# Sanity check cmake version. Executorch reinstalls cmake and I'm not sure if
# they support 4.0.0 yet, so exclude them from this check.
CMAKE_VERSION=$(drun cmake --version)
if [[ "$EXECUTORCH" != *yes* && "$CMAKE_VERSION" != *4.* ]]; then
echo "CMake version is not 4.0.0:"
drun cmake --version
exit 1
fi

View File

@ -66,15 +66,15 @@ if [ -n "${UBUNTU_VERSION}" ] && [ -n "${GCC_VERSION}" ] && [[ "${GCC_VERSION}"
# Triton needs at least gcc-9 to build # Triton needs at least gcc-9 to build
apt-get install -y g++-9 apt-get install -y g++-9
CXX=g++-9 conda_run python setup.py bdist_wheel CXX=g++-9 conda_run python -m build --wheel --no-isolation
elif [ -n "${UBUNTU_VERSION}" ] && [ -n "${CLANG_VERSION}" ]; then elif [ -n "${UBUNTU_VERSION}" ] && [ -n "${CLANG_VERSION}" ]; then
# Triton needs <filesystem> which surprisingly is not available with clang-9 toolchain # Triton needs <filesystem> which surprisingly is not available with clang-9 toolchain
add-apt-repository -y ppa:ubuntu-toolchain-r/test add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get install -y g++-9 apt-get install -y g++-9
CXX=g++-9 conda_run python setup.py bdist_wheel CXX=g++-9 conda_run python -m build --wheel --no-isolation
else else
conda_run python setup.py bdist_wheel conda_run python -m build --wheel --no-isolation
fi fi
# Copy the wheel to /opt for multi stage docker builds # Copy the wheel to /opt for multi stage docker builds

View File

@ -10,6 +10,11 @@ boto3==1.35.42
#Pinned versions: 1.19.12, 1.16.34 #Pinned versions: 1.19.12, 1.16.34
#test that import: #test that import:
build==1.3.0
#Description: A simple, correct Python build frontend.
#Pinned versions: 1.3.0
#test that import:
click click
#Description: Command Line Interface Creation Kit #Description: Command Line Interface Creation Kit
#Pinned versions: #Pinned versions:
@ -106,10 +111,10 @@ networkx==2.8.8
#Pinned versions: 2.8.8 #Pinned versions: 2.8.8
#test that import: functorch #test that import: functorch
ninja==1.11.1.3 ninja==1.11.1.4
#Description: build system. Used in some tests. Used in build to generate build #Description: build system. Used in some tests. Used in build to generate build
#time tracing information #time tracing information
#Pinned versions: 1.11.1.3 #Pinned versions: 1.11.1.4
#test that import: run_test.py, test_cpp_extensions_aot.py,test_determination.py #test that import: run_test.py, test_cpp_extensions_aot.py,test_determination.py
numba==0.55.2 ; python_version == "3.10" and platform_machine != "s390x" numba==0.55.2 ; python_version == "3.10" and platform_machine != "s390x"
@ -373,7 +378,7 @@ dataclasses_json==0.6.7
#Pinned versions: 0.6.7 #Pinned versions: 0.6.7
#test that import: #test that import:
cmake==4.0.0 cmake==3.31.6
#Description: required for building #Description: required for building
tlparse==0.4.0 tlparse==0.4.0

View File

@ -142,7 +142,7 @@ time CMAKE_ARGS=${CMAKE_ARGS[@]} \
EXTRA_CAFFE2_CMAKE_FLAGS=${EXTRA_CAFFE2_CMAKE_FLAGS[@]} \ EXTRA_CAFFE2_CMAKE_FLAGS=${EXTRA_CAFFE2_CMAKE_FLAGS[@]} \
BUILD_LIBTORCH_CPU_WITH_DEBUG=$BUILD_DEBUG_INFO \ BUILD_LIBTORCH_CPU_WITH_DEBUG=$BUILD_DEBUG_INFO \
USE_NCCL=${USE_NCCL} USE_RCCL=${USE_RCCL} USE_KINETO=${USE_KINETO} \ USE_NCCL=${USE_NCCL} USE_RCCL=${USE_RCCL} USE_KINETO=${USE_KINETO} \
python setup.py bdist_wheel -d /tmp/$WHEELHOUSE_DIR python -m build --wheel --no-isolation --outdir /tmp/$WHEELHOUSE_DIR
echo "Finished setup.py bdist at $(date)" echo "Finished setup.py bdist at $(date)"
# Build libtorch packages # Build libtorch packages

View File

@ -290,13 +290,13 @@ else
WERROR=1 python setup.py clean WERROR=1 python setup.py clean
WERROR=1 python setup.py bdist_wheel WERROR=1 python -m build --wheel --no-isolation
else else
python setup.py clean python setup.py clean
if [[ "$BUILD_ENVIRONMENT" == *xla* ]]; then if [[ "$BUILD_ENVIRONMENT" == *xla* ]]; then
source .ci/pytorch/install_cache_xla.sh source .ci/pytorch/install_cache_xla.sh
fi fi
python setup.py bdist_wheel python -m build --wheel --no-isolation
fi fi
pip_install_whl "$(echo dist/*.whl)" pip_install_whl "$(echo dist/*.whl)"

View File

@ -36,11 +36,11 @@ fi
print_cmake_info print_cmake_info
if [[ ${BUILD_ENVIRONMENT} == *"distributed"* ]]; then if [[ ${BUILD_ENVIRONMENT} == *"distributed"* ]]; then
# Needed for inductor benchmarks, as lots of HF networks make `torch.distribtued` calls # Needed for inductor benchmarks, as lots of HF networks make `torch.distribtued` calls
USE_DISTRIBUTED=1 USE_OPENMP=1 WERROR=1 python setup.py bdist_wheel USE_DISTRIBUTED=1 USE_OPENMP=1 WERROR=1 python -m build --wheel --no-isolation
else else
# Explicitly set USE_DISTRIBUTED=0 to align with the default build config on mac. This also serves as the sole CI config that tests # Explicitly set USE_DISTRIBUTED=0 to align with the default build config on mac. This also serves as the sole CI config that tests
# that building with USE_DISTRIBUTED=0 works at all. See https://github.com/pytorch/pytorch/issues/86448 # that building with USE_DISTRIBUTED=0 works at all. See https://github.com/pytorch/pytorch/issues/86448
USE_DISTRIBUTED=0 USE_OPENMP=1 MACOSX_DEPLOYMENT_TARGET=11.0 WERROR=1 BUILD_TEST=OFF USE_PYTORCH_METAL=1 python setup.py bdist_wheel --plat-name macosx_11_0_arm64 USE_DISTRIBUTED=0 USE_OPENMP=1 MACOSX_DEPLOYMENT_TARGET=11.0 WERROR=1 BUILD_TEST=OFF USE_PYTORCH_METAL=1 python -m build --wheel --no-isolation -C--build-option=--plat-name=macosx_11_0_arm64
fi fi
if which sccache > /dev/null; then if which sccache > /dev/null; then
print_sccache_stats print_sccache_stats

View File

@ -1415,7 +1415,7 @@ EOF
pip3 install -r requirements.txt pip3 install -r requirements.txt
# shellcheck source=./common-build.sh # shellcheck source=./common-build.sh
source "$(dirname "${BASH_SOURCE[0]}")/common-build.sh" source "$(dirname "${BASH_SOURCE[0]}")/common-build.sh"
python setup.py bdist_wheel --bdist-dir="base_bdist_tmp" --dist-dir="base_dist" python -m build --wheel --no-isolation -C--build-option=--bdist-dir="base_bdist_tmp" --outdir "base_dist"
python -mpip install base_dist/*.whl python -mpip install base_dist/*.whl
echo "::endgroup::" echo "::endgroup::"

View File

@ -70,7 +70,7 @@ sccache --zero-stats
sccache --show-stats sccache --show-stats
# Build the wheel # Build the wheel
python setup.py bdist_wheel python -m build --wheel --no-build-isolation
if ($LASTEXITCODE -ne 0) { exit 1 } if ($LASTEXITCODE -ne 0) { exit 1 }
# Install the wheel locally # Install the wheel locally

View File

@ -130,7 +130,7 @@ if "%USE_CUDA%"=="1" (
:: Print all existing environment variable for debugging :: Print all existing environment variable for debugging
set set
python setup.py bdist_wheel python -m build --wheel --no-isolation
if errorlevel 1 goto fail if errorlevel 1 goto fail
if not errorlevel 0 goto fail if not errorlevel 0 goto fail
sccache --show-stats sccache --show-stats

View File

@ -48,7 +48,7 @@ sccache --zero-stats
sccache --show-stats sccache --show-stats
:: Call PyTorch build script :: Call PyTorch build script
python setup.py bdist_wheel -d "%PYTORCH_FINAL_PACKAGE_DIR%" python -m build --wheel --no-isolation --outdir "%PYTORCH_FINAL_PACKAGE_DIR%"
:: show sccache stats :: show sccache stats
sccache --show-stats sccache --show-stats

View File

@ -28,5 +28,5 @@ start /wait "" python-amd64.exe /quiet InstallAllUsers=1 PrependPath=0 Include_t
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
set "PATH=%CD%\Python\Scripts;%CD%\Python;%PATH%" set "PATH=%CD%\Python\Scripts;%CD%\Python;%PATH%"
%PYTHON_EXEC% -m pip install --upgrade pip setuptools packaging wheel %PYTHON_EXEC% -m pip install --upgrade pip setuptools packaging wheel build
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1

View File

@ -86,7 +86,7 @@ copy /Y "%LIBTORCH_PREFIX%-%PYTORCH_BUILD_VERSION%.zip" "%PYTORCH_FINAL_PACKAGE_
goto build_end goto build_end
:pytorch :pytorch
%PYTHON_EXEC% setup.py bdist_wheel -d "%PYTORCH_FINAL_PACKAGE_DIR%" %PYTHON_EXEC% -m build --wheel --no-isolation --outdir "%PYTORCH_FINAL_PACKAGE_DIR%"
:build_end :build_end
IF ERRORLEVEL 1 exit /b 1 IF ERRORLEVEL 1 exit /b 1

View File

@ -18,7 +18,7 @@ if "%DESIRED_PYTHON%" == "3.9" %PYTHON_EXEC% -m pip install numpy==2.0.2 cmake
%PYTHON_EXEC% -m pip install pyyaml %PYTHON_EXEC% -m pip install pyyaml
%PYTHON_EXEC% -m pip install mkl-include mkl-static %PYTHON_EXEC% -m pip install mkl-include mkl-static
%PYTHON_EXEC% -m pip install boto3 ninja typing_extensions setuptools==72.1.0 %PYTHON_EXEC% -m pip install boto3 requests ninja typing_extensions setuptools==72.1.0
where cmake.exe where cmake.exe

View File

@ -143,7 +143,8 @@ case $desired_python in
RENAME_WHEEL=false RENAME_WHEEL=false
;; ;;
3.13t) 3.13t)
echo "Using 3.13 deps" echo "Using 3.13t deps"
mac_version='macosx-11.0-arm64'
NUMPY_PINNED_VERSION="==2.1.0" NUMPY_PINNED_VERSION="==2.1.0"
RENAME_WHEEL=false RENAME_WHEEL=false
;; ;;
@ -185,11 +186,11 @@ export USE_QNNPACK=OFF
export BUILD_TEST=OFF export BUILD_TEST=OFF
pushd "$pytorch_rootdir" pushd "$pytorch_rootdir"
echo "Calling setup.py bdist_wheel at $(date)" echo "Calling -m build --wheel --no-isolation at $(date)"
_PYTHON_HOST_PLATFORM=${mac_version} ARCHFLAGS="-arch arm64" python setup.py bdist_wheel -d "$whl_tmp_dir" --plat-name "${mac_version//[-.]/_}" _PYTHON_HOST_PLATFORM=${mac_version} ARCHFLAGS="-arch arm64" python -m build --wheel --no-isolation --outdir "$whl_tmp_dir" -C--plat-name="${mac_version//[-.]/_}"
echo "Finished setup.py bdist_wheel at $(date)" echo "Finished -m build --wheel --no-isolation at $(date)"
if [[ $package_type != 'libtorch' ]]; then if [[ $package_type != 'libtorch' ]]; then
echo "delocating wheel dependencies" echo "delocating wheel dependencies"

View File

@ -1,4 +1,5 @@
boto3==1.35.42 boto3==1.35.42
build==1.2.2.post1
cmake==3.27.* cmake==3.27.*
expecttest==0.3.0 expecttest==0.3.0
fbscribelogger==0.1.7 fbscribelogger==0.1.7

View File

@ -4,7 +4,7 @@
requires = [ requires = [
# 70.1.0: min version for integrated bdist_wheel command from wheel package # 70.1.0: min version for integrated bdist_wheel command from wheel package
# 77.0.0: min version for SPDX expression support for project.license # 77.0.0: min version for SPDX expression support for project.license
"setuptools>=70.1.0,<80.0", "setuptools>=70.1.0",
"cmake>=3.27", "cmake>=3.27",
"ninja", "ninja",
"numpy", "numpy",

View File

@ -1,5 +1,5 @@
# Build System requirements # Build System requirements
setuptools>=70.1.0,<80.0 # setuptools develop deprecated on 80.0 setuptools>=70.1.0
cmake>=3.27 cmake>=3.27
ninja ninja
numpy numpy

View File

@ -28,7 +28,7 @@ class TestPythonAgnostic(TestCase):
shutil.rmtree(cls.dist_dir) shutil.rmtree(cls.dist_dir)
# Build the wheel # Build the wheel
wheel_cmd = [sys.executable, "setup.py", "bdist_wheel"] wheel_cmd = [sys.executable, "-m", "build", "--wheel", "--no-isolation"]
return_code = shell(wheel_cmd, cwd=cls.extension_root, env=os.environ) return_code = shell(wheel_cmd, cwd=cls.extension_root, env=os.environ)
if return_code != 0: if return_code != 0:
raise RuntimeError("python_agnostic bdist_wheel failed to build") raise RuntimeError("python_agnostic bdist_wheel failed to build")
@ -39,7 +39,7 @@ class TestPythonAgnostic(TestCase):
) )
@unittest.skipIf(not IS_LINUX, "test requires linux tools ldd and nm") @unittest.skipIf(not IS_LINUX, "test requires linux tools ldd and nm")
def test_extension_is_python_agnostic(self, device): def test_extension_is_python_agnostic(self, device):
# For this test, run_test.py will call `python setup.py bdist_wheel` in the # For this test, run_test.py will call `python -m build --wheel --no-isolation` in the
# cpp_extensions/python_agnostic_extension folder, where the extension and # cpp_extensions/python_agnostic_extension folder, where the extension and
# setup calls specify py_limited_api to `True`. To approximate that the # setup calls specify py_limited_api to `True`. To approximate that the
# extension is indeed python agnostic, we test # extension is indeed python agnostic, we test

View File

@ -837,7 +837,7 @@ def _test_cpp_extensions_aot(test_directory, options, use_ninja):
"--root", "--root",
"./install", "./install",
] ]
wheel_cmd = [sys.executable, "-m", "pip", "wheel", ".", "-w", "./dist"] wheel_cmd = [sys.executable, "-m", "build", "--wheel", "--no-isolation"]
return_code = shell(install_cmd, cwd=cpp_extensions_test_dir, env=shell_env) return_code = shell(install_cmd, cwd=cpp_extensions_test_dir, env=shell_env)
if return_code != 0: if return_code != 0:
return return_code return return_code

View File

@ -20,7 +20,6 @@ logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
ROOT_PATH = Path(__file__).absolute().parent.parent.parent ROOT_PATH = Path(__file__).absolute().parent.parent.parent
SETUP_PY_PATH = ROOT_PATH / "setup.py"
REQUIREMENTS_PATH = ROOT_PATH / "requirements.txt" REQUIREMENTS_PATH = ROOT_PATH / "requirements.txt"
PYPROJECT_TOML_PATH = ROOT_PATH / "pyproject.toml" PYPROJECT_TOML_PATH = ROOT_PATH / "pyproject.toml"
@ -143,18 +142,27 @@ class Builder:
def __init__(self, interpreter: str) -> None: def __init__(self, interpreter: str) -> None:
self.interpreter = interpreter self.interpreter = interpreter
def setup_py(self, cmd_args: list[str]) -> bool: def build_wheel(self, destination: str) -> bool:
return (
run_cmd([self.interpreter, str(SETUP_PY_PATH), *cmd_args]).returncode == 0
)
def bdist_wheel(self, destination: str) -> bool:
logger.info("Running bdist_wheel -d %s", destination) logger.info("Running bdist_wheel -d %s", destination)
return self.setup_py(["bdist_wheel", "-d", destination]) return (
run_cmd(
[
self.interpreter,
"-m",
"build",
"--wheel",
"--no-isolation",
"--outdir",
destination,
str(ROOT_PATH),
]
).returncode
== 0
)
def clean(self) -> bool: def clean(self) -> bool:
logger.info("Running clean") logger.info("Running clean")
return self.setup_py(["clean"]) return run_cmd([self.interpreter, "setup.py", "clean"]).returncode == 0
def install_requirements(self) -> None: def install_requirements(self) -> None:
logger.info("Installing requirements") logger.info("Installing requirements")
@ -234,7 +242,7 @@ def main() -> None:
start_time = time.time() start_time = time.time()
builder.bdist_wheel(args.destination) builder.build_wheel(args.destination)
end_time = time.time() end_time = time.time()