1*523fa7a6SAndroid Build Coastguard Worker# Copyright (c) Meta Platforms, Inc. and affiliates. 2*523fa7a6SAndroid Build Coastguard Worker# Copyright 2024 Arm Limited and/or its affiliates. 3*523fa7a6SAndroid Build Coastguard Worker# All rights reserved. 4*523fa7a6SAndroid Build Coastguard Worker# 5*523fa7a6SAndroid Build Coastguard Worker# This source code is licensed under the BSD-style license found in the 6*523fa7a6SAndroid Build Coastguard Worker# LICENSE file in the root directory of this source tree. 7*523fa7a6SAndroid Build Coastguard Worker 8*523fa7a6SAndroid Build Coastguard Worker# Part of this code is from pybind11 cmake_example: 9*523fa7a6SAndroid Build Coastguard Worker# https://github.com/pybind/cmake_example/blob/master/setup.py so attach the 10*523fa7a6SAndroid Build Coastguard Worker# license below. 11*523fa7a6SAndroid Build Coastguard Worker 12*523fa7a6SAndroid Build Coastguard Worker# Copyright (c) 2016 The Pybind Development Team, All rights reserved. 13*523fa7a6SAndroid Build Coastguard Worker# 14*523fa7a6SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 15*523fa7a6SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 16*523fa7a6SAndroid Build Coastguard Worker# 17*523fa7a6SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright notice, this 18*523fa7a6SAndroid Build Coastguard Worker# list of conditions and the following disclaimer. 19*523fa7a6SAndroid Build Coastguard Worker# 20*523fa7a6SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright notice, 21*523fa7a6SAndroid Build Coastguard Worker# this list of conditions and the following disclaimer in the documentation 22*523fa7a6SAndroid Build Coastguard Worker# and/or other materials provided with the distribution. 23*523fa7a6SAndroid Build Coastguard Worker# 24*523fa7a6SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the names of its contributors 25*523fa7a6SAndroid Build Coastguard Worker# may be used to endorse or promote products derived from this software 26*523fa7a6SAndroid Build Coastguard Worker# without specific prior written permission. 27*523fa7a6SAndroid Build Coastguard Worker# 28*523fa7a6SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 29*523fa7a6SAndroid Build Coastguard Worker# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30*523fa7a6SAndroid Build Coastguard Worker# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31*523fa7a6SAndroid Build Coastguard Worker# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 32*523fa7a6SAndroid Build Coastguard Worker# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33*523fa7a6SAndroid Build Coastguard Worker# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34*523fa7a6SAndroid Build Coastguard Worker# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35*523fa7a6SAndroid Build Coastguard Worker# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36*523fa7a6SAndroid Build Coastguard Worker# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37*523fa7a6SAndroid Build Coastguard Worker# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38*523fa7a6SAndroid Build Coastguard Worker# 39*523fa7a6SAndroid Build Coastguard Worker# You are under no obligation whatsoever to provide any bug fixes, patches, or 40*523fa7a6SAndroid Build Coastguard Worker# upgrades to the features, functionality or performance of the source code 41*523fa7a6SAndroid Build Coastguard Worker# ("Enhancements") to anyone; however, if you choose to make your Enhancements 42*523fa7a6SAndroid Build Coastguard Worker# available either publicly, or directly to the author of this software, without 43*523fa7a6SAndroid Build Coastguard Worker# imposing a separate written license agreement for such Enhancements, then you 44*523fa7a6SAndroid Build Coastguard Worker# hereby grant the following license: a non-exclusive, royalty-free perpetual 45*523fa7a6SAndroid Build Coastguard Worker# license to install, use, modify, prepare derivative works, incorporate into 46*523fa7a6SAndroid Build Coastguard Worker# other computer software, distribute, and sublicense such enhancements or 47*523fa7a6SAndroid Build Coastguard Worker# derivative works thereof, in binary and source code form. 48*523fa7a6SAndroid Build Coastguard Worker 49*523fa7a6SAndroid Build Coastguard Workerimport contextlib 50*523fa7a6SAndroid Build Coastguard Workerimport os 51*523fa7a6SAndroid Build Coastguard Workerimport platform 52*523fa7a6SAndroid Build Coastguard Workerimport re 53*523fa7a6SAndroid Build Coastguard Workerimport sys 54*523fa7a6SAndroid Build Coastguard Worker 55*523fa7a6SAndroid Build Coastguard Worker# Import this before distutils so that setuptools can intercept the distuils 56*523fa7a6SAndroid Build Coastguard Worker# imports. 57*523fa7a6SAndroid Build Coastguard Workerimport setuptools # noqa: F401 # usort: skip 58*523fa7a6SAndroid Build Coastguard Worker 59*523fa7a6SAndroid Build Coastguard Workerfrom distutils import log 60*523fa7a6SAndroid Build Coastguard Workerfrom distutils.sysconfig import get_python_lib 61*523fa7a6SAndroid Build Coastguard Workerfrom pathlib import Path 62*523fa7a6SAndroid Build Coastguard Workerfrom typing import List, Optional 63*523fa7a6SAndroid Build Coastguard Worker 64*523fa7a6SAndroid Build Coastguard Workerfrom setuptools import Extension, setup 65*523fa7a6SAndroid Build Coastguard Workerfrom setuptools.command.build import build 66*523fa7a6SAndroid Build Coastguard Workerfrom setuptools.command.build_ext import build_ext 67*523fa7a6SAndroid Build Coastguard Workerfrom setuptools.command.build_py import build_py 68*523fa7a6SAndroid Build Coastguard Worker 69*523fa7a6SAndroid Build Coastguard Worker# For information on setuptools Command subclassing see 70*523fa7a6SAndroid Build Coastguard Worker# https://setuptools.pypa.io/en/latest/userguide/extension.html 71*523fa7a6SAndroid Build Coastguard Worker 72*523fa7a6SAndroid Build Coastguard Worker 73*523fa7a6SAndroid Build Coastguard Workerclass ShouldBuild: 74*523fa7a6SAndroid Build Coastguard Worker """Indicates whether to build various components.""" 75*523fa7a6SAndroid Build Coastguard Worker 76*523fa7a6SAndroid Build Coastguard Worker @staticmethod 77*523fa7a6SAndroid Build Coastguard Worker def _is_env_enabled(env_var: str, default: bool = False) -> bool: 78*523fa7a6SAndroid Build Coastguard Worker val = os.environ.get(env_var, None) 79*523fa7a6SAndroid Build Coastguard Worker if val is None: 80*523fa7a6SAndroid Build Coastguard Worker return default 81*523fa7a6SAndroid Build Coastguard Worker if val in ("OFF", "0", ""): 82*523fa7a6SAndroid Build Coastguard Worker return False 83*523fa7a6SAndroid Build Coastguard Worker return True 84*523fa7a6SAndroid Build Coastguard Worker 85*523fa7a6SAndroid Build Coastguard Worker @classmethod 86*523fa7a6SAndroid Build Coastguard Worker def pybindings(cls) -> bool: 87*523fa7a6SAndroid Build Coastguard Worker return cls._is_env_enabled("EXECUTORCH_BUILD_PYBIND", default=False) 88*523fa7a6SAndroid Build Coastguard Worker 89*523fa7a6SAndroid Build Coastguard Worker @classmethod 90*523fa7a6SAndroid Build Coastguard Worker def llama_custom_ops(cls) -> bool: 91*523fa7a6SAndroid Build Coastguard Worker return cls._is_env_enabled("EXECUTORCH_BUILD_KERNELS_CUSTOM_AOT", default=True) 92*523fa7a6SAndroid Build Coastguard Worker 93*523fa7a6SAndroid Build Coastguard Worker @classmethod 94*523fa7a6SAndroid Build Coastguard Worker def flatc(cls) -> bool: 95*523fa7a6SAndroid Build Coastguard Worker return cls._is_env_enabled("EXECUTORCH_BUILD_FLATC", default=True) 96*523fa7a6SAndroid Build Coastguard Worker 97*523fa7a6SAndroid Build Coastguard Worker 98*523fa7a6SAndroid Build Coastguard Workerclass Version: 99*523fa7a6SAndroid Build Coastguard Worker """Static strings that describe the version of the pip package.""" 100*523fa7a6SAndroid Build Coastguard Worker 101*523fa7a6SAndroid Build Coastguard Worker # Cached values returned by the properties. 102*523fa7a6SAndroid Build Coastguard Worker __root_dir_attr: Optional[str] = None 103*523fa7a6SAndroid Build Coastguard Worker __string_attr: Optional[str] = None 104*523fa7a6SAndroid Build Coastguard Worker __git_hash_attr: Optional[str] = None 105*523fa7a6SAndroid Build Coastguard Worker 106*523fa7a6SAndroid Build Coastguard Worker @classmethod 107*523fa7a6SAndroid Build Coastguard Worker def _root_dir(cls) -> str: 108*523fa7a6SAndroid Build Coastguard Worker """The path to the root of the git repo.""" 109*523fa7a6SAndroid Build Coastguard Worker if cls.__root_dir_attr is None: 110*523fa7a6SAndroid Build Coastguard Worker # This setup.py file lives in the root of the repo. 111*523fa7a6SAndroid Build Coastguard Worker cls.__root_dir_attr = str(Path(__file__).parent.resolve()) 112*523fa7a6SAndroid Build Coastguard Worker return str(cls.__root_dir_attr) 113*523fa7a6SAndroid Build Coastguard Worker 114*523fa7a6SAndroid Build Coastguard Worker @classmethod 115*523fa7a6SAndroid Build Coastguard Worker def git_hash(cls) -> Optional[str]: 116*523fa7a6SAndroid Build Coastguard Worker """The current git hash, if known.""" 117*523fa7a6SAndroid Build Coastguard Worker if cls.__git_hash_attr is None: 118*523fa7a6SAndroid Build Coastguard Worker import subprocess 119*523fa7a6SAndroid Build Coastguard Worker 120*523fa7a6SAndroid Build Coastguard Worker try: 121*523fa7a6SAndroid Build Coastguard Worker cls.__git_hash_attr = ( 122*523fa7a6SAndroid Build Coastguard Worker subprocess.check_output( 123*523fa7a6SAndroid Build Coastguard Worker ["git", "rev-parse", "HEAD"], cwd=cls._root_dir() 124*523fa7a6SAndroid Build Coastguard Worker ) 125*523fa7a6SAndroid Build Coastguard Worker .decode("ascii") 126*523fa7a6SAndroid Build Coastguard Worker .strip() 127*523fa7a6SAndroid Build Coastguard Worker ) 128*523fa7a6SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 129*523fa7a6SAndroid Build Coastguard Worker cls.__git_hash_attr = "" # Non-None but empty. 130*523fa7a6SAndroid Build Coastguard Worker # A non-None but empty value indicates that we don't know it. 131*523fa7a6SAndroid Build Coastguard Worker return cls.__git_hash_attr if cls.__git_hash_attr else None 132*523fa7a6SAndroid Build Coastguard Worker 133*523fa7a6SAndroid Build Coastguard Worker @classmethod 134*523fa7a6SAndroid Build Coastguard Worker def string(cls) -> str: 135*523fa7a6SAndroid Build Coastguard Worker """The version string.""" 136*523fa7a6SAndroid Build Coastguard Worker if cls.__string_attr is None: 137*523fa7a6SAndroid Build Coastguard Worker # If set, BUILD_VERSION should override any local version 138*523fa7a6SAndroid Build Coastguard Worker # information. CI will use this to manage, e.g., release vs. nightly 139*523fa7a6SAndroid Build Coastguard Worker # versions. 140*523fa7a6SAndroid Build Coastguard Worker version = os.getenv("BUILD_VERSION", "").strip() 141*523fa7a6SAndroid Build Coastguard Worker if not version: 142*523fa7a6SAndroid Build Coastguard Worker # Otherwise, read the version from a local file and add the git 143*523fa7a6SAndroid Build Coastguard Worker # commit if available. 144*523fa7a6SAndroid Build Coastguard Worker version = ( 145*523fa7a6SAndroid Build Coastguard Worker open(os.path.join(cls._root_dir(), "version.txt")).read().strip() 146*523fa7a6SAndroid Build Coastguard Worker ) 147*523fa7a6SAndroid Build Coastguard Worker if cls.git_hash(): 148*523fa7a6SAndroid Build Coastguard Worker version += "+" + cls.git_hash()[:7] 149*523fa7a6SAndroid Build Coastguard Worker cls.__string_attr = version 150*523fa7a6SAndroid Build Coastguard Worker return cls.__string_attr 151*523fa7a6SAndroid Build Coastguard Worker 152*523fa7a6SAndroid Build Coastguard Worker @classmethod 153*523fa7a6SAndroid Build Coastguard Worker def write_to_python_file(cls, path: str) -> None: 154*523fa7a6SAndroid Build Coastguard Worker """Creates a file similar to PyTorch core's `torch/version.py`.""" 155*523fa7a6SAndroid Build Coastguard Worker lines = [ 156*523fa7a6SAndroid Build Coastguard Worker "from typing import Optional", 157*523fa7a6SAndroid Build Coastguard Worker '__all__ = ["__version__", "git_version"]', 158*523fa7a6SAndroid Build Coastguard Worker f'__version__ = "{cls.string()}"', 159*523fa7a6SAndroid Build Coastguard Worker # A string or None. 160*523fa7a6SAndroid Build Coastguard Worker f"git_version: Optional[str] = {repr(cls.git_hash())}", 161*523fa7a6SAndroid Build Coastguard Worker ] 162*523fa7a6SAndroid Build Coastguard Worker with open(path, "w") as fp: 163*523fa7a6SAndroid Build Coastguard Worker fp.write("\n".join(lines) + "\n") 164*523fa7a6SAndroid Build Coastguard Worker 165*523fa7a6SAndroid Build Coastguard Worker 166*523fa7a6SAndroid Build Coastguard Worker# The build type is determined by the DEBUG environment variable. If DEBUG is 167*523fa7a6SAndroid Build Coastguard Worker# set to a non-empty value, the build type is Debug. Otherwise, the build type 168*523fa7a6SAndroid Build Coastguard Worker# is Release. 169*523fa7a6SAndroid Build Coastguard Workerdef get_build_type(is_debug=None) -> str: 170*523fa7a6SAndroid Build Coastguard Worker debug = int(os.environ.get("DEBUG", 0)) if is_debug is None else is_debug 171*523fa7a6SAndroid Build Coastguard Worker cfg = "Debug" if debug else "Release" 172*523fa7a6SAndroid Build Coastguard Worker return cfg 173*523fa7a6SAndroid Build Coastguard Worker 174*523fa7a6SAndroid Build Coastguard Worker 175*523fa7a6SAndroid Build Coastguard Workerdef get_dynamic_lib_name(name: str) -> str: 176*523fa7a6SAndroid Build Coastguard Worker if platform.system() == "Windows": 177*523fa7a6SAndroid Build Coastguard Worker return name + ".dll" 178*523fa7a6SAndroid Build Coastguard Worker elif platform.system() == "Darwin": 179*523fa7a6SAndroid Build Coastguard Worker return "lib" + name + ".dylib" 180*523fa7a6SAndroid Build Coastguard Worker else: 181*523fa7a6SAndroid Build Coastguard Worker return "lib" + name + ".so" 182*523fa7a6SAndroid Build Coastguard Worker 183*523fa7a6SAndroid Build Coastguard Worker 184*523fa7a6SAndroid Build Coastguard Workerdef get_executable_name(name: str) -> str: 185*523fa7a6SAndroid Build Coastguard Worker if platform.system() == "Windows": 186*523fa7a6SAndroid Build Coastguard Worker return name + ".exe" 187*523fa7a6SAndroid Build Coastguard Worker else: 188*523fa7a6SAndroid Build Coastguard Worker return name 189*523fa7a6SAndroid Build Coastguard Worker 190*523fa7a6SAndroid Build Coastguard Worker 191*523fa7a6SAndroid Build Coastguard Workerclass _BaseExtension(Extension): 192*523fa7a6SAndroid Build Coastguard Worker """A base class that maps an abstract source to an abstract destination.""" 193*523fa7a6SAndroid Build Coastguard Worker 194*523fa7a6SAndroid Build Coastguard Worker def __init__(self, src: str, dst: str, name: str): 195*523fa7a6SAndroid Build Coastguard Worker # Source path; semantics defined by the subclass. 196*523fa7a6SAndroid Build Coastguard Worker self.src: str = src 197*523fa7a6SAndroid Build Coastguard Worker 198*523fa7a6SAndroid Build Coastguard Worker # Destination path relative to a namespace defined elsewhere. If this ends 199*523fa7a6SAndroid Build Coastguard Worker # in "/", it is treated as a directory. If this is "", it is treated as the 200*523fa7a6SAndroid Build Coastguard Worker # root of the namespace. 201*523fa7a6SAndroid Build Coastguard Worker # Destination path; semantics defined by the subclass. 202*523fa7a6SAndroid Build Coastguard Worker self.dst: str = dst 203*523fa7a6SAndroid Build Coastguard Worker 204*523fa7a6SAndroid Build Coastguard Worker # Other parts of setuptools expects .name to exist. For actual extensions 205*523fa7a6SAndroid Build Coastguard Worker # this can be the module path, but otherwise it should be somehing unique 206*523fa7a6SAndroid Build Coastguard Worker # that doesn't look like a module path. 207*523fa7a6SAndroid Build Coastguard Worker self.name: str = name 208*523fa7a6SAndroid Build Coastguard Worker 209*523fa7a6SAndroid Build Coastguard Worker super().__init__(name=self.name, sources=[]) 210*523fa7a6SAndroid Build Coastguard Worker 211*523fa7a6SAndroid Build Coastguard Worker def src_path(self, installer: "InstallerBuildExt") -> Path: 212*523fa7a6SAndroid Build Coastguard Worker """Returns the path to the source file, resolving globs. 213*523fa7a6SAndroid Build Coastguard Worker 214*523fa7a6SAndroid Build Coastguard Worker Args: 215*523fa7a6SAndroid Build Coastguard Worker installer: The InstallerBuildExt instance that is installing the 216*523fa7a6SAndroid Build Coastguard Worker file. 217*523fa7a6SAndroid Build Coastguard Worker """ 218*523fa7a6SAndroid Build Coastguard Worker # Share the cmake-out location with CustomBuild. 219*523fa7a6SAndroid Build Coastguard Worker cmake_cache_dir = Path(installer.get_finalized_command("build").cmake_cache_dir) 220*523fa7a6SAndroid Build Coastguard Worker 221*523fa7a6SAndroid Build Coastguard Worker cfg = get_build_type(installer.debug) 222*523fa7a6SAndroid Build Coastguard Worker 223*523fa7a6SAndroid Build Coastguard Worker if os.name == "nt": 224*523fa7a6SAndroid Build Coastguard Worker # Replace %BUILD_TYPE% with the current build type. 225*523fa7a6SAndroid Build Coastguard Worker self.src = self.src.replace("%BUILD_TYPE%", cfg) 226*523fa7a6SAndroid Build Coastguard Worker else: 227*523fa7a6SAndroid Build Coastguard Worker # Remove %BUILD_TYPE% from the path. 228*523fa7a6SAndroid Build Coastguard Worker self.src = self.src.replace("/%BUILD_TYPE%", "") 229*523fa7a6SAndroid Build Coastguard Worker 230*523fa7a6SAndroid Build Coastguard Worker # Construct the full source path, resolving globs. If there are no glob 231*523fa7a6SAndroid Build Coastguard Worker # pattern characters, this will just ensure that the source file exists. 232*523fa7a6SAndroid Build Coastguard Worker srcs = tuple(cmake_cache_dir.glob(self.src)) 233*523fa7a6SAndroid Build Coastguard Worker if len(srcs) != 1: 234*523fa7a6SAndroid Build Coastguard Worker raise ValueError( 235*523fa7a6SAndroid Build Coastguard Worker f"Expected exactly one file matching '{self.src}'; found {repr(srcs)}" 236*523fa7a6SAndroid Build Coastguard Worker ) 237*523fa7a6SAndroid Build Coastguard Worker return srcs[0] 238*523fa7a6SAndroid Build Coastguard Worker 239*523fa7a6SAndroid Build Coastguard Worker 240*523fa7a6SAndroid Build Coastguard Workerclass BuiltFile(_BaseExtension): 241*523fa7a6SAndroid Build Coastguard Worker """An extension that installs a single file that was built by cmake. 242*523fa7a6SAndroid Build Coastguard Worker 243*523fa7a6SAndroid Build Coastguard Worker This isn't technically a `build_ext` style python extension, but there's no 244*523fa7a6SAndroid Build Coastguard Worker dedicated command for installing arbitrary data. It's convenient to use 245*523fa7a6SAndroid Build Coastguard Worker this, though, because it lets us manage the files to install as entries in 246*523fa7a6SAndroid Build Coastguard Worker `ext_modules`. 247*523fa7a6SAndroid Build Coastguard Worker """ 248*523fa7a6SAndroid Build Coastguard Worker 249*523fa7a6SAndroid Build Coastguard Worker def __init__( 250*523fa7a6SAndroid Build Coastguard Worker self, 251*523fa7a6SAndroid Build Coastguard Worker src_dir: str, 252*523fa7a6SAndroid Build Coastguard Worker src_name: str, 253*523fa7a6SAndroid Build Coastguard Worker dst: str, 254*523fa7a6SAndroid Build Coastguard Worker is_executable: bool = False, 255*523fa7a6SAndroid Build Coastguard Worker is_dynamic_lib: bool = False, 256*523fa7a6SAndroid Build Coastguard Worker ): 257*523fa7a6SAndroid Build Coastguard Worker """Initializes a BuiltFile. 258*523fa7a6SAndroid Build Coastguard Worker 259*523fa7a6SAndroid Build Coastguard Worker Args: 260*523fa7a6SAndroid Build Coastguard Worker src_dir: The directory of the file to install, relative to the cmake-out 261*523fa7a6SAndroid Build Coastguard Worker directory. A placeholder %BUILD_TYPE% will be replaced with the build 262*523fa7a6SAndroid Build Coastguard Worker type for multi-config generators (like Visual Studio) where the build 263*523fa7a6SAndroid Build Coastguard Worker output is in a subdirectory named after the build type. For single- 264*523fa7a6SAndroid Build Coastguard Worker config generators (like Makefile Generators or Ninja), this placeholder 265*523fa7a6SAndroid Build Coastguard Worker will be removed. 266*523fa7a6SAndroid Build Coastguard Worker src_name: The name of the file to install 267*523fa7a6SAndroid Build Coastguard Worker dst: The path to install to, relative to the root of the pip 268*523fa7a6SAndroid Build Coastguard Worker package. If dst ends in "/", it is treated as a directory. 269*523fa7a6SAndroid Build Coastguard Worker Otherwise it is treated as a filename. 270*523fa7a6SAndroid Build Coastguard Worker is_executable: If True, the file is an executable. This is used to 271*523fa7a6SAndroid Build Coastguard Worker determine the destination filename for executable. 272*523fa7a6SAndroid Build Coastguard Worker is_dynamic_lib: If True, the file is a dynamic library. This is used 273*523fa7a6SAndroid Build Coastguard Worker to determine the destination filename for dynamic library. 274*523fa7a6SAndroid Build Coastguard Worker """ 275*523fa7a6SAndroid Build Coastguard Worker if is_executable and is_dynamic_lib: 276*523fa7a6SAndroid Build Coastguard Worker raise ValueError("is_executable and is_dynamic_lib cannot be both True.") 277*523fa7a6SAndroid Build Coastguard Worker if is_executable: 278*523fa7a6SAndroid Build Coastguard Worker src_name = get_executable_name(src_name) 279*523fa7a6SAndroid Build Coastguard Worker elif is_dynamic_lib: 280*523fa7a6SAndroid Build Coastguard Worker src_name = get_dynamic_lib_name(src_name) 281*523fa7a6SAndroid Build Coastguard Worker src = os.path.join(src_dir, src_name) 282*523fa7a6SAndroid Build Coastguard Worker # This is not a real extension, so use a unique name that doesn't look 283*523fa7a6SAndroid Build Coastguard Worker # like a module path. Some of setuptools's autodiscovery will look for 284*523fa7a6SAndroid Build Coastguard Worker # extension names with prefixes that match certain module paths. 285*523fa7a6SAndroid Build Coastguard Worker super().__init__(src=src, dst=dst, name=f"@EXECUTORCH_BuiltFile_{src}:{dst}") 286*523fa7a6SAndroid Build Coastguard Worker 287*523fa7a6SAndroid Build Coastguard Worker def dst_path(self, installer: "InstallerBuildExt") -> Path: 288*523fa7a6SAndroid Build Coastguard Worker """Returns the path to the destination file. 289*523fa7a6SAndroid Build Coastguard Worker 290*523fa7a6SAndroid Build Coastguard Worker Args: 291*523fa7a6SAndroid Build Coastguard Worker installer: The InstallerBuildExt instance that is installing the 292*523fa7a6SAndroid Build Coastguard Worker file. 293*523fa7a6SAndroid Build Coastguard Worker """ 294*523fa7a6SAndroid Build Coastguard Worker dst_root = Path(installer.build_lib).resolve() 295*523fa7a6SAndroid Build Coastguard Worker 296*523fa7a6SAndroid Build Coastguard Worker if self.dst.endswith("/"): 297*523fa7a6SAndroid Build Coastguard Worker # Destination looks like a directory. Use the basename of the source 298*523fa7a6SAndroid Build Coastguard Worker # file for its final component. 299*523fa7a6SAndroid Build Coastguard Worker return dst_root / Path(self.dst) / self.src_path(installer).name 300*523fa7a6SAndroid Build Coastguard Worker else: 301*523fa7a6SAndroid Build Coastguard Worker # Destination looks like a file. 302*523fa7a6SAndroid Build Coastguard Worker return dst_root / Path(self.dst) 303*523fa7a6SAndroid Build Coastguard Worker 304*523fa7a6SAndroid Build Coastguard Worker 305*523fa7a6SAndroid Build Coastguard Workerclass BuiltExtension(_BaseExtension): 306*523fa7a6SAndroid Build Coastguard Worker """An extension that installs a python extension that was built by cmake.""" 307*523fa7a6SAndroid Build Coastguard Worker 308*523fa7a6SAndroid Build Coastguard Worker def __init__(self, src: str, modpath: str): 309*523fa7a6SAndroid Build Coastguard Worker """Initializes a BuiltExtension. 310*523fa7a6SAndroid Build Coastguard Worker 311*523fa7a6SAndroid Build Coastguard Worker Args: 312*523fa7a6SAndroid Build Coastguard Worker src: The path to the file to install (typically a shared library), 313*523fa7a6SAndroid Build Coastguard Worker relative to the cmake-out directory. May be an fnmatch-style 314*523fa7a6SAndroid Build Coastguard Worker glob that matches exactly one file. If the path ends in `.so`, 315*523fa7a6SAndroid Build Coastguard Worker this class will also look for similarly-named `.dylib` files. 316*523fa7a6SAndroid Build Coastguard Worker modpath: The dotted path of the python module that maps to the 317*523fa7a6SAndroid Build Coastguard Worker extension. 318*523fa7a6SAndroid Build Coastguard Worker """ 319*523fa7a6SAndroid Build Coastguard Worker assert ( 320*523fa7a6SAndroid Build Coastguard Worker "/" not in modpath 321*523fa7a6SAndroid Build Coastguard Worker ), f"modpath must be a dotted python module path: saw '{modpath}'" 322*523fa7a6SAndroid Build Coastguard Worker # This is a real extension, so use the modpath as the name. 323*523fa7a6SAndroid Build Coastguard Worker super().__init__(src=src, dst=modpath, name=modpath) 324*523fa7a6SAndroid Build Coastguard Worker 325*523fa7a6SAndroid Build Coastguard Worker def src_path(self, installer: "InstallerBuildExt") -> Path: 326*523fa7a6SAndroid Build Coastguard Worker """Returns the path to the source file, resolving globs. 327*523fa7a6SAndroid Build Coastguard Worker 328*523fa7a6SAndroid Build Coastguard Worker Args: 329*523fa7a6SAndroid Build Coastguard Worker installer: The InstallerBuildExt instance that is installing the 330*523fa7a6SAndroid Build Coastguard Worker file. 331*523fa7a6SAndroid Build Coastguard Worker """ 332*523fa7a6SAndroid Build Coastguard Worker try: 333*523fa7a6SAndroid Build Coastguard Worker return super().src_path(installer) 334*523fa7a6SAndroid Build Coastguard Worker except ValueError: 335*523fa7a6SAndroid Build Coastguard Worker # Probably couldn't find the file. If the path ends with .so, try 336*523fa7a6SAndroid Build Coastguard Worker # looking for a .dylib file instead, in case we're running on macos. 337*523fa7a6SAndroid Build Coastguard Worker if self.src.endswith(".so"): 338*523fa7a6SAndroid Build Coastguard Worker dylib_src = re.sub(r"\.so$", ".dylib", self.src) 339*523fa7a6SAndroid Build Coastguard Worker return BuiltExtension(src=dylib_src, modpath=self.dst).src_path( 340*523fa7a6SAndroid Build Coastguard Worker installer 341*523fa7a6SAndroid Build Coastguard Worker ) 342*523fa7a6SAndroid Build Coastguard Worker else: 343*523fa7a6SAndroid Build Coastguard Worker raise 344*523fa7a6SAndroid Build Coastguard Worker 345*523fa7a6SAndroid Build Coastguard Worker def dst_path(self, installer: "InstallerBuildExt") -> Path: 346*523fa7a6SAndroid Build Coastguard Worker """Returns the path to the destination file. 347*523fa7a6SAndroid Build Coastguard Worker 348*523fa7a6SAndroid Build Coastguard Worker Args: 349*523fa7a6SAndroid Build Coastguard Worker installer: The InstallerBuildExt instance that is installing the 350*523fa7a6SAndroid Build Coastguard Worker file. 351*523fa7a6SAndroid Build Coastguard Worker """ 352*523fa7a6SAndroid Build Coastguard Worker # Our destination is a dotted module path. get_ext_fullpath() returns 353*523fa7a6SAndroid Build Coastguard Worker # the relative path to the .so/.dylib/etc. file that maps to the module 354*523fa7a6SAndroid Build Coastguard Worker # path: that's the file we're creating. 355*523fa7a6SAndroid Build Coastguard Worker return Path(installer.get_ext_fullpath(self.dst)) 356*523fa7a6SAndroid Build Coastguard Worker 357*523fa7a6SAndroid Build Coastguard Worker 358*523fa7a6SAndroid Build Coastguard Workerclass InstallerBuildExt(build_ext): 359*523fa7a6SAndroid Build Coastguard Worker """Installs files that were built by cmake.""" 360*523fa7a6SAndroid Build Coastguard Worker 361*523fa7a6SAndroid Build Coastguard Worker # TODO(dbort): Depend on the "build" command to ensure it runs first 362*523fa7a6SAndroid Build Coastguard Worker 363*523fa7a6SAndroid Build Coastguard Worker def build_extension(self, ext: _BaseExtension) -> None: 364*523fa7a6SAndroid Build Coastguard Worker src_file: Path = ext.src_path(self) 365*523fa7a6SAndroid Build Coastguard Worker dst_file: Path = ext.dst_path(self) 366*523fa7a6SAndroid Build Coastguard Worker 367*523fa7a6SAndroid Build Coastguard Worker # Ensure that the destination directory exists. 368*523fa7a6SAndroid Build Coastguard Worker self.mkpath(os.fspath(dst_file.parent)) 369*523fa7a6SAndroid Build Coastguard Worker 370*523fa7a6SAndroid Build Coastguard Worker # Copy the file. 371*523fa7a6SAndroid Build Coastguard Worker self.copy_file(os.fspath(src_file), os.fspath(dst_file)) 372*523fa7a6SAndroid Build Coastguard Worker 373*523fa7a6SAndroid Build Coastguard Worker # Ensure that the destination file is writable, even if the source was 374*523fa7a6SAndroid Build Coastguard Worker # not. build_py does this by passing preserve_mode=False to copy_file, 375*523fa7a6SAndroid Build Coastguard Worker # but that would clobber the X bit on any executables. TODO(dbort): This 376*523fa7a6SAndroid Build Coastguard Worker # probably won't work on Windows. 377*523fa7a6SAndroid Build Coastguard Worker if not os.access(src_file, os.W_OK): 378*523fa7a6SAndroid Build Coastguard Worker # Make the file writable. This should respect the umask. 379*523fa7a6SAndroid Build Coastguard Worker os.chmod(src_file, os.stat(src_file).st_mode | 0o222) 380*523fa7a6SAndroid Build Coastguard Worker 381*523fa7a6SAndroid Build Coastguard Worker 382*523fa7a6SAndroid Build Coastguard Workerclass CustomBuildPy(build_py): 383*523fa7a6SAndroid Build Coastguard Worker """Copies platform-independent files from the source tree into the output 384*523fa7a6SAndroid Build Coastguard Worker package directory. 385*523fa7a6SAndroid Build Coastguard Worker 386*523fa7a6SAndroid Build Coastguard Worker Override it so we can copy some files to locations that don't match their 387*523fa7a6SAndroid Build Coastguard Worker original relative locations. 388*523fa7a6SAndroid Build Coastguard Worker 389*523fa7a6SAndroid Build Coastguard Worker Standard setuptools features like package_data and MANIFEST.in can only 390*523fa7a6SAndroid Build Coastguard Worker include or exclude a file in the source tree; they don't have a way to map 391*523fa7a6SAndroid Build Coastguard Worker a file to a different relative location under the output package directory. 392*523fa7a6SAndroid Build Coastguard Worker """ 393*523fa7a6SAndroid Build Coastguard Worker 394*523fa7a6SAndroid Build Coastguard Worker def run(self): 395*523fa7a6SAndroid Build Coastguard Worker # Copy python files to the output directory. This set of files is 396*523fa7a6SAndroid Build Coastguard Worker # defined by the py_module list and package_data patterns. 397*523fa7a6SAndroid Build Coastguard Worker build_py.run(self) 398*523fa7a6SAndroid Build Coastguard Worker 399*523fa7a6SAndroid Build Coastguard Worker # dst_root is the root of the `executorch` module in the output package 400*523fa7a6SAndroid Build Coastguard Worker # directory. build_lib is the platform-independent root of the output 401*523fa7a6SAndroid Build Coastguard Worker # package, and will look like `pip-out/lib`. It can contain multiple 402*523fa7a6SAndroid Build Coastguard Worker # python packages, so be sure to copy the files into the `executorch` 403*523fa7a6SAndroid Build Coastguard Worker # package subdirectory. 404*523fa7a6SAndroid Build Coastguard Worker dst_root = os.path.join(self.build_lib, self.get_package_dir("executorch")) 405*523fa7a6SAndroid Build Coastguard Worker 406*523fa7a6SAndroid Build Coastguard Worker # Create the version file. 407*523fa7a6SAndroid Build Coastguard Worker Version.write_to_python_file(os.path.join(dst_root, "version.py")) 408*523fa7a6SAndroid Build Coastguard Worker 409*523fa7a6SAndroid Build Coastguard Worker # Manually copy files into the output package directory. These are 410*523fa7a6SAndroid Build Coastguard Worker # typically python "resource" files that will live alongside the python 411*523fa7a6SAndroid Build Coastguard Worker # code that uses them. 412*523fa7a6SAndroid Build Coastguard Worker src_to_dst = [ 413*523fa7a6SAndroid Build Coastguard Worker # TODO(dbort): See if we can add a custom pyproject.toml section for 414*523fa7a6SAndroid Build Coastguard Worker # these, instead of hard-coding them here. See 415*523fa7a6SAndroid Build Coastguard Worker # https://setuptools.pypa.io/en/latest/userguide/extension.html 416*523fa7a6SAndroid Build Coastguard Worker ("schema/scalar_type.fbs", "exir/_serialize/scalar_type.fbs"), 417*523fa7a6SAndroid Build Coastguard Worker ("schema/program.fbs", "exir/_serialize/program.fbs"), 418*523fa7a6SAndroid Build Coastguard Worker ( 419*523fa7a6SAndroid Build Coastguard Worker "devtools/bundled_program/schema/bundled_program_schema.fbs", 420*523fa7a6SAndroid Build Coastguard Worker "devtools/bundled_program/serialize/bundled_program_schema.fbs", 421*523fa7a6SAndroid Build Coastguard Worker ), 422*523fa7a6SAndroid Build Coastguard Worker ( 423*523fa7a6SAndroid Build Coastguard Worker "devtools/bundled_program/schema/scalar_type.fbs", 424*523fa7a6SAndroid Build Coastguard Worker "devtools/bundled_program/serialize/scalar_type.fbs", 425*523fa7a6SAndroid Build Coastguard Worker ), 426*523fa7a6SAndroid Build Coastguard Worker # Install executorch-wheel-config.cmake to pip package. 427*523fa7a6SAndroid Build Coastguard Worker ( 428*523fa7a6SAndroid Build Coastguard Worker "build/executorch-wheel-config.cmake", 429*523fa7a6SAndroid Build Coastguard Worker "share/cmake/executorch-config.cmake", 430*523fa7a6SAndroid Build Coastguard Worker ), 431*523fa7a6SAndroid Build Coastguard Worker ] 432*523fa7a6SAndroid Build Coastguard Worker # Copy all the necessary headers into include/executorch/ so that they can 433*523fa7a6SAndroid Build Coastguard Worker # be found in the pip package. This is the subset of headers that are 434*523fa7a6SAndroid Build Coastguard Worker # essential for building custom ops extensions. 435*523fa7a6SAndroid Build Coastguard Worker # TODO: Use cmake to gather the headers instead of hard-coding them here. 436*523fa7a6SAndroid Build Coastguard Worker # For example: https://discourse.cmake.org/t/installing-headers-the-modern- 437*523fa7a6SAndroid Build Coastguard Worker # way-regurgitated-and-revisited/3238/3 438*523fa7a6SAndroid Build Coastguard Worker for include_dir in [ 439*523fa7a6SAndroid Build Coastguard Worker "runtime/core/", 440*523fa7a6SAndroid Build Coastguard Worker "runtime/kernel/", 441*523fa7a6SAndroid Build Coastguard Worker "runtime/platform/", 442*523fa7a6SAndroid Build Coastguard Worker "extension/kernel_util/", 443*523fa7a6SAndroid Build Coastguard Worker "extension/tensor/", 444*523fa7a6SAndroid Build Coastguard Worker "extension/threadpool/", 445*523fa7a6SAndroid Build Coastguard Worker ]: 446*523fa7a6SAndroid Build Coastguard Worker src_list = Path(include_dir).rglob("*.h") 447*523fa7a6SAndroid Build Coastguard Worker for src in src_list: 448*523fa7a6SAndroid Build Coastguard Worker src_to_dst.append( 449*523fa7a6SAndroid Build Coastguard Worker (str(src), os.path.join("include/executorch", str(src))) 450*523fa7a6SAndroid Build Coastguard Worker ) 451*523fa7a6SAndroid Build Coastguard Worker for src, dst in src_to_dst: 452*523fa7a6SAndroid Build Coastguard Worker dst = os.path.join(dst_root, dst) 453*523fa7a6SAndroid Build Coastguard Worker 454*523fa7a6SAndroid Build Coastguard Worker # When modifying the filesystem, use the self.* methods defined by 455*523fa7a6SAndroid Build Coastguard Worker # Command to benefit from the same logging and dry_run logic as 456*523fa7a6SAndroid Build Coastguard Worker # setuptools. 457*523fa7a6SAndroid Build Coastguard Worker 458*523fa7a6SAndroid Build Coastguard Worker # Ensure that the destination directory exists. 459*523fa7a6SAndroid Build Coastguard Worker self.mkpath(os.path.dirname(dst)) 460*523fa7a6SAndroid Build Coastguard Worker # Follow the example of the base build_py class by not preserving 461*523fa7a6SAndroid Build Coastguard Worker # the mode. This ensures that the output file is read/write even if 462*523fa7a6SAndroid Build Coastguard Worker # the input file is read-only. 463*523fa7a6SAndroid Build Coastguard Worker self.copy_file(src, dst, preserve_mode=False) 464*523fa7a6SAndroid Build Coastguard Worker 465*523fa7a6SAndroid Build Coastguard Worker 466*523fa7a6SAndroid Build Coastguard Workerclass Buck2EnvironmentFixer(contextlib.AbstractContextManager): 467*523fa7a6SAndroid Build Coastguard Worker """Removes HOME from the environment when running as root. 468*523fa7a6SAndroid Build Coastguard Worker 469*523fa7a6SAndroid Build Coastguard Worker This script is sometimes run as root in docker containers. buck2 doesn't 470*523fa7a6SAndroid Build Coastguard Worker allow running as root unless $HOME is owned by root or is not set. 471*523fa7a6SAndroid Build Coastguard Worker 472*523fa7a6SAndroid Build Coastguard Worker TODO(pytorch/test-infra#5091): Remove this once the CI jobs stop running as 473*523fa7a6SAndroid Build Coastguard Worker root. 474*523fa7a6SAndroid Build Coastguard Worker """ 475*523fa7a6SAndroid Build Coastguard Worker 476*523fa7a6SAndroid Build Coastguard Worker def __init__(self): 477*523fa7a6SAndroid Build Coastguard Worker self.saved_env = {} 478*523fa7a6SAndroid Build Coastguard Worker 479*523fa7a6SAndroid Build Coastguard Worker def __enter__(self): 480*523fa7a6SAndroid Build Coastguard Worker if os.name != "nt" and os.geteuid() == 0 and "HOME" in os.environ: 481*523fa7a6SAndroid Build Coastguard Worker log.info("temporarily unsetting HOME while running as root") 482*523fa7a6SAndroid Build Coastguard Worker self.saved_env["HOME"] = os.environ.pop("HOME") 483*523fa7a6SAndroid Build Coastguard Worker return self 484*523fa7a6SAndroid Build Coastguard Worker 485*523fa7a6SAndroid Build Coastguard Worker def __exit__(self, *args, **kwargs): 486*523fa7a6SAndroid Build Coastguard Worker if "HOME" in self.saved_env: 487*523fa7a6SAndroid Build Coastguard Worker log.info("restored HOME") 488*523fa7a6SAndroid Build Coastguard Worker os.environ["HOME"] = self.saved_env["HOME"] 489*523fa7a6SAndroid Build Coastguard Worker 490*523fa7a6SAndroid Build Coastguard Worker 491*523fa7a6SAndroid Build Coastguard Worker# TODO(dbort): For editable wheels, may need to update get_source_files(), 492*523fa7a6SAndroid Build Coastguard Worker# get_outputs(), and get_output_mapping() to satisfy 493*523fa7a6SAndroid Build Coastguard Worker# https://setuptools.pypa.io/en/latest/userguide/extension.html#setuptools.command.build.SubCommand.get_output_mapping 494*523fa7a6SAndroid Build Coastguard Worker 495*523fa7a6SAndroid Build Coastguard Worker 496*523fa7a6SAndroid Build Coastguard Workerclass CustomBuild(build): 497*523fa7a6SAndroid Build Coastguard Worker def initialize_options(self): 498*523fa7a6SAndroid Build Coastguard Worker super().initialize_options() 499*523fa7a6SAndroid Build Coastguard Worker # The default build_base directory is called "build", but we have a 500*523fa7a6SAndroid Build Coastguard Worker # top-level directory with that name. Setting build_base in setup() 501*523fa7a6SAndroid Build Coastguard Worker # doesn't affect this, so override the core build command. 502*523fa7a6SAndroid Build Coastguard Worker # 503*523fa7a6SAndroid Build Coastguard Worker # See build.initialize_options() in 504*523fa7a6SAndroid Build Coastguard Worker # setuptools/_distutils/command/build.py for the default. 505*523fa7a6SAndroid Build Coastguard Worker self.build_base = "pip-out" 506*523fa7a6SAndroid Build Coastguard Worker 507*523fa7a6SAndroid Build Coastguard Worker # Default build parallelism based on number of cores, but allow 508*523fa7a6SAndroid Build Coastguard Worker # overriding through the environment. 509*523fa7a6SAndroid Build Coastguard Worker default_parallel = str(os.cpu_count() - 1) 510*523fa7a6SAndroid Build Coastguard Worker self.parallel = os.environ.get("CMAKE_BUILD_PARALLEL_LEVEL", default_parallel) 511*523fa7a6SAndroid Build Coastguard Worker 512*523fa7a6SAndroid Build Coastguard Worker def run(self): 513*523fa7a6SAndroid Build Coastguard Worker self.dump_options() 514*523fa7a6SAndroid Build Coastguard Worker 515*523fa7a6SAndroid Build Coastguard Worker cfg = get_build_type(self.debug) 516*523fa7a6SAndroid Build Coastguard Worker 517*523fa7a6SAndroid Build Coastguard Worker # get_python_lib() typically returns the path to site-packages, where 518*523fa7a6SAndroid Build Coastguard Worker # all pip packages in the environment are installed. 519*523fa7a6SAndroid Build Coastguard Worker cmake_prefix_path = os.environ.get("CMAKE_PREFIX_PATH", get_python_lib()) 520*523fa7a6SAndroid Build Coastguard Worker 521*523fa7a6SAndroid Build Coastguard Worker # The root of the repo should be the current working directory. Get 522*523fa7a6SAndroid Build Coastguard Worker # the absolute path. 523*523fa7a6SAndroid Build Coastguard Worker repo_root = os.fspath(Path.cwd()) 524*523fa7a6SAndroid Build Coastguard Worker 525*523fa7a6SAndroid Build Coastguard Worker # If blank, the cmake build system will find an appropriate binary. 526*523fa7a6SAndroid Build Coastguard Worker buck2 = os.environ.get( 527*523fa7a6SAndroid Build Coastguard Worker "BUCK2_EXECUTABLE", os.environ.get("BUCK2", os.environ.get("BUCK", "")) 528*523fa7a6SAndroid Build Coastguard Worker ) 529*523fa7a6SAndroid Build Coastguard Worker 530*523fa7a6SAndroid Build Coastguard Worker cmake_args = [ 531*523fa7a6SAndroid Build Coastguard Worker f"-DBUCK2={buck2}", 532*523fa7a6SAndroid Build Coastguard Worker f"-DPYTHON_EXECUTABLE={sys.executable}", 533*523fa7a6SAndroid Build Coastguard Worker # Let cmake calls like `find_package(Torch)` find cmake config files 534*523fa7a6SAndroid Build Coastguard Worker # like `TorchConfig.cmake` that are provided by pip packages. 535*523fa7a6SAndroid Build Coastguard Worker f"-DCMAKE_PREFIX_PATH={cmake_prefix_path}", 536*523fa7a6SAndroid Build Coastguard Worker f"-DCMAKE_BUILD_TYPE={cfg}", 537*523fa7a6SAndroid Build Coastguard Worker # Enable logging even when in release mode. We are building for 538*523fa7a6SAndroid Build Coastguard Worker # desktop, where saving a few kB is less important than showing 539*523fa7a6SAndroid Build Coastguard Worker # useful error information to users. 540*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_ENABLE_LOGGING=ON", 541*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_LOG_LEVEL=Info", 542*523fa7a6SAndroid Build Coastguard Worker "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15", 543*523fa7a6SAndroid Build Coastguard Worker # The separate host project is only required when cross-compiling, 544*523fa7a6SAndroid Build Coastguard Worker # and it can cause build race conditions (libflatcc.a errors) when 545*523fa7a6SAndroid Build Coastguard Worker # enabled. TODO(dbort): Remove this override once this option is 546*523fa7a6SAndroid Build Coastguard Worker # managed by cmake itself. 547*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_SEPARATE_FLATCC_HOST_PROJECT=OFF", 548*523fa7a6SAndroid Build Coastguard Worker ] 549*523fa7a6SAndroid Build Coastguard Worker 550*523fa7a6SAndroid Build Coastguard Worker build_args = [f"-j{self.parallel}"] 551*523fa7a6SAndroid Build Coastguard Worker 552*523fa7a6SAndroid Build Coastguard Worker # TODO(dbort): Try to manage these targets and the cmake args from the 553*523fa7a6SAndroid Build Coastguard Worker # extension entries themselves instead of hard-coding them here. 554*523fa7a6SAndroid Build Coastguard Worker build_args += ["--target", "flatc"] 555*523fa7a6SAndroid Build Coastguard Worker 556*523fa7a6SAndroid Build Coastguard Worker if ShouldBuild.pybindings(): 557*523fa7a6SAndroid Build Coastguard Worker cmake_args += [ 558*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_PYBIND=ON", 559*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON", # add quantized ops to pybindings. 560*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON", 561*523fa7a6SAndroid Build Coastguard Worker ] 562*523fa7a6SAndroid Build Coastguard Worker build_args += ["--target", "portable_lib"] 563*523fa7a6SAndroid Build Coastguard Worker # To link backends into the portable_lib target, callers should 564*523fa7a6SAndroid Build Coastguard Worker # add entries like `-DEXECUTORCH_BUILD_XNNPACK=ON` to the CMAKE_ARGS 565*523fa7a6SAndroid Build Coastguard Worker # environment variable. 566*523fa7a6SAndroid Build Coastguard Worker 567*523fa7a6SAndroid Build Coastguard Worker if ShouldBuild.llama_custom_ops(): 568*523fa7a6SAndroid Build Coastguard Worker cmake_args += [ 569*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON", # add llama sdpa ops to pybindings. 570*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_CUSTOM_AOT=ON", 571*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON", # add quantized ops to pybindings. 572*523fa7a6SAndroid Build Coastguard Worker "-DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON", 573*523fa7a6SAndroid Build Coastguard Worker ] 574*523fa7a6SAndroid Build Coastguard Worker build_args += ["--target", "custom_ops_aot_lib"] 575*523fa7a6SAndroid Build Coastguard Worker build_args += ["--target", "quantized_ops_aot_lib"] 576*523fa7a6SAndroid Build Coastguard Worker # Allow adding extra cmake args through the environment. Used by some 577*523fa7a6SAndroid Build Coastguard Worker # tests and demos to expand the set of targets included in the pip 578*523fa7a6SAndroid Build Coastguard Worker # package. 579*523fa7a6SAndroid Build Coastguard Worker if "CMAKE_ARGS" in os.environ: 580*523fa7a6SAndroid Build Coastguard Worker cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] 581*523fa7a6SAndroid Build Coastguard Worker 582*523fa7a6SAndroid Build Coastguard Worker # Allow adding extra build args through the environment. Used by some 583*523fa7a6SAndroid Build Coastguard Worker # tests and demos to expand the set of targets included in the pip 584*523fa7a6SAndroid Build Coastguard Worker # package. 585*523fa7a6SAndroid Build Coastguard Worker if "CMAKE_BUILD_ARGS" in os.environ: 586*523fa7a6SAndroid Build Coastguard Worker build_args += [ 587*523fa7a6SAndroid Build Coastguard Worker item for item in os.environ["CMAKE_BUILD_ARGS"].split(" ") if item 588*523fa7a6SAndroid Build Coastguard Worker ] 589*523fa7a6SAndroid Build Coastguard Worker 590*523fa7a6SAndroid Build Coastguard Worker # CMAKE_BUILD_TYPE variable specifies the build type (configuration) for 591*523fa7a6SAndroid Build Coastguard Worker # single-configuration generators (e.g., Makefile Generators or Ninja). 592*523fa7a6SAndroid Build Coastguard Worker # For multi-config generators (like Visual Studio), CMAKE_BUILD_TYPE 593*523fa7a6SAndroid Build Coastguard Worker # isn’t directly applicable. 594*523fa7a6SAndroid Build Coastguard Worker # During the build step, --config specifies the configuration to build 595*523fa7a6SAndroid Build Coastguard Worker # for multi-config generators. 596*523fa7a6SAndroid Build Coastguard Worker build_args += ["--config", cfg] 597*523fa7a6SAndroid Build Coastguard Worker 598*523fa7a6SAndroid Build Coastguard Worker # Put the cmake cache under the temp directory, like 599*523fa7a6SAndroid Build Coastguard Worker # "pip-out/temp.<plat>/cmake-out". 600*523fa7a6SAndroid Build Coastguard Worker cmake_cache_dir = os.path.join(repo_root, self.build_temp, "cmake-out") 601*523fa7a6SAndroid Build Coastguard Worker self.mkpath(cmake_cache_dir) 602*523fa7a6SAndroid Build Coastguard Worker 603*523fa7a6SAndroid Build Coastguard Worker # Generate the cmake cache from scratch to ensure that the cache state 604*523fa7a6SAndroid Build Coastguard Worker # is predictable. 605*523fa7a6SAndroid Build Coastguard Worker cmake_cache_file = Path(cmake_cache_dir) / "CMakeCache.txt" 606*523fa7a6SAndroid Build Coastguard Worker log.info(f"deleting {cmake_cache_file}") 607*523fa7a6SAndroid Build Coastguard Worker if not self.dry_run: 608*523fa7a6SAndroid Build Coastguard Worker # Dry run should log the command but not actually run it. 609*523fa7a6SAndroid Build Coastguard Worker (Path(cmake_cache_dir) / "CMakeCache.txt").unlink(missing_ok=True) 610*523fa7a6SAndroid Build Coastguard Worker with Buck2EnvironmentFixer(): 611*523fa7a6SAndroid Build Coastguard Worker # The context manager may patch the environment while running this 612*523fa7a6SAndroid Build Coastguard Worker # cmake command, which happens to run buck2 to get some source 613*523fa7a6SAndroid Build Coastguard Worker # lists. 614*523fa7a6SAndroid Build Coastguard Worker 615*523fa7a6SAndroid Build Coastguard Worker # Generate the build system files. 616*523fa7a6SAndroid Build Coastguard Worker self.spawn(["cmake", "-S", repo_root, "-B", cmake_cache_dir, *cmake_args]) 617*523fa7a6SAndroid Build Coastguard Worker 618*523fa7a6SAndroid Build Coastguard Worker # Build the system. 619*523fa7a6SAndroid Build Coastguard Worker self.spawn(["cmake", "--build", cmake_cache_dir, *build_args]) 620*523fa7a6SAndroid Build Coastguard Worker 621*523fa7a6SAndroid Build Coastguard Worker # Non-python files should live under this data directory. 622*523fa7a6SAndroid Build Coastguard Worker data_root = os.path.join(self.build_lib, "executorch", "data") 623*523fa7a6SAndroid Build Coastguard Worker 624*523fa7a6SAndroid Build Coastguard Worker # Directories like bin/ and lib/ live under data/. 625*523fa7a6SAndroid Build Coastguard Worker bin_dir = os.path.join(data_root, "bin") 626*523fa7a6SAndroid Build Coastguard Worker 627*523fa7a6SAndroid Build Coastguard Worker # Copy the bin wrapper so that users can run any executables under 628*523fa7a6SAndroid Build Coastguard Worker # data/bin, as long as they are listed in the [project.scripts] section 629*523fa7a6SAndroid Build Coastguard Worker # of pyproject.toml. 630*523fa7a6SAndroid Build Coastguard Worker self.mkpath(bin_dir) 631*523fa7a6SAndroid Build Coastguard Worker self.copy_file( 632*523fa7a6SAndroid Build Coastguard Worker "build/pip_data_bin_init.py.in", 633*523fa7a6SAndroid Build Coastguard Worker os.path.join(bin_dir, "__init__.py"), 634*523fa7a6SAndroid Build Coastguard Worker ) 635*523fa7a6SAndroid Build Coastguard Worker # Share the cmake-out location with _BaseExtension. 636*523fa7a6SAndroid Build Coastguard Worker self.cmake_cache_dir = cmake_cache_dir 637*523fa7a6SAndroid Build Coastguard Worker 638*523fa7a6SAndroid Build Coastguard Worker # Finally, run the underlying subcommands like build_py, build_ext. 639*523fa7a6SAndroid Build Coastguard Worker build.run(self) 640*523fa7a6SAndroid Build Coastguard Worker 641*523fa7a6SAndroid Build Coastguard Worker 642*523fa7a6SAndroid Build Coastguard Workerdef get_ext_modules() -> List[Extension]: 643*523fa7a6SAndroid Build Coastguard Worker """Returns the set of extension modules to build.""" 644*523fa7a6SAndroid Build Coastguard Worker ext_modules = [] 645*523fa7a6SAndroid Build Coastguard Worker if ShouldBuild.flatc(): 646*523fa7a6SAndroid Build Coastguard Worker ext_modules.append( 647*523fa7a6SAndroid Build Coastguard Worker BuiltFile( 648*523fa7a6SAndroid Build Coastguard Worker src_dir="third-party/flatbuffers/%BUILD_TYPE%/", 649*523fa7a6SAndroid Build Coastguard Worker src_name="flatc", 650*523fa7a6SAndroid Build Coastguard Worker dst="executorch/data/bin/", 651*523fa7a6SAndroid Build Coastguard Worker is_executable=True, 652*523fa7a6SAndroid Build Coastguard Worker ) 653*523fa7a6SAndroid Build Coastguard Worker ) 654*523fa7a6SAndroid Build Coastguard Worker 655*523fa7a6SAndroid Build Coastguard Worker if ShouldBuild.pybindings(): 656*523fa7a6SAndroid Build Coastguard Worker ext_modules.append( 657*523fa7a6SAndroid Build Coastguard Worker # Install the prebuilt pybindings extension wrapper for the runtime, 658*523fa7a6SAndroid Build Coastguard Worker # portable kernels, and a selection of backends. This lets users 659*523fa7a6SAndroid Build Coastguard Worker # load and execute .pte files from python. 660*523fa7a6SAndroid Build Coastguard Worker BuiltExtension( 661*523fa7a6SAndroid Build Coastguard Worker "_portable_lib.*", "executorch.extension.pybindings._portable_lib" 662*523fa7a6SAndroid Build Coastguard Worker ) 663*523fa7a6SAndroid Build Coastguard Worker ) 664*523fa7a6SAndroid Build Coastguard Worker if ShouldBuild.llama_custom_ops(): 665*523fa7a6SAndroid Build Coastguard Worker ext_modules.append( 666*523fa7a6SAndroid Build Coastguard Worker BuiltFile( 667*523fa7a6SAndroid Build Coastguard Worker src_dir="extension/llm/custom_ops/%BUILD_TYPE%/", 668*523fa7a6SAndroid Build Coastguard Worker src_name="custom_ops_aot_lib", 669*523fa7a6SAndroid Build Coastguard Worker dst="executorch/extension/llm/custom_ops", 670*523fa7a6SAndroid Build Coastguard Worker is_dynamic_lib=True, 671*523fa7a6SAndroid Build Coastguard Worker ) 672*523fa7a6SAndroid Build Coastguard Worker ) 673*523fa7a6SAndroid Build Coastguard Worker ext_modules.append( 674*523fa7a6SAndroid Build Coastguard Worker # Install the prebuilt library for quantized ops required by custom ops. 675*523fa7a6SAndroid Build Coastguard Worker BuiltFile( 676*523fa7a6SAndroid Build Coastguard Worker src_dir="kernels/quantized/%BUILD_TYPE%/", 677*523fa7a6SAndroid Build Coastguard Worker src_name="quantized_ops_aot_lib", 678*523fa7a6SAndroid Build Coastguard Worker dst="executorch/kernels/quantized/", 679*523fa7a6SAndroid Build Coastguard Worker is_dynamic_lib=True, 680*523fa7a6SAndroid Build Coastguard Worker ) 681*523fa7a6SAndroid Build Coastguard Worker ) 682*523fa7a6SAndroid Build Coastguard Worker 683*523fa7a6SAndroid Build Coastguard Worker # Note that setuptools uses the presence of ext_modules as the main signal 684*523fa7a6SAndroid Build Coastguard Worker # that a wheel is platform-specific. If we install any platform-specific 685*523fa7a6SAndroid Build Coastguard Worker # files, this list must be non-empty. Therefore, we should always install 686*523fa7a6SAndroid Build Coastguard Worker # platform-specific files using InstallerBuildExt. 687*523fa7a6SAndroid Build Coastguard Worker return ext_modules 688*523fa7a6SAndroid Build Coastguard Worker 689*523fa7a6SAndroid Build Coastguard Worker 690*523fa7a6SAndroid Build Coastguard Worker# Override extension suffix to be ".so", skipping package info such as 691*523fa7a6SAndroid Build Coastguard Worker# "cpython-311-darwin" 692*523fa7a6SAndroid Build Coastguard Workeros.environ["SETUPTOOLS_EXT_SUFFIX"] = ".so" 693*523fa7a6SAndroid Build Coastguard Worker 694*523fa7a6SAndroid Build Coastguard Workersetup( 695*523fa7a6SAndroid Build Coastguard Worker version=Version.string(), 696*523fa7a6SAndroid Build Coastguard Worker # TODO(dbort): Could use py_modules to restrict the set of modules we 697*523fa7a6SAndroid Build Coastguard Worker # package, and package_data to restrict the set up non-python files we 698*523fa7a6SAndroid Build Coastguard Worker # include. See also setuptools/discovery.py for custom finders. 699*523fa7a6SAndroid Build Coastguard Worker package_dir={ 700*523fa7a6SAndroid Build Coastguard Worker "executorch/backends": "backends", 701*523fa7a6SAndroid Build Coastguard Worker # TODO(mnachin T180504136): Do not put examples/models 702*523fa7a6SAndroid Build Coastguard Worker # into core pip packages. Refactor out the necessary utils 703*523fa7a6SAndroid Build Coastguard Worker # or core models files into a separate package. 704*523fa7a6SAndroid Build Coastguard Worker "executorch/examples/models": "examples/models", 705*523fa7a6SAndroid Build Coastguard Worker "executorch/exir": "exir", 706*523fa7a6SAndroid Build Coastguard Worker "executorch/extension": "extension", 707*523fa7a6SAndroid Build Coastguard Worker "executorch/kernels/quantized": "kernels/quantized", 708*523fa7a6SAndroid Build Coastguard Worker "executorch/schema": "schema", 709*523fa7a6SAndroid Build Coastguard Worker "executorch/devtools": "devtools", 710*523fa7a6SAndroid Build Coastguard Worker "executorch/devtools/bundled_program": "devtools/bundled_program", 711*523fa7a6SAndroid Build Coastguard Worker "executorch/runtime": "runtime", 712*523fa7a6SAndroid Build Coastguard Worker "executorch/util": "util", 713*523fa7a6SAndroid Build Coastguard Worker # Note: This will install a top-level module called "serializer", 714*523fa7a6SAndroid Build Coastguard Worker # which seems too generic and might conflict with other pip packages. 715*523fa7a6SAndroid Build Coastguard Worker "serializer": "backends/arm/third-party/serialization_lib/python/serializer", 716*523fa7a6SAndroid Build Coastguard Worker "tosa": "backends/arm/third-party/serialization_lib/python/tosa", 717*523fa7a6SAndroid Build Coastguard Worker }, 718*523fa7a6SAndroid Build Coastguard Worker cmdclass={ 719*523fa7a6SAndroid Build Coastguard Worker "build": CustomBuild, 720*523fa7a6SAndroid Build Coastguard Worker "build_ext": InstallerBuildExt, 721*523fa7a6SAndroid Build Coastguard Worker "build_py": CustomBuildPy, 722*523fa7a6SAndroid Build Coastguard Worker }, 723*523fa7a6SAndroid Build Coastguard Worker ext_modules=get_ext_modules(), 724*523fa7a6SAndroid Build Coastguard Worker) 725