mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
See also: - #156029 - #156027 Pull Request resolved: https://github.com/pytorch/pytorch/pull/156045 Approved by: https://github.com/ezyang ghstack dependencies: #156040, #156041
110 lines
3.2 KiB
Python
110 lines
3.2 KiB
Python
"""Script to build split pytorch wheels
|
|
|
|
What is split build / why is it important?
|
|
> Split build is splitting the PyTorch build into a libtorch &
|
|
> PyTorch python frontend package. This allows us to to publish
|
|
> both as separate packages and opens up our ability to have users
|
|
> install different libtorch backends per their PyTorch frontend
|
|
>
|
|
> Example: opening up the door to things like:
|
|
> pip install torch[cuda]
|
|
> pip install torch[rocm]
|
|
> pip install torch[cpu]
|
|
> etc.
|
|
|
|
Why does this exist?
|
|
> Currently our split build requires you to invoke setup.py twice
|
|
> Which ends up complicating the build process and adds some level
|
|
> of complexity to our setup.py / build invocation for split builds.
|
|
> Ideally this script will eventually not be needed but for
|
|
> development purposes we should have an easy way to invoke this script
|
|
"""
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.DEBUG)
|
|
|
|
|
|
# NOTE: This will need to be updated if this script is ever moved
|
|
ROOT_PATH = Path(__file__).absolute().parents[2]
|
|
SETUP_PY_PATH = ROOT_PATH / "setup.py"
|
|
|
|
|
|
def requirements_installed() -> bool:
|
|
try:
|
|
import setuptools # type: ignore[import-untyped] # noqa: F401
|
|
|
|
return True
|
|
except ImportError:
|
|
logger.error(
|
|
"Requirements not installed, run the following command to install:"
|
|
)
|
|
logger.error(
|
|
" > %s -m pip install -r %s/requirements.txt", sys.executable, ROOT_PATH
|
|
)
|
|
return False
|
|
|
|
|
|
def setup_py(cmd_args: list[str], extra_env: Optional[dict[str, str]] = None) -> None:
|
|
if extra_env is None:
|
|
extra_env = {}
|
|
cmd = [sys.executable, str(SETUP_PY_PATH), *cmd_args]
|
|
logger.debug("+ %s", " ".join(cmd))
|
|
subprocess.run(
|
|
cmd,
|
|
# Give the parent environment to the subprocess
|
|
env={**os.environ, **extra_env},
|
|
check=True,
|
|
)
|
|
|
|
|
|
def split_build(cmd: str) -> None:
|
|
logger.info("Running %s for libtorch wheel", cmd)
|
|
setup_py(
|
|
[cmd],
|
|
extra_env={"BUILD_LIBTORCH_WHL": "1", "BUILD_PYTHON_ONLY": "0"},
|
|
)
|
|
logger.info("Running %s for torch wheel", cmd)
|
|
# NOTE: Passing CMAKE_FRESH=1 is necessary here since the torch frontend has it's
|
|
# own cmake files that it needs to generate
|
|
setup_py(
|
|
[cmd],
|
|
extra_env={
|
|
"BUILD_LIBTORCH_WHL": "0",
|
|
"BUILD_PYTHON_ONLY": "1",
|
|
"CMAKE_FRESH": "1",
|
|
},
|
|
)
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser()
|
|
command_subparser = parser.add_subparsers(dest="command")
|
|
# Ideally these should mirror setuptools commands if we need support here for that
|
|
command_subparser.add_parser("install")
|
|
command_subparser.add_parser("bdist_wheel")
|
|
command_subparser.add_parser("develop")
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
if not requirements_installed():
|
|
sys.exit(1)
|
|
split_build(args.command)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|