1# Copyright (c) Meta Platforms, Inc. and affiliates. 2# All rights reserved. 3# 4# This source code is licensed under the BSD-style license found in the 5# LICENSE file in the root directory of this source tree. 6 7 8import glob 9import os 10import platform 11import re 12import shutil 13import subprocess 14import sys 15 16# Before doing anything, cd to the directory containing this script. 17os.chdir(os.path.dirname(os.path.abspath(__file__))) 18 19 20def python_is_compatible(): 21 # Scrape the version range from pyproject.toml, which should be in the current directory. 22 version_specifier = None 23 with open("pyproject.toml", "r") as file: 24 for line in file: 25 if line.startswith("requires-python"): 26 match = re.search(r'"([^"]*)"', line) 27 if match: 28 version_specifier = match.group(1) 29 break 30 31 if not version_specifier: 32 print( 33 "WARNING: Skipping python version check: version range not found", 34 file=sys.stderr, 35 ) 36 return False 37 38 # Install the packaging module if necessary. 39 try: 40 import packaging 41 except ImportError: 42 subprocess.run( 43 [sys.executable, "-m", "pip", "install", "packaging"], check=True 44 ) 45 # Compare the current python version to the range in version_specifier. Exits 46 # with status 1 if the version is not compatible, or with status 0 if the 47 # version is compatible or the logic itself fails. 48 try: 49 import packaging.specifiers 50 import packaging.version 51 52 python_version = packaging.version.parse(platform.python_version()) 53 version_range = packaging.specifiers.SpecifierSet(version_specifier) 54 if python_version not in version_range: 55 print( 56 f'ERROR: ExecuTorch does not support python version {python_version}: must satisfy "{version_specifier}"', 57 file=sys.stderr, 58 ) 59 return False 60 except Exception as e: 61 print(f"WARNING: Skipping python version check: {e}", file=sys.stderr) 62 return True 63 64 65if not python_is_compatible(): 66 sys.exit(1) 67 68# Parse options. 69EXECUTORCH_BUILD_PYBIND = "OFF" 70CMAKE_ARGS = os.getenv("CMAKE_ARGS", "") 71CMAKE_BUILD_ARGS = os.getenv("CMAKE_BUILD_ARGS", "") 72USE_PYTORCH_NIGHTLY = True 73 74for arg in sys.argv[1:]: 75 if arg == "--pybind": 76 EXECUTORCH_BUILD_PYBIND = "ON" 77 elif arg in ["coreml", "mps", "xnnpack"]: 78 if EXECUTORCH_BUILD_PYBIND == "ON": 79 arg_upper = arg.upper() 80 CMAKE_ARGS += f" -DEXECUTORCH_BUILD_{arg_upper}=ON" 81 else: 82 print(f"Error: {arg} must follow --pybind") 83 sys.exit(1) 84 elif arg == "--clean": 85 print("Cleaning build artifacts...") 86 print("Cleaning pip-out/...") 87 shutil.rmtree("pip-out/", ignore_errors=True) 88 dirs = glob.glob("cmake-out*/") 89 for d in dirs: 90 print(f"Cleaning {d}...") 91 shutil.rmtree(d, ignore_errors=True) 92 print("Done cleaning build artifacts.") 93 sys.exit(0) 94 elif arg == "--use-pt-pinned-commit": 95 # This option is used in CI to make sure that PyTorch build from the pinned commit 96 # is used instead of nightly. CI jobs wouldn't be able to catch regression from the 97 # latest PT commit otherwise 98 USE_PYTORCH_NIGHTLY = False 99 else: 100 print(f"Error: Unknown option {arg}") 101 sys.exit(1) 102 103# Use ClangCL on Windows. 104# ClangCL is an alias to Clang that configures it to work in an MSVC-compatible 105# mode. Using it on Windows to avoid compiler compatibility issues for MSVC. 106if os.name == "nt": 107 CMAKE_ARGS += " -T ClangCL" 108 109# Since ExecuTorch often uses main-branch features of pytorch, only the nightly 110# pip versions will have the required features. 111# 112# NOTE: If a newly-fetched version of the executorch repo changes the value of 113# NIGHTLY_VERSION, you should re-run this script to install the necessary 114# package versions. 115NIGHTLY_VERSION = "dev20241112" 116 117# The pip repository that hosts nightly torch packages. 118TORCH_URL = "https://download.pytorch.org/whl/test/cpu" 119 120# pip packages needed by exir. 121EXIR_REQUIREMENTS = [ 122 # Setting USE_PYTORCH_NIGHTLY to false to test the pinned PyTorch commit. Note 123 # that we don't need to set any version number there because they have already 124 # been installed on CI before this step, so pip won't reinstall them 125 f"torch==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torch", 126 ( 127 f"torchvision==0.20.0.{NIGHTLY_VERSION}" 128 if USE_PYTORCH_NIGHTLY 129 else "torchvision" 130 ), # For testing. 131 "typing-extensions", 132] 133 134# pip packages needed to run examples. 135# TODO: Make each example publish its own requirements.txt 136EXAMPLES_REQUIREMENTS = [ 137 "timm==1.0.7", 138 f"torchaudio==2.5.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torchaudio", 139 "torchsr==1.0.4", 140 "transformers==4.46.1", 141] 142 143# pip packages needed for development. 144DEVEL_REQUIREMENTS = [ 145 "cmake", # For building binary targets. 146 "pip>=23", # For building the pip package. 147 "pyyaml", # Imported by the kernel codegen tools. 148 "setuptools>=63", # For building the pip package. 149 "tomli", # Imported by extract_sources.py when using python < 3.11. 150 "wheel", # For building the pip package archive. 151 "zstd", # Imported by resolve_buck.py. 152] 153 154# Assemble the list of requirements to actually install. 155# TODO: Add options for reducing the number of requirements. 156REQUIREMENTS_TO_INSTALL = EXIR_REQUIREMENTS + DEVEL_REQUIREMENTS + EXAMPLES_REQUIREMENTS 157 158# Install the requirements. `--extra-index-url` tells pip to look for package 159# versions on the provided URL if they aren't available on the default URL. 160subprocess.run( 161 [ 162 sys.executable, 163 "-m", 164 "pip", 165 "install", 166 *REQUIREMENTS_TO_INSTALL, 167 "--extra-index-url", 168 TORCH_URL, 169 ], 170 check=True, 171) 172 173# 174# Install executorch pip package. This also makes `flatc` available on the path. 175# The --extra-index-url may be necessary if pyproject.toml has a dependency on a 176# pre-release or nightly version of a torch package. 177# 178 179# Set environment variables 180os.environ["EXECUTORCH_BUILD_PYBIND"] = EXECUTORCH_BUILD_PYBIND 181os.environ["CMAKE_ARGS"] = CMAKE_ARGS 182os.environ["CMAKE_BUILD_ARGS"] = CMAKE_BUILD_ARGS 183 184# Run the pip install command 185subprocess.run( 186 [ 187 sys.executable, 188 "-m", 189 "pip", 190 "install", 191 ".", 192 "--no-build-isolation", 193 "-v", 194 "--extra-index-url", 195 TORCH_URL, 196 ], 197 check=True, 198) 199