# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. import glob import os import platform import re import shutil import subprocess import sys # Before doing anything, cd to the directory containing this script. os.chdir(os.path.dirname(os.path.abspath(__file__))) def python_is_compatible(): # Scrape the version range from pyproject.toml, which should be in the current directory. version_specifier = None with open("pyproject.toml", "r") as file: for line in file: if line.startswith("requires-python"): match = re.search(r'"([^"]*)"', line) if match: version_specifier = match.group(1) break if not version_specifier: print( "WARNING: Skipping python version check: version range not found", file=sys.stderr, ) return False # Install the packaging module if necessary. try: import packaging except ImportError: subprocess.run( [sys.executable, "-m", "pip", "install", "packaging"], check=True ) # Compare the current python version to the range in version_specifier. Exits # with status 1 if the version is not compatible, or with status 0 if the # version is compatible or the logic itself fails. try: import packaging.specifiers import packaging.version python_version = packaging.version.parse(platform.python_version()) version_range = packaging.specifiers.SpecifierSet(version_specifier) if python_version not in version_range: print( f'ERROR: ExecuTorch does not support python version {python_version}: must satisfy "{version_specifier}"', file=sys.stderr, ) return False except Exception as e: print(f"WARNING: Skipping python version check: {e}", file=sys.stderr) return True if not python_is_compatible(): sys.exit(1) # Parse options. EXECUTORCH_BUILD_PYBIND = "OFF" CMAKE_ARGS = os.getenv("CMAKE_ARGS", "") CMAKE_BUILD_ARGS = os.getenv("CMAKE_BUILD_ARGS", "") USE_PYTORCH_NIGHTLY = True for arg in sys.argv[1:]: if arg == "--pybind": EXECUTORCH_BUILD_PYBIND = "ON" elif arg in ["coreml", "mps", "xnnpack"]: if EXECUTORCH_BUILD_PYBIND == "ON": arg_upper = arg.upper() CMAKE_ARGS += f" -DEXECUTORCH_BUILD_{arg_upper}=ON" else: print(f"Error: {arg} must follow --pybind") sys.exit(1) elif arg == "--clean": print("Cleaning build artifacts...") print("Cleaning pip-out/...") shutil.rmtree("pip-out/", ignore_errors=True) dirs = glob.glob("cmake-out*/") for d in dirs: print(f"Cleaning {d}...") shutil.rmtree(d, ignore_errors=True) print("Done cleaning build artifacts.") sys.exit(0) elif arg == "--use-pt-pinned-commit": # This option is used in CI to make sure that PyTorch build from the pinned commit # is used instead of nightly. CI jobs wouldn't be able to catch regression from the # latest PT commit otherwise USE_PYTORCH_NIGHTLY = False else: print(f"Error: Unknown option {arg}") sys.exit(1) # Use ClangCL on Windows. # ClangCL is an alias to Clang that configures it to work in an MSVC-compatible # mode. Using it on Windows to avoid compiler compatibility issues for MSVC. if os.name == "nt": CMAKE_ARGS += " -T ClangCL" # Since ExecuTorch often uses main-branch features of pytorch, only the nightly # pip versions will have the required features. # # NOTE: If a newly-fetched version of the executorch repo changes the value of # NIGHTLY_VERSION, you should re-run this script to install the necessary # package versions. NIGHTLY_VERSION = "dev20241112" # The pip repository that hosts nightly torch packages. TORCH_URL = "https://download.pytorch.org/whl/test/cpu" # pip packages needed by exir. EXIR_REQUIREMENTS = [ # Setting USE_PYTORCH_NIGHTLY to false to test the pinned PyTorch commit. Note # that we don't need to set any version number there because they have already # been installed on CI before this step, so pip won't reinstall them f"torch==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torch", ( f"torchvision==0.20.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torchvision" ), # For testing. "typing-extensions", ] # pip packages needed to run examples. # TODO: Make each example publish its own requirements.txt EXAMPLES_REQUIREMENTS = [ "timm==1.0.7", f"torchaudio==2.5.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torchaudio", "torchsr==1.0.4", "transformers==4.46.1", ] # pip packages needed for development. DEVEL_REQUIREMENTS = [ "cmake", # For building binary targets. "pip>=23", # For building the pip package. "pyyaml", # Imported by the kernel codegen tools. "setuptools>=63", # For building the pip package. "tomli", # Imported by extract_sources.py when using python < 3.11. "wheel", # For building the pip package archive. "zstd", # Imported by resolve_buck.py. ] # Assemble the list of requirements to actually install. # TODO: Add options for reducing the number of requirements. REQUIREMENTS_TO_INSTALL = EXIR_REQUIREMENTS + DEVEL_REQUIREMENTS + EXAMPLES_REQUIREMENTS # Install the requirements. `--extra-index-url` tells pip to look for package # versions on the provided URL if they aren't available on the default URL. subprocess.run( [ sys.executable, "-m", "pip", "install", *REQUIREMENTS_TO_INSTALL, "--extra-index-url", TORCH_URL, ], check=True, ) # # Install executorch pip package. This also makes `flatc` available on the path. # The --extra-index-url may be necessary if pyproject.toml has a dependency on a # pre-release or nightly version of a torch package. # # Set environment variables os.environ["EXECUTORCH_BUILD_PYBIND"] = EXECUTORCH_BUILD_PYBIND os.environ["CMAKE_ARGS"] = CMAKE_ARGS os.environ["CMAKE_BUILD_ARGS"] = CMAKE_BUILD_ARGS # Run the pip install command subprocess.run( [ sys.executable, "-m", "pip", "install", ".", "--no-build-isolation", "-v", "--extra-index-url", TORCH_URL, ], check=True, )