| # Copyright 2020 The IREE Authors | |
| # | |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. | |
| # See https://llvm.org/LICENSE.txt for license information. | |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| # This configure script wraps a normal CMake configure of the project for use | |
| # in CI pipelines, doing some sanity checks, discovery and work-arounding. | |
| # This future is needed to print Python2 EOL message | |
| from __future__ import print_function | |
| import sys | |
| if sys.version_info < (3,): | |
| print("Python 2 has reached end-of-life and is no longer supported.") | |
| sys.exit(-1) | |
| if sys.platform == "win32" and sys.maxsize.bit_length() == 31: | |
| print( | |
| "32-bit Windows Python runtime is not supported. Please switch to 64-bit Python." | |
| ) | |
| sys.exit(-1) | |
| import importlib | |
| import json | |
| import os | |
| import platform | |
| import subprocess | |
| import sysconfig | |
| import tempfile | |
| is_windows = platform.system() == "Windows" | |
| def display_help(): | |
| print("Syntax: python build_tools/cmake/cmake_ci.py [--install|--build] ...") | |
| print("If neither --install or --build are the first argument, then it is ") | |
| print("assumed to be a generate invocation") | |
| mode = "generate" | |
| if len(sys.argv) < 2: | |
| display_help() | |
| sys.exit(1) | |
| if sys.argv[1] == "--install": | |
| mode = "install" | |
| elif sys.argv[1] == "--build": | |
| mode = "build" | |
| def report(*args): | |
| print("--", *args) | |
| def get_setting(varname, default_value): | |
| value = os.environ.get(varname) | |
| if value is None: | |
| return default_value | |
| return value | |
| def get_bool_setting(varname, default_value): | |
| value = get_setting(varname, default_value) | |
| if value is True or value is False: | |
| return value | |
| return value == "" or value == "ON" or value == "1" | |
| def which(thefile): | |
| path = os.environ.get("PATH", os.defpath).split(os.pathsep) | |
| for d in path: | |
| fname = os.path.join(d, thefile) | |
| fnames = [fname] | |
| if sys.platform == "win32": | |
| exts = os.environ.get("PATHEXT", "").split(os.pathsep) | |
| fnames += [fname + ext for ext in exts] | |
| for name in fnames: | |
| if os.access(name, os.F_OK | os.X_OK) and not os.path.isdir(name): | |
| return name | |
| return None | |
| def use_tool_path(toolname, varname=None): | |
| if not varname: | |
| varname = toolname.upper() | |
| value = get_setting(f"USE_{varname}", "ON") | |
| if value.upper() == "OFF": | |
| return None | |
| if value.upper() == "ON" or value == "": | |
| return which(toolname) | |
| if os.access(value, os.F_OK | os.X_OK) and not os.path.isdir(value): | |
| return value | |
| ### Detect cmake. | |
| use_cmake = use_tool_path("cmake") or "cmake" | |
| cmake_command_prefix = [use_cmake] | |
| cmake_environ = os.environ | |
| def cmake_commandline(args): | |
| return cmake_command_prefix + args | |
| if is_windows: | |
| # Bazel needs msys bash and TensorFlow will melt down and cry if it finds | |
| # system bash. Because, of course it will. | |
| # Note that we don't set this as a CMake option because it may have spaces | |
| # in the path, use backslashes or various other things that get corrupted | |
| # in the five or six layers of shoddy string transformations between here | |
| # and where it gets used. | |
| bash_exe = which("bash") | |
| report("Found Windows bash:", bash_exe) | |
| report( | |
| "NOTE: If the above is system32 bash and you are using bazel to build " | |
| "TensorFlow, you are going to have a bad time. Suggest being explicit " | |
| "adding the correct directory to your path. I'm really sorry. " | |
| "I didn't make this mess... just the messenger" | |
| ) | |
| report(f'Full path = {os.environ.get("PATH")}') | |
| def invoke_generate(): | |
| ############################################################################## | |
| # Figure out where we are and where we are going. | |
| ############################################################################## | |
| repo_root = os.path.abspath( | |
| get_setting("REPO_DIR", os.path.join(os.path.dirname(__file__), "..", "..")) | |
| ) | |
| report(f"Using REPO_DIR = {repo_root}") | |
| ############################################################################## | |
| # Load version_info.json | |
| ############################################################################## | |
| def load_version_info(): | |
| with open(os.path.join(repo_root, "version_info.json"), "rt") as f: | |
| return json.load(f) | |
| try: | |
| version_info = load_version_info() | |
| except FileNotFoundError: | |
| report("version_info.json found") | |
| version_info = {} | |
| ############################################################################## | |
| # CMake configure. | |
| ############################################################################## | |
| cmake_args = [ | |
| f"-S{repo_root}", | |
| f"-DPython3_EXECUTABLE:FILEPATH={sys.executable}", | |
| # The old python package settings should not be needed, but since there | |
| # can be configuration races between packages that use both mechanisms, | |
| # be explicit. | |
| f"-DPYTHON_EXECUTABLE:FILEPATH={sys.executable}", | |
| f'-DPython3_INCLUDE_DIR:PATH={sysconfig.get_path("include")}', | |
| f'-DPYTHON_INCLUDE_DIR:PATH={sysconfig.get_path("include")}', | |
| f'-DIREE_RELEASE_PACKAGE_SUFFIX:STRING={version_info.get("package-suffix") or ""}', | |
| f'-DIREE_RELEASE_VERSION:STRING={version_info.get("package-version") or "0.0.1a1"}', | |
| f'-DIREE_RELEASE_REVISION:STRING={version_info.get("iree-revision") or "HEAD"}', | |
| ] | |
| ### Detect generator. | |
| if use_tool_path("ninja"): | |
| report("Using ninja") | |
| cmake_args.append("-GNinja") | |
| elif is_windows: | |
| cmake_args.extend(["-G", "NMake Makefiles"]) | |
| # Detect other build tools. | |
| use_ccache = use_tool_path("ccache") | |
| if not is_windows and use_ccache: | |
| report(f"Using ccache {use_ccache}") | |
| cmake_args.append(f"-DCMAKE_CXX_COMPILER_LAUNCHER={use_ccache}") | |
| # Clang | |
| use_clang = use_tool_path("clang") | |
| if not is_windows and use_clang: | |
| report(f"Using clang {use_clang}") | |
| cmake_args.append(f"-DCMAKE_C_COMPILER={use_clang}") | |
| use_clangcpp = use_tool_path("clang++", "CLANGCPP") | |
| if not is_windows and use_clangcpp: | |
| report(f"Using clang++ {use_clangcpp}") | |
| cmake_args.append(f"-DCMAKE_CXX_COMPILER={use_clangcpp}") | |
| # LLD | |
| use_lld = use_tool_path("lld") | |
| if not is_windows and use_lld: | |
| report(f"Using linker {use_lld}") | |
| cmake_args.append("-DIREE_ENABLE_LLD=ON") | |
| cmake_args.extend(sys.argv[1:]) | |
| report(f'Running cmake (generate): {" ".join(cmake_args)}') | |
| subprocess.check_call(cmake_commandline(cmake_args), env=cmake_environ) | |
| # Select which mode. | |
| if mode == "generate": | |
| invoke_generate() | |
| else: | |
| # Just pass-through. | |
| cmake_args = cmake_commandline(sys.argv[1:]) | |
| report("Invoke CMake:", " ".join(cmake_args)) | |
| subprocess.check_call(cmake_args, env=cmake_environ) |