blob: 0e328bd6092ae9bf6bb414fbe725e535d405fce0 [file] [log] [blame]
# 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)