| 
6 | 6 | # LICENSE file in the root directory of this source tree.  | 
7 | 7 | 
 
  | 
8 | 8 | 
 
  | 
 | 9 | +import argparse  | 
9 | 10 | import glob  | 
 | 11 | +import itertools  | 
10 | 12 | import os  | 
11 | 13 | import platform  | 
12 | 14 | import re  | 
@@ -63,174 +65,201 @@ def python_is_compatible():  | 
63 | 65 |     return True  | 
64 | 66 | 
 
  | 
65 | 67 | 
 
  | 
66 |  | -if not python_is_compatible():  | 
67 |  | -    sys.exit(1)  | 
 | 68 | +def clean():  | 
 | 69 | +    print("Cleaning build artifacts...")  | 
 | 70 | +    print("Cleaning pip-out/...")  | 
 | 71 | +    shutil.rmtree("pip-out/", ignore_errors=True)  | 
 | 72 | +    dirs = glob.glob("cmake-out*/") + glob.glob("cmake-android-out/")  | 
 | 73 | +    for d in dirs:  | 
 | 74 | +        print(f"Cleaning {d}...")  | 
 | 75 | +        shutil.rmtree(d, ignore_errors=True)  | 
 | 76 | +    print("Done cleaning build artifacts.")  | 
68 | 77 | 
 
  | 
69 |  | -# Parse options.  | 
70 | 78 | 
 
  | 
71 |  | -EXECUTORCH_BUILD_PYBIND = ""  | 
72 |  | -CMAKE_ARGS = os.getenv("CMAKE_ARGS", "")  | 
73 |  | -CMAKE_BUILD_ARGS = os.getenv("CMAKE_BUILD_ARGS", "")  | 
74 |  | -USE_PYTORCH_NIGHTLY = True  | 
 | 79 | +VALID_PYBINDS = ["coreml", "mps", "xnnpack"]  | 
75 | 80 | 
 
  | 
76 |  | -args = sys.argv[1:]  | 
77 |  | -for arg in args:  | 
78 |  | -    if arg == "--pybind":  | 
79 |  | -        pass  | 
80 |  | -    elif arg in ["coreml", "mps", "xnnpack"]:  | 
81 |  | -        if "--pybind" in args:  | 
82 |  | -            arg_upper = arg.upper()  | 
83 |  | -            EXECUTORCH_BUILD_PYBIND = "ON"  | 
84 |  | -            CMAKE_ARGS += f" -DEXECUTORCH_BUILD_{arg_upper}=ON"  | 
85 |  | -        else:  | 
86 |  | -            print(f"Error: {arg} must follow --pybind")  | 
87 |  | -            sys.exit(1)  | 
88 |  | -    elif arg == "off":  | 
89 |  | -        if "--pybind" in args:  | 
90 |  | -            if EXECUTORCH_BUILD_PYBIND == "ON":  | 
91 |  | -                print("Cannot turnoff pybind option as it is already set.")  | 
92 |  | -                sys.exit(1)  | 
 | 81 | + | 
 | 82 | +def main(args):  | 
 | 83 | +    if not python_is_compatible():  | 
 | 84 | +        sys.exit(1)  | 
 | 85 | + | 
 | 86 | +    # Parse options.  | 
 | 87 | + | 
 | 88 | +    EXECUTORCH_BUILD_PYBIND = ""  | 
 | 89 | +    CMAKE_ARGS = os.getenv("CMAKE_ARGS", "")  | 
 | 90 | +    CMAKE_BUILD_ARGS = os.getenv("CMAKE_BUILD_ARGS", "")  | 
 | 91 | +    USE_PYTORCH_NIGHTLY = True  | 
 | 92 | + | 
 | 93 | +    parser = argparse.ArgumentParser()  | 
 | 94 | +    parser.add_argument(  | 
 | 95 | +        "--pybind",  | 
 | 96 | +        action="append",  | 
 | 97 | +        nargs="+",  | 
 | 98 | +        help="one or more of coreml/mps/xnnpack, or off",  | 
 | 99 | +    )  | 
 | 100 | +    parser.add_argument(  | 
 | 101 | +        "--clean",  | 
 | 102 | +        action="store_true",  | 
 | 103 | +        help="clean build artifacts and pip-out instead of installing",  | 
 | 104 | +    )  | 
 | 105 | +    parser.add_argument(  | 
 | 106 | +        "--use-pt-pinned-commit",  | 
 | 107 | +        action="store_true",  | 
 | 108 | +        help="build from the pinned PyTorch commit instead of nightly",  | 
 | 109 | +    )  | 
 | 110 | +    args = parser.parse_args(args)  | 
 | 111 | + | 
 | 112 | +    if args.clean:  | 
 | 113 | +        clean()  | 
 | 114 | +        return  | 
 | 115 | + | 
 | 116 | +    if args.pybind:  | 
 | 117 | +        # Flatten list of lists.  | 
 | 118 | +        args.pybind = list(itertools.chain(*args.pybind))  | 
 | 119 | +        if "off" in args.pybind:  | 
 | 120 | +            if len(args.pybind) != 1:  | 
 | 121 | +                raise Exception(  | 
 | 122 | +                    f"Cannot combine `off` with other pybinds: {args.pybind}"  | 
 | 123 | +                )  | 
