|
55 | 55 | # Import this before distutils so that setuptools can intercept the distuils |
56 | 56 | # imports. |
57 | 57 | import setuptools # noqa: F401 # usort: skip |
| 58 | +import logging |
| 59 | +import subprocess |
58 | 60 |
|
59 | 61 | from distutils import log |
60 | 62 | from distutils.sysconfig import get_python_lib |
|
66 | 68 | from setuptools.command.build_ext import build_ext |
67 | 69 | from setuptools.command.build_py import build_py |
68 | 70 |
|
| 71 | +# Set up logging |
| 72 | +logging.basicConfig( |
| 73 | + level=logging.INFO, format="%(asctime)s [ExecuTorch] %(levelname)s: %(message)s" |
| 74 | +) |
| 75 | +logger = logging.getLogger() |
| 76 | + |
69 | 77 | # For information on setuptools Command subclassing see |
70 | 78 | # https://setuptools.pypa.io/en/latest/userguide/extension.html |
71 | 79 |
|
| 80 | +################################################################################ |
| 81 | +# Git submodules |
| 82 | +################################################################################ |
| 83 | +# The following submodules are required to be able to build ExecuTorch. If any of |
| 84 | +# these folders are missing or missing CMakeLists.txt, we will run |
| 85 | +# `git submodule update` to try to fix it. If the command fails, we will raise an |
| 86 | +# error. |
| 87 | +# An alternative to this would be to run `git submodule status` and run |
| 88 | +# `git submodule update` if there's any local changes. However this is a bit |
| 89 | +# too restrictive for users who modifies and tests the dependencies locally. |
| 90 | + |
| 91 | +# keep sorted |
| 92 | +REQUIRED_SUBMODULES = [ |
| 93 | + "ao", |
| 94 | + "cpuinfo", |
| 95 | + "eigen", |
| 96 | + "flatbuffers", |
| 97 | + "FP16", |
| 98 | + "FXdiv", |
| 99 | + "gflags", |
| 100 | + "prelude", |
| 101 | + "pthreadpool", |
| 102 | + "pybind11", |
| 103 | + "XNNPACK", |
| 104 | +] |
| 105 | + |
| 106 | + |
| 107 | +def get_required_submodule_paths(): |
| 108 | + gitsubmodule_path = os.path.join(os.getcwd(), ".gitsubmodule") |
| 109 | + |
| 110 | + if not os.path.isfile(gitsubmodule_path): |
| 111 | + print("Error: .gitsubmodule file not found.") |
| 112 | + exit(1) |
| 113 | + |
| 114 | + with open(gitsubmodule_path, "r") as file: |
| 115 | + lines = file.readlines() |
| 116 | + |
| 117 | + # Extract paths of required submodules |
| 118 | + required_paths = [] |
| 119 | + for line in lines: |
| 120 | + if line.strip().startswith("path ="): |
| 121 | + path = line.split("=")[1].strip() |
| 122 | + if any(submodule in path for submodule in REQUIRED_SUBMODULES): |
| 123 | + required_paths.append(path) |
| 124 | + return required_paths |
| 125 | + |
| 126 | + |
| 127 | +def check_and_update_submodules(): |
| 128 | + def check_folder(folder: str) -> bool: |
| 129 | + return os.path.isdir(folder) and os.path.isfile( |
| 130 | + os.path.join(folder, "CMakeLists.txt") |
| 131 | + ) |
| 132 | + |
| 133 | + # Check if the directories exist for each required submodule |
| 134 | + missing_submodules = [] |
| 135 | + for path in get_required_submodule_paths(): |
| 136 | + if not check_folder(path): |
| 137 | + missing_submodules.append(path) |
| 138 | + |
| 139 | + # If any required submodule directories are missing, update them |
| 140 | + if missing_submodules: |
| 141 | + logger.warn("Some required submodules are missing. Updating submodules...") |
| 142 | + try: |
| 143 | + subprocess.check_call( |
| 144 | + ["git", "submodule", "update", "--init", "--recursive"] |
| 145 | + ) |
| 146 | + except subprocess.CalledProcessError as e: |
| 147 | + logger.error(f"Error updating submodules: {e}") |
| 148 | + exit(1) |
| 149 | + |
| 150 | + # After updating submodules, check again |
| 151 | + for path in missing_submodules: |
| 152 | + if not check_folder(path): |
| 153 | + logger.error(f"Error: CMakeLists.txt not found in {path}.") |
| 154 | + logger.error("Please run `git submodule update --init --recursive`.") |
| 155 | + exit(1) |
| 156 | + logger.info("All required submodules are present and contain CMakeLists.txt.") |
| 157 | + |
72 | 158 |
|
73 | 159 | class ShouldBuild: |
74 | 160 | """Indicates whether to build various components.""" |
@@ -720,31 +806,39 @@ def get_ext_modules() -> List[Extension]: |
720 | 806 | return ext_modules |
721 | 807 |
|
722 | 808 |
|
723 | | -setup( |
724 | | - version=Version.string(), |
725 | | - # TODO(dbort): Could use py_modules to restrict the set of modules we |
726 | | - # package, and package_data to restrict the set up non-python files we |
727 | | - # include. See also setuptools/discovery.py for custom finders. |
728 | | - package_dir={ |
729 | | - "executorch/backends": "backends", |
730 | | - "executorch/codegen": "codegen", |
731 | | - # TODO(mnachin T180504136): Do not put examples/models |
732 | | - # into core pip packages. Refactor out the necessary utils |
733 | | - # or core models files into a separate package. |
734 | | - "executorch/examples/models": "examples/models", |
735 | | - "executorch/exir": "exir", |
736 | | - "executorch/extension": "extension", |
737 | | - "executorch/kernels/quantized": "kernels/quantized", |
738 | | - "executorch/schema": "schema", |
739 | | - "executorch/devtools": "devtools", |
740 | | - "executorch/devtools/bundled_program": "devtools/bundled_program", |
741 | | - "executorch/runtime": "runtime", |
742 | | - "executorch/util": "util", |
743 | | - }, |
744 | | - cmdclass={ |
745 | | - "build": CustomBuild, |
746 | | - "build_ext": InstallerBuildExt, |
747 | | - "build_py": CustomBuildPy, |
748 | | - }, |
749 | | - ext_modules=get_ext_modules(), |
750 | | -) |
| 809 | +def main(): |
| 810 | + # Check submodules |
| 811 | + check_and_update_submodules() |
| 812 | + |
| 813 | + setup( |
| 814 | + version=Version.string(), |
| 815 | + # TODO(dbort): Could use py_modules to restrict the set of modules we |
| 816 | + # package, and package_data to restrict the set up non-python files we |
| 817 | + # include. See also setuptools/discovery.py for custom finders. |
| 818 | + package_dir={ |
| 819 | + "executorch/backends": "backends", |
| 820 | + "executorch/codegen": "codegen", |
| 821 | + # TODO(mnachin T180504136): Do not put examples/models |
| 822 | + # into core pip packages. Refactor out the necessary utils |
| 823 | + # or core models files into a separate package. |
| 824 | + "executorch/examples/models": "examples/models", |
| 825 | + "executorch/exir": "exir", |
| 826 | + "executorch/extension": "extension", |
| 827 | + "executorch/kernels/quantized": "kernels/quantized", |
| 828 | + "executorch/schema": "schema", |
| 829 | + "executorch/devtools": "devtools", |
| 830 | + "executorch/devtools/bundled_program": "devtools/bundled_program", |
| 831 | + "executorch/runtime": "runtime", |
| 832 | + "executorch/util": "util", |
| 833 | + }, |
| 834 | + cmdclass={ |
| 835 | + "build": CustomBuild, |
| 836 | + "build_ext": InstallerBuildExt, |
| 837 | + "build_py": CustomBuildPy, |
| 838 | + }, |
| 839 | + ext_modules=get_ext_modules(), |
| 840 | + ) |
| 841 | + |
| 842 | + |
| 843 | +if __name__ == "__main__": |
| 844 | + main() |
0 commit comments