xref: /aosp_15_r20/external/executorch/install_requirements.py (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
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