blob: 6e4334216d19af33336a4f048b5333e6d2172668 [file] [log] [blame] [edit]
# pylint: disable=g-bad-file-header
# Copyright 2016 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Base library for configuring the C++ toolchain."""
def escape_string(arg):
"""Escape percent sign (%) in the string so it can appear in the Crosstool."""
if arg != None:
return str(arg).replace("%", "%%")
else:
return None
def split_escaped(string, delimiter):
"""Split string on the delimiter unless %-escaped.
Examples:
Basic usage:
split_escaped("a:b:c", ":") -> [ "a", "b", "c" ]
Delimeter that is not supposed to be splitten on has to be %-escaped:
split_escaped("a%:b", ":") -> [ "a:b" ]
Literal % can be represented by escaping it as %%:
split_escaped("a%%b", ":") -> [ "a%b" ]
Consecutive delimiters produce empty strings:
split_escaped("a::b", ":") -> [ "a", "", "", "b" ]
Args:
string: a string to be splitted
delimiter: non-empty string not containing %-sign to be used as a delimiter
Returns:
a list of substrings
"""
if delimiter == "": fail("Delimiter cannot be empty")
if delimiter.find("%") != -1: fail("Delimiter cannot contain %-sign")
i = 0
result = []
accumulator = []
length = len(string)
delimiter_length = len(delimiter)
# Iterate over the length of string since Skylark doesn't have while loops
for _ in range(length):
if i >= length:
break
if i + 2 <= length and string[i : i + 2] == "%%":
accumulator.append("%")
i += 2
elif (i + 1 + delimiter_length <= length and
string[i : i + 1 + delimiter_length] == "%" + delimiter):
accumulator.append(delimiter)
i += 1 + delimiter_length
elif i + delimiter_length <= length and string[i : i + delimiter_length] == delimiter:
result.append(''.join(accumulator))
accumulator = []
i += delimiter_length
else:
accumulator.append(string[i])
i += 1
# Append the last group still in accumulator
result.append(''.join(accumulator))
return result
def auto_configure_fail(msg):
"""Output failure message when auto configuration fails."""
red = "\033[0;31m"
no_color = "\033[0m"
fail("\n%sAuto-Configuration Error:%s %s\n" % (red, no_color, msg))
def auto_configure_warning(msg):
"""Output warning message during auto configuration."""
yellow = "\033[1;33m"
no_color = "\033[0m"
print("\n%sAuto-Configuration Warning:%s %s\n" % (yellow, no_color, msg))
def get_env_var(repository_ctx, name, default = None, enable_warning = True):
"""Find an environment variable in system path. Doesn't %-escape the value!"""
if name in repository_ctx.os.environ:
return repository_ctx.os.environ[name]
if default != None:
if enable_warning:
auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default))
return default
auto_configure_fail("'%s' environment variable is not set" % name)
def which(repository_ctx, cmd, default = None):
"""A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value!"""
result = repository_ctx.which(cmd)
return default if result == None else str(result)
def which_cmd(repository_ctx, cmd, default = None):
"""Find cmd in PATH using repository_ctx.which() and fail if cannot find it. Doesn't %-escape the cmd!"""
result = repository_ctx.which(cmd)
if result != None:
return str(result)
path = get_env_var(repository_ctx, "PATH")
if default != None:
auto_configure_warning("Cannot find %s in PATH, using '%s' as default.\nPATH=%s" % (cmd, default, path))
return default
auto_configure_fail("Cannot find %s in PATH, please make sure %s is installed and add its directory in PATH.\nPATH=%s" % (cmd, cmd, path))
return str(result)
def execute(repository_ctx, command, environment = None,
expect_failure = False):
"""Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result!"""
if environment:
result = repository_ctx.execute(command, environment = environment)
else:
result = repository_ctx.execute(command)
if expect_failure != (result.return_code != 0):
if expect_failure:
auto_configure_fail(
"expected failure, command %s, stderr: (%s)" % (
command, result.stderr))
else:
auto_configure_fail(
"non-zero exit code: %d, command %s, stderr: (%s)" % (
result.return_code, command, result.stderr))
stripped_stdout = result.stdout.strip()
if not stripped_stdout:
auto_configure_fail(
"empty output from command %s, stderr: (%s)" % (command, result.stderr))
return stripped_stdout
def get_cpu_value(repository_ctx):
"""Compute the cpu_value based on the OS name. Doesn't %-escape the result!"""
os_name = repository_ctx.os.name.lower()
if os_name.startswith("mac os"):
return "darwin"
if os_name.find("freebsd") != -1:
return "freebsd"
if os_name.find("windows") != -1:
return "x64_windows"
# Use uname to figure out whether we are on x86_32 or x86_64
result = repository_ctx.execute(["uname", "-m"])
if result.stdout.strip() in ["power", "ppc64le", "ppc", "ppc64"]:
return "ppc"
if result.stdout.strip() in ["arm", "armv7l", "aarch64"]:
return "arm"
return "k8" if result.stdout.strip() in ["amd64", "x86_64", "x64"] else "piii"
def tpl(repository_ctx, template, substitutions={}, out=None):
if not out:
out = template
repository_ctx.template(
out,
Label("@bazel_tools//tools/cpp:%s.tpl" % template),
substitutions)
def is_cc_configure_debug(repository_ctx):
"""Returns True if CC_CONFIGURE_DEBUG is set to 1."""
env = repository_ctx.os.environ
return "CC_CONFIGURE_DEBUG" in env and env["CC_CONFIGURE_DEBUG"] == "1"