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