93 | 124 |             EXECUTORCH_BUILD_PYBIND = "OFF"  | 
94 | 125 |         else:  | 
95 |  | -            print(f"Error: {arg} must follow --pybind")  | 
96 |  | -            sys.exit(1)  | 
97 |  | - | 
98 |  | -    elif arg == "--clean":  | 
99 |  | -        print("Cleaning build artifacts...")  | 
100 |  | -        print("Cleaning pip-out/...")  | 
101 |  | -        shutil.rmtree("pip-out/", ignore_errors=True)  | 
102 |  | -        dirs = glob.glob("cmake-out*/") + glob.glob("cmake-android-out/")  | 
103 |  | -        for d in dirs:  | 
104 |  | -            print(f"Cleaning {d}...")  | 
105 |  | -            shutil.rmtree(d, ignore_errors=True)  | 
106 |  | -        print("Done cleaning build artifacts.")  | 
107 |  | -        sys.exit(0)  | 
108 |  | -    elif arg == "--use-pt-pinned-commit":  | 
 | 126 | +            for pybind_arg in args.pybind:  | 
 | 127 | +                if pybind_arg not in VALID_PYBINDS:  | 
 | 128 | +                    raise Exception(  | 
 | 129 | +                        f"Unrecognized pybind argument {pybind_arg}; valid options are: {', '.join(VALID_PYBINDS)}"  | 
 | 130 | +                    )  | 
 | 131 | +                EXECUTORCH_BUILD_PYBIND = "ON"  | 
 | 132 | +                CMAKE_ARGS += f" -DEXECUTORCH_BUILD_{pybind_arg.upper()}=ON"  | 
 | 133 | + | 
 | 134 | +    if args.use_pt_pinned_commit:  | 
109 | 135 |         # This option is used in CI to make sure that PyTorch build from the pinned commit  | 
110 | 136 |         # is used instead of nightly. CI jobs wouldn't be able to catch regression from the  | 
111 | 137 |         # latest PT commit otherwise  | 
112 | 138 |         USE_PYTORCH_NIGHTLY = False  | 
113 |  | -    else:  | 
114 |  | -        print(f"Error: Unknown option {arg}")  | 
115 |  | -        sys.exit(1)  | 
116 | 139 | 
 
  | 
