| # 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) |