blob: 853f73cbdc0fffbc7845546b1a530a1540a2211f [file] [log] [blame]
# Copyright (C) 2022 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.
"""Utilities for handling `--cache_dir`."""
load("@bazel_skylib//lib:shell.bzl", "shell")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
visibility("//build/kernel/kleaf/impl/...")
_FLOCK_FD = 0x41F # KLF
def _get_flock_cmd(ctx):
if ctx.attr._debug_cache_dir_conflict[BuildSettingInfo].value == "none":
pre_cmd = ""
post_cmd = ""
return struct(
pre_cmd = pre_cmd,
post_cmd = post_cmd,
)
if ctx.attr._debug_cache_dir_conflict[BuildSettingInfo].value not in ("detect", "resolve"):
fail("{}: {} has unexpected value {}. Must be one of none, detect, resolve.".format(
ctx.label,
ctx.attr._debug_cache_dir_conflict.label,
ctx.attr._debug_cache_dir_conflict[BuildSettingInfo].value,
))
lock_args = ""
if ctx.attr._debug_cache_dir_conflict[BuildSettingInfo].value == "detect":
lock_args = "-n"
pre_cmd = """
(
echo "DEBUG: [$(date -In)] {label}: Locking ${{COMMON_OUT_DIR}}/kleaf_config_tags.json before using" >&2
if ! flock -x {lock_args} {flock_fd}; then
echo "ERROR: [$(date -In)] {label}: Unable to lock ${{COMMON_OUT_DIR}}/kleaf_config_tags.json." >&2
echo " Please file a bug! See build/kernel/kleaf/docs/errors.md" >&2
exit 1
fi
""".format(
label = ctx.label,
lock_args = lock_args,
flock_fd = _FLOCK_FD,
)
post_cmd = """
) {flock_fd}<"${{COMMON_OUT_DIR}}/kleaf_config_tags.json"
echo "DEBUG: [$(date -In)] {label}: Unlocked ${{COMMON_OUT_DIR}}/kleaf_config_tags.json after using" >&2
""".format(
label = ctx.label,
flock_fd = _FLOCK_FD,
)
return struct(
pre_cmd = pre_cmd,
post_cmd = post_cmd,
)
def _get_step(ctx, common_config_tags, symlink_name):
"""Returns a step for caching the output directory.
Args:
ctx: ctx
common_config_tags: from `kernel_env[KernelEnvAttrInfo]`
symlink_name: name of the "last" symlink
Returns:
A struct with these fields:
* inputs
* tools
* cmd
* outputs
* post_cmd
"""
# Use a local cache directory for ${OUT_DIR} so that, even when this _kernel_build
# target needs to be rebuilt, we are using $OUT_DIR from previous invocations. This
# boosts --config=local builds. See (b/235632059).
cache_dir_cmd = ""
post_cmd = ""
inputs = []
tools = []
if ctx.attr._config_is_local[BuildSettingInfo].value:
if not ctx.attr._cache_dir[BuildSettingInfo].value:
fail("--config=local requires --cache_dir.")
tools.append(ctx.executable._cache_dir_config_tags)
inputs.append(common_config_tags)
flock_ret = _get_flock_cmd(ctx)
cache_dir_cmd = """
KLEAF_CONFIG_TAGS_TMP=$(mktemp kleaf_config_tags.json.XXXXXX)
# cache_dir_config_tags.py requires --dest to not exist, otherwise it compares
# and fails.
rm -f "${{KLEAF_CONFIG_TAGS_TMP}}"
# Add label of this target.
{cache_dir_config_tags} \\
--base {common_config_tags} \\
--target {label} \\
--dest "${{KLEAF_CONFIG_TAGS_TMP}}"
export OUT_DIR_SUFFIX=$(cat ${{KLEAF_CONFIG_TAGS_TMP}} | sha1sum -b | cut -c-8)
export COMMON_OUT_DIR={cache_dir}/${{OUT_DIR_SUFFIX}}
export OUT_DIR=${{COMMON_OUT_DIR}}/${{KERNEL_DIR}}
mkdir -p "${{OUT_DIR}}"
# Reconcile differences between expected file and target file, if any,
# to prevent hash collision.
{cache_dir_config_tags} \\
--base "${{KLEAF_CONFIG_TAGS_TMP}}" \\
--dest "${{COMMON_OUT_DIR}}/kleaf_config_tags.json"
rm -f "${{KLEAF_CONFIG_TAGS_TMP}}"
unset KLEAF_CONFIG_TAGS_TMP
# Append more HOSTLDFLAGS/HOSTRUSTFLAGS now that OUT_DIR changes. Binaries built with these flags
# can be executed with or without the sandbox.
kleaf_internal_eval_ldflags
kleaf_internal_eval_rust_flags
{flock_pre_cmd}
""".format(
label = shell.quote(str(ctx.label)),
cache_dir_config_tags = ctx.executable._cache_dir_config_tags.path,
cache_dir = ctx.attr._cache_dir[BuildSettingInfo].value,
common_config_tags = common_config_tags.path,
flock_pre_cmd = flock_ret.pre_cmd,
)
post_cmd = """
ln -sfT ${{OUT_DIR_SUFFIX}} {cache_dir}/last_{symlink_name}
{flock_post_cmd}
""".format(
cache_dir = ctx.attr._cache_dir[BuildSettingInfo].value,
symlink_name = symlink_name,
flock_post_cmd = flock_ret.post_cmd,
)
return struct(
inputs = inputs,
tools = tools,
cmd = cache_dir_cmd,
outputs = [],
post_cmd = post_cmd,
)
def _attrs():
return {
"_config_is_local": attr.label(default = "//build/kernel/kleaf:config_local"),
"_cache_dir": attr.label(default = "//build/kernel/kleaf:cache_dir"),
"_cache_dir_config_tags": attr.label(
default = "//build/kernel/kleaf/impl:cache_dir_config_tags",
executable = True,
cfg = "exec",
),
"_debug_cache_dir_conflict": attr.label(
default = "//build/kernel/kleaf:debug_cache_dir_conflict",
),
}
cache_dir = struct(
get_step = _get_step,
attrs = _attrs,
)