blob: d9649b1e4c19399754ace024da68177fd5f408cb [file] [log] [blame]
# Copyright (C) 2023 The Android Open Source Project
#
# 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.
"""Helper for `kernel_env` to get toolchains for different platforms."""
load("@bazel_skylib//lib:shell.bzl", "shell")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("//prebuilts/clang/host/linux-x86/kleaf:versions.bzl", _CLANG_VERSIONS = "VERSIONS")
load(
":common_providers.bzl",
"KernelEnvToolchainsInfo",
"KernelPlatformToolchainInfo",
)
visibility("//build/kernel/kleaf/...")
def _quote_prepend_cwd(value):
"""Prepends $PWD to value.
Returns:
quoted shell value
"""
if not value.startswith("/"):
return "${PWD}/" + shell.quote(value)
return shell.quote(value)
def _get_declared_toolchain_version(ctx):
declared_toolchain_version = None
for version in _CLANG_VERSIONS:
attr = getattr(ctx.attr, "_clang_version_{}".format(version))
if ctx.target_platform_has_constraint(attr[platform_common.ConstraintValueInfo]):
declared_toolchain_version = version
return declared_toolchain_version
def _check_toolchain_version(ctx, resolved_toolchain_info, declared_toolchain_version, platform_name):
if declared_toolchain_version == None:
# kernel_build does not declare toolchain_version. Use default CLANG_VERSION from toolchain
# resolution.
return
if resolved_toolchain_info.compiler_version != declared_toolchain_version:
if resolved_toolchain_info.compiler_version == "kleaf_user_clang_toolchain_skip_version_check":
# buildifier: disable=print
print("\nWARNING: kernel_build.toolchain_version = {}, but overriding with --user_clang_toolchain".format(
declared_toolchain_version,
))
else:
fail("{}: Resolved to incorrect toolchain for {} platform. Expected: {}, actual: {}".format(
ctx.label,
platform_name,
declared_toolchain_version,
resolved_toolchain_info.compiler_version,
))
def _get_target_arch(ctx):
if ctx.target_platform_has_constraint(ctx.attr._platform_cpu_arm[platform_common.ConstraintValueInfo]):
return "arm"
if ctx.target_platform_has_constraint(ctx.attr._platform_cpu_arm64[platform_common.ConstraintValueInfo]):
return "arm64"
if ctx.target_platform_has_constraint(ctx.attr._platform_cpu_i386[platform_common.ConstraintValueInfo]):
return "i386"
if ctx.target_platform_has_constraint(ctx.attr._platform_cpu_riscv64[platform_common.ConstraintValueInfo]):
return "riscv64"
if ctx.target_platform_has_constraint(ctx.attr._platform_cpu_x86_64[platform_common.ConstraintValueInfo]):
return "x86_64"
fail("{}: Cannot determine target platform.".format(ctx.label))
def _quote_sanitize_flags(flags):
"""Turns paths into ones relative to $PWD for each flag.
Kbuild executes the compiler in subdirectories, hence an absolute path is needed.
Returns:
quoted shell value
"""
result_quoted_flags = []
long_flags = [
"--sysroot",
"-iquote",
"-isystem",
]
short_flags = [
"-I",
"-L",
]
prev = None
for _index, flag in enumerate(flags):
if prev in long_flags or prev in short_flags:
result_quoted_flags.append(_quote_prepend_cwd(flag))
elif any([flag.startswith(long_flag + "=") for long_flag in long_flags]):
key, value = flag.split("=", 2)
result_quoted_flags.append("{}={}".format(key, _quote_prepend_cwd(value)))
elif any([flag.startswith(short_flag) for short_flag in short_flags]):
key, value = flag[:2], flag[2:]
result_quoted_flags.append("{}{}".format(key, _quote_prepend_cwd(value)))
else:
result_quoted_flags.append(shell.quote(flag))
prev = flag
return "' '".join(result_quoted_flags)
def _kernel_toolchains_impl(ctx):
exec = ctx.attr.exec_toolchain[KernelPlatformToolchainInfo]
target = ctx.attr.target_toolchain[KernelPlatformToolchainInfo]
# The toolchain_version declared in kernel_build. May be None to use
# default toolchain version.
declared_toolchain_version = _get_declared_toolchain_version(ctx)
# Check that
# declared_toolchain_version == None or exec.compiler_version == declared_toolchain_version
_check_toolchain_version(ctx, exec, declared_toolchain_version, "exec")
# Check that
# declared_toolchain_version == None or target.compiler_version == declared_toolchain_version
_check_toolchain_version(ctx, target, declared_toolchain_version, "target")
# If declared_toolchain_version == None, ensures that the resolved toolchain
# for the two platforms equal.
if target.compiler_version != exec.compiler_version:
fail("{}: Target platform has compiler version {} but exec platform has {}".format(
ctx.label,
target.compiler_version,
exec.compiler_version,
))
actual_toolchain_version = target.compiler_version
all_files = depset(transitive = [exec.all_files, target.all_files])
target_arch = _get_target_arch(ctx)
quoted_bin_paths = [
_quote_prepend_cwd(exec.bin_path),
_quote_prepend_cwd(target.bin_path),
]
setup_env_var_cmd = """
export PATH={quoted_bin_paths}:${{PATH}}
""".format(
quoted_bin_paths = ":".join(quoted_bin_paths),
)
if ctx.attr._kernel_use_resolved_toolchains[BuildSettingInfo].value:
setup_env_var_cmd += """
export HOSTCFLAGS={quoted_hostcflags}
export USERCFLAGS={quoted_usercflags}
export HOSTLDFLAGS={quoted_hostldflags}
export USERLDFLAGS={quoted_userldflags}
""".format(
quoted_hostcflags = _quote_sanitize_flags(exec.cflags),
quoted_usercflags = _quote_sanitize_flags(target.cflags),
quoted_hostldflags = _quote_sanitize_flags(exec.ldflags),
quoted_userldflags = _quote_sanitize_flags(target.ldflags),
)
# Kleaf clang bins are under kleaf/parent, so CLANG_PREBUILT_BIN in
# build.config.common is incorrect. Manually set additional PATH's.
return KernelEnvToolchainsInfo(
all_files = all_files,
target_arch = target_arch,
setup_env_var_cmd = setup_env_var_cmd,
compiler_version = actual_toolchain_version,
)
kernel_toolchains = rule(
doc = """Helper for `kernel_env` to get toolchains for different platforms.""",
implementation = _kernel_toolchains_impl,
attrs = {
"exec_toolchain": attr.label(
cfg = "exec",
providers = [KernelPlatformToolchainInfo],
),
"target_toolchain": attr.label(
providers = [KernelPlatformToolchainInfo],
),
"_kernel_use_resolved_toolchains": attr.label(
default = "//build/kernel/kleaf:incompatible_kernel_use_resolved_toolchains",
),
"_platform_cpu_arm": attr.label(default = "@platforms//cpu:arm"),
"_platform_cpu_arm64": attr.label(default = "@platforms//cpu:arm64"),
"_platform_cpu_i386": attr.label(default = "@platforms//cpu:i386"),
"_platform_cpu_riscv64": attr.label(default = "@platforms//cpu:riscv64"),
"_platform_cpu_x86_64": attr.label(default = "@platforms//cpu:x86_64"),
} | {
"_clang_version_{}".format(version): attr.label(default = "//prebuilts/clang/host/linux-x86/kleaf:{}".format(version))
for version in _CLANG_VERSIONS
},
)