blob: b01a7ef020e5b80f7ed70580e73705d845f9271f [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)