117 |  | -# If --pybind is not set explicitly for backends (e.g., --pybind xnnpack)  | 
118 |  | -# or is not turned off explicitly (--pybind off)  | 
119 |  | -# then install XNNPACK by default.  | 
120 |  | -if EXECUTORCH_BUILD_PYBIND == "":  | 
121 |  | -    EXECUTORCH_BUILD_PYBIND = "ON"  | 
122 |  | -    CMAKE_ARGS += " -DEXECUTORCH_BUILD_XNNPACK=ON"  | 
123 |  | - | 
124 |  | -# Use ClangCL on Windows.  | 
125 |  | -# ClangCL is an alias to Clang that configures it to work in an MSVC-compatible  | 
126 |  | -# mode. Using it on Windows to avoid compiler compatibility issues for MSVC.  | 
127 |  | -if os.name == "nt":  | 
128 |  | -    CMAKE_ARGS += " -T ClangCL"  | 
129 |  | - | 
130 |  | -# Since ExecuTorch often uses main-branch features of pytorch, only the nightly  | 
131 |  | -# pip versions will have the required features.  | 
132 |  | -#  | 
133 |  | -# NOTE: If a newly-fetched version of the executorch repo changes the value of  | 
134 |  | -# NIGHTLY_VERSION, you should re-run this script to install the necessary  | 
135 |  | -# package versions.  | 
136 |  | -NIGHTLY_VERSION = "dev20250104"  | 
137 |  | - | 
138 |  | -# The pip repository that hosts nightly torch packages.  | 
139 |  | -TORCH_NIGHTLY_URL = "https://download.pytorch.org/whl/nightly/cpu"  | 
140 |  | - | 
141 |  | -# pip packages needed by exir.  | 
142 |  | -EXIR_REQUIREMENTS = [  | 
143 |  | -    # Setting USE_PYTORCH_NIGHTLY to false to test the pinned PyTorch commit. Note  | 
144 |  | -    # that we don't need to set any version number there because they have already  | 
145 |  | -    # been installed on CI before this step, so pip won't reinstall them  | 
146 |  | -    f"torch==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torch",  | 
147 |  | -    (  | 
148 |  | -        f"torchvision==0.22.0.{NIGHTLY_VERSION}"  | 
149 |  | -        if USE_PYTORCH_NIGHTLY  | 
150 |  | -        else "torchvision"  | 
151 |  | -    ),  # For testing.  | 
152 |  | -    "typing-extensions",  | 
153 |  | -]  | 
154 |  | - | 
155 |  | -# pip packages needed to run examples.  | 
156 |  | -# TODO: Make each example publish its own requirements.txt  | 
157 |  | -EXAMPLES_REQUIREMENTS = [  | 
158 |  | -    "timm==1.0.7",  | 
159 |  | -    f"torchaudio==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torchaudio",  | 
160 |  | -    "torchsr==1.0.4",  | 
161 |  | -    "transformers==4.47.1",  | 
162 |  | -]  | 
163 |  | - | 
164 |  | -# pip packages needed for development.  | 
165 |  | -DEVEL_REQUIREMENTS = [  | 
166 |  | -    "cmake",  # For building binary targets.  | 
167 |  | -    "pip>=23",  # For building the pip package.  | 
168 |  | -    "pyyaml",  # Imported by the kernel codegen tools.  | 
169 |  | -    "setuptools>=63",  # For building the pip package.  | 
170 |  | -    "tomli",  # Imported by extract_sources.py when using python < 3.11.  | 
171 |  | -    "wheel",  # For building the pip package archive.  | 
172 |  | -    "zstd",  # Imported by resolve_buck.py.  | 
173 |  | -]  | 
174 |  | - | 
175 |  | -# Assemble the list of requirements to actually install.  | 
176 |  | -# TODO: Add options for reducing the number of requirements.  | 
177 |  | -REQUIREMENTS_TO_INSTALL = EXIR_REQUIREMENTS + DEVEL_REQUIREMENTS + EXAMPLES_REQUIREMENTS  | 
178 |  | - | 
179 |  | -# Install the requirements. `--extra-index-url` tells pip to look for package  | 
180 |  | -# versions on the provided URL if they aren't available on the default URL.  | 
181 |  | -subprocess.run(  | 
182 |  | -    [  | 
183 |  | -        sys.executable,  | 
184 |  | -        "-m",  | 
185 |  | -        "pip",  | 
186 |  | -        "install",  | 
187 |  | -        *REQUIREMENTS_TO_INSTALL,  | 
188 |  | -        "--extra-index-url",  | 
189 |  | -        TORCH_NIGHTLY_URL,  | 
190 |  | -    ],  | 
191 |  | -    check=True,  | 
192 |  | -)  | 
193 |  | - | 
194 |  | -LOCAL_REQUIREMENTS = [  | 
195 |  | -    "third-party/ao",  # We need the latest kernels for fast iteration, so not relying on pypi.  | 
196 |  | -]  | 
197 |  | - | 
198 |  | -# Install packages directly from local copy instead of pypi.  | 
199 |  | -# This is usually not recommended.  | 
200 |  | -subprocess.run(  | 
201 |  | -    [  | 
202 |  | -        sys.executable,  | 
203 |  | -        "-m",  | 
204 |  | -        "pip",  | 
205 |  | -        "install",  | 
206 |  | -        *LOCAL_REQUIREMENTS,  | 
207 |  | -    ],  | 
208 |  | -    check=True,  | 
209 |  | -)  | 
 | 140 | +    # If --pybind is not set explicitly for backends (e.g., --pybind xnnpack)  | 
 | 141 | +    # or is not turned off explicitly (--pybind off)  | 
 | 142 | +    # then install XNNPACK by default.  | 
 | 143 | +    if EXECUTORCH_BUILD_PYBIND == "":  | 
 | 144 | +        EXECUTORCH_BUILD_PYBIND = "ON"  | 
 | 145 | +        CMAKE_ARGS += " -DEXECUTORCH_BUILD_XNNPACK=ON"  | 
 | 146 | + | 
 | 147 | +    # Use ClangCL on Windows.  | 
 | 148 | +    # ClangCL is an alias to Clang that configures it to work in an MSVC-compatible  | 
 | 149 | +    # mode. Using it on Windows to avoid compiler compatibility issues for MSVC.  | 
 | 150 | +    if os.name == "nt":  | 
 | 151 | +        CMAKE_ARGS += " -T ClangCL"  | 
 | 152 | + | 
 | 153 | +    # Since ExecuTorch often uses main-branch features of pytorch, only the nightly  | 
 | 154 | +    # pip versions will have the required features.  | 
 | 155 | +    #  | 
 | 156 | +    # NOTE: If a newly-fetched version of the executorch repo changes the value of  | 
 | 157 | +    # NIGHTLY_VERSION, you should re-run this script to install the necessary  | 
 | 158 | +    # package versions.  | 
 | 159 | +    NIGHTLY_VERSION = "dev20250104"  | 
 | 160 | + | 
 | 161 | +    # The pip repository that hosts nightly torch packages.  | 
 | 162 | +    TORCH_NIGHTLY_URL = "https://download.pytorch.org/whl/nightly/cpu"  | 
 | 163 | + | 
 | 164 | +    # pip packages needed by exir.  | 
 | 165 | +    EXIR_REQUIREMENTS = [  | 
 | 166 | +        # Setting USE_PYTORCH_NIGHTLY to false to test the pinned PyTorch commit. Note  | 
 | 167 | +        # that we don't need to set any version number there because they have already  | 
 | 168 | +        # been installed on CI before this step, so pip won't reinstall them  | 
 | 169 | +        f"torch==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torch",  | 
 | 170 | +        (  | 
 | 171 | +            f"torchvision==0.22.0.{NIGHTLY_VERSION}"  | 
 | 172 | +            if USE_PYTORCH_NIGHTLY  | 
 | 173 | +            else "torchvision"  | 
 | 174 | +        ),  # For testing.  | 
 | 175 | +        "typing-extensions",  | 
 | 176 | +    ]  | 
 | 177 | + | 
 | 178 | +    # pip packages needed to run examples.  | 
 | 179 | +    # TODO: Make each example publish its own requirements.txt  | 
 | 180 | +    EXAMPLES_REQUIREMENTS = [  | 
 | 181 | +        "timm==1.0.7",  | 
 | 182 | +        f"torchaudio==2.6.0.{NIGHTLY_VERSION}" if USE_PYTORCH_NIGHTLY else "torchaudio",  | 
 | 183 | +        "torchsr==1.0.4",  | 
 | 184 | +        "transformers==4.47.1",  | 
 | 185 | +    ]  | 
 | 186 | + | 
 | 187 | +    # pip packages needed for development.  | 
 | 188 | +    DEVEL_REQUIREMENTS = [  | 
 | 189 | +        "cmake",  # For building binary targets.  | 
 | 190 | +        "pip>=23",  # For building the pip package.  | 
 | 191 | +        "pyyaml",  # Imported by the kernel codegen tools.  | 
 | 192 | +        "setuptools>=63",  # For building the pip package.  | 
 | 193 | +        "tomli",  # Imported by extract_sources.py when using python < 3.11.  | 
 | 194 | +        "wheel",  # For building the pip package archive.  | 
 | 195 | +        "zstd",  # Imported by resolve_buck.py.  | 
 | 196 | +    ]  | 
 | 197 | + | 
 | 198 | +    # Assemble the list of requirements to actually install.  | 
 | 199 | +    # TODO: Add options for reducing the number of requirements.  | 
 | 200 | +    REQUIREMENTS_TO_INSTALL = (  | 
 | 201 | +        EXIR_REQUIREMENTS + DEVEL_REQUIREMENTS + EXAMPLES_REQUIREMENTS  | 
 | 202 | +    )  | 
 | 203 | + | 
 | 204 | +    # Install the requirements. `--extra-index-url` tells pip to look for package  | 
 | 205 | +    # versions on the provided URL if they aren't available on the default URL.  | 
 | 206 | +    subprocess.run(  | 
 | 207 | +        [  | 
 | 208 | +            sys.executable,  | 
 | 209 | +            "-m",  | 
 | 210 | +            "pip",  | 
 | 211 | +            "install",  | 
 | 212 | +            *REQUIREMENTS_TO_INSTALL,  | 
 | 213 | +            "--extra-index-url",  | 
 | 214 | +            TORCH_NIGHTLY_URL,  | 
 | 215 | +        ],  | 
 | 216 | +        check=True,  | 
 | 217 | +    )  | 
 | 218 | + | 
 | 219 | +    LOCAL_REQUIREMENTS = [  | 
 | 220 | +        "third-party/ao",  # We need the latest kernels for fast iteration, so not relying on pypi.  | 
 | 221 | +    ]  | 
 | 222 | + | 
 | 223 | +    # Install packages directly from local copy instead of pypi.  | 
 | 224 | +    # This is usually not recommended.  | 
 | 225 | +    subprocess.run(  | 
 | 226 | +        [  | 
 | 227 | +            sys.executable,  | 
 | 228 | +            "-m",  | 
 | 229 | +            "pip",  | 
 | 230 | +            "install",  | 
 | 231 | +            *LOCAL_REQUIREMENTS,  | 
 | 232 | +        ],  | 
 | 233 | +        check=True,  | 
 | 234 | +    )  | 
 | 235 | + | 
 | 236 | +    #  | 
 | 237 | +    # Install executorch pip package. This also makes `flatc` available on the path.  | 
 | 238 | +    # The --extra-index-url may be necessary if pyproject.toml has a dependency on a  | 
 | 239 | +    # pre-release or nightly version of a torch package.  | 
 | 240 | +    #  | 
 | 241 | + | 
 | 242 | +    # Set environment variables  | 
 | 243 | +    os.environ["EXECUTORCH_BUILD_PYBIND"] = EXECUTORCH_BUILD_PYBIND  | 
 | 244 | +    os.environ["CMAKE_ARGS"] = CMAKE_ARGS  | 
 | 245 | +    os.environ["CMAKE_BUILD_ARGS"] = CMAKE_BUILD_ARGS  | 
 | 246 | + | 
 | 247 | +    # Run the pip install command  | 
 | 248 | +    subprocess.run(  | 
 | 249 | +        [  | 
 | 250 | +            sys.executable,  | 
 | 251 | +            "-m",  | 
 | 252 | +            "pip",  | 
 | 253 | +            "install",  | 
 | 254 | +            ".",  | 
 | 255 | +            "--no-build-isolation",  | 
 | 256 | +            "-v",  | 
 | 257 | +            "--extra-index-url",  | 
 | 258 | +            TORCH_NIGHTLY_URL,  | 
 | 259 | +        ],  | 
 | 260 | +        check=True,  | 
 | 261 | +    )  | 
210 | 262 | 
 
  | 
211 |  | -#  | 
212 |  | -# Install executorch pip package. This also makes `flatc` available on the path.  | 
213 |  | -# The --extra-index-url may be necessary if pyproject.toml has a dependency on a  | 
214 |  | -# pre-release or nightly version of a torch package.  | 
215 |  | -#  | 
216 | 263 | 
 
  | 
217 |  | -# Set environment variables  | 
218 |  | -os.environ["EXECUTORCH_BUILD_PYBIND"] = EXECUTORCH_BUILD_PYBIND  | 
219 |  | -os.environ["CMAKE_ARGS"] = CMAKE_ARGS  | 
220 |  | -os.environ["CMAKE_BUILD_ARGS"] = CMAKE_BUILD_ARGS  | 
221 |  | - | 
222 |  | -# Run the pip install command  | 
223 |  | -subprocess.run(  | 
224 |  | -    [  | 
225 |  | -        sys.executable,  | 
226 |  | -        "-m",  | 
227 |  | -        "pip",  | 
228 |  | -        "install",  | 
229 |  | -        ".",  | 
230 |  | -        "--no-build-isolation",  | 
231 |  | -        "-v",  | 
232 |  | -        "--extra-index-url",  | 
233 |  | -        TORCH_NIGHTLY_URL,  | 
234 |  | -    ],  | 
235 |  | -    check=True,  | 
236 |  | -)  | 
 | 264 | +if __name__ == "__main__":  | 
 | 265 | +    main(sys.argv[1:])  | 
0 commit comments