blob: e142de33c8ef5d8d0bd8d6ef674b85855d246c9f [file] [log] [blame] [edit]
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
load("@rules_pkg//pkg:providers.bzl", "PackageArtifactInfo")
load("//bazel/transitions:primordial.bzl", "primordial_transition")
load(":common.bzl", "BinaryPackageInfo", "BinaryPackageSetInfo", "OverlaySetInfo", "SDKInfo")
load(":install_deps.bzl", "install_deps")
def _sdk_from_archive_impl(ctx):
output_prefix = ctx.attr.out or ctx.attr.name
output_root = ctx.actions.declare_directory(output_prefix)
output_log = ctx.actions.declare_file(output_prefix + ".log")
output_profile = ctx.actions.declare_file(output_prefix + ".profile.json")
args = ctx.actions.args()
args.add_all([
"--log",
output_log,
"--profile",
output_profile,
ctx.executable._sdk_from_archive,
"--input",
ctx.file.src,
"--output",
output_root,
], expand_directories = False)
inputs = [ctx.executable._sdk_from_archive, ctx.file.src]
outputs = [output_root, output_log, output_profile]
ctx.actions.run(
inputs = inputs,
outputs = outputs,
executable = ctx.executable._action_wrapper,
tools = [ctx.executable._sdk_from_archive],
arguments = [args],
mnemonic = "SdkFromArchive",
progress_message = ctx.attr.progress_message,
)
return [
DefaultInfo(files = depset([output_root])),
OutputGroupInfo(
logs = depset([output_log]),
traces = depset([output_profile]),
),
SDKInfo(
layers = [output_root],
packages = depset(),
),
]
sdk_from_archive = rule(
implementation = _sdk_from_archive_impl,
attrs = {
"out": attr.string(
doc = "Output directory name. Defaults to the target name.",
),
"progress_message": attr.string(
default = "Extracting SDK archive",
),
"src": attr.label(
mandatory = True,
allow_single_file = True,
),
"_action_wrapper": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/action_wrapper"),
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
"_sdk_from_archive": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/sdk_from_archive"),
),
},
cfg = primordial_transition,
)
def _sdk_update_impl(ctx):
output_prefix = ctx.attr.out or ctx.attr.name
output_root = ctx.actions.declare_directory(output_prefix)
output_log = ctx.actions.declare_file(output_prefix + ".log")
output_profile = ctx.actions.declare_file(output_prefix + ".profile.json")
args = ctx.actions.args()
args.add_all([
"--log",
output_log,
"--profile",
output_profile,
ctx.executable._sdk_update,
"--output",
output_root,
], expand_directories = False)
base_sdk = ctx.attr.base[SDKInfo]
layer_inputs = base_sdk.layers
args.add_all(layer_inputs, format_each = "--layer=%s", expand_directories = False)
args.add_all(ctx.files.extra_tarballs, format_each = "--install-tarball=%s")
inputs = depset(
[ctx.executable._sdk_update] + layer_inputs + ctx.files.extra_tarballs,
)
outputs = [output_root, output_log, output_profile]
ctx.actions.run(
inputs = inputs,
outputs = outputs,
executable = ctx.executable._action_wrapper,
tools = [ctx.executable._sdk_update],
arguments = [args],
execution_requirements = {
# Disable sandbox to avoid creating a symlink forest.
# This does not affect hermeticity since sdk_update runs in a container.
"no-sandbox": "",
# Send SIGTERM instead of SIGKILL on user interruption.
"supports-graceful-termination": "",
},
mnemonic = "SdkUpdate",
progress_message = "Building %{label}",
)
return [
DefaultInfo(files = depset([output_root])),
OutputGroupInfo(
logs = depset([output_log]),
traces = depset([output_profile]),
),
SDKInfo(
layers = base_sdk.layers + [output_root],
packages = base_sdk.packages,
),
]
sdk_update = rule(
implementation = _sdk_update_impl,
attrs = {
"base": attr.label(
mandatory = True,
providers = [SDKInfo],
),
"extra_tarballs": attr.label_list(
allow_files = True,
),
"out": attr.string(
doc = "Output directory name. Defaults to the target name.",
),
"progress_message": attr.string(
doc = """
Progress message for this target.
If the message contains `{dep_count}' it will be replaced with the
total number of dependencies that need to be installed.
""",
default = "Updating SDK",
),
"_action_wrapper": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/action_wrapper"),
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
"_sdk_update": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/sdk_update"),
),
},
cfg = primordial_transition,
)
def _sdk_install_deps_impl(ctx):
sdk = ctx.attr.base[SDKInfo]
install_set = depset(
transitive = [dep[BinaryPackageSetInfo].packages for dep in ctx.attr.target_deps],
order = "postorder",
)
deps = install_deps(
ctx = ctx,
output_prefix = ctx.attr.out or ctx.attr.name,
board = ctx.attr.board,
sdk = sdk,
overlays = ctx.attr.overlays[OverlaySetInfo],
portage_configs = ctx.files.portage_config,
install_set = install_set,
executable_action_wrapper = ctx.executable._action_wrapper,
executable_fast_install_packages =
ctx.executable._fast_install_packages,
progress_message = ctx.attr.progress_message,
)
layers = deps.sparse_layers
return [
DefaultInfo(files = depset(layers)),
OutputGroupInfo(
logs = depset([deps.log_file]),
traces = depset([deps.trace_file]),
),
SDKInfo(
layers = sdk.layers + layers,
packages = depset(transitive = [sdk.packages, install_set]),
),
]
sdk_install_deps = rule(
implementation = _sdk_install_deps_impl,
attrs = {
"base": attr.label(
doc = """
Base SDK to derive a new SDK from.
""",
mandatory = True,
providers = [SDKInfo],
),
"board": attr.string(
doc = """
If set, the packages are installed into the board's sysroot,
otherwise they are installed into the host's sysroot.
""",
),
"out": attr.string(
doc = "Output directory name. Defaults to the target name.",
),
"overlays": attr.label(
providers = [OverlaySetInfo],
mandatory = True,
),
"portage_config": attr.label_list(
providers = [PackageArtifactInfo],
doc = """
The portage config for the host and optionally the target. This should
at minimum contain a make.conf file.
""",
mandatory = True,
),
"progress_message": attr.string(
doc = """
Progress message for this target.
If the message contains `{dep_count}' it will be replaced with the
total number of dependencies that need to be installed.
""",
default = "Installing {dep_count} packages into %{label}",
),
"target_deps": attr.label_list(
doc = """
Target packages to install in the SDK.
""",
providers = [BinaryPackageSetInfo],
),
"_action_wrapper": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/action_wrapper"),
),
"_fast_install_packages": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/fast_install_packages"),
),
},
)
def _sdk_extend_impl(ctx):
sdk = ctx.attr.base[SDKInfo]
sdk = SDKInfo(
layers = sdk.layers + ctx.files.extra_tarballs,
packages = sdk.packages,
)
return [
# We don't return any files since this rule doesn't create any.
DefaultInfo(),
sdk,
]
sdk_extend = rule(
doc = "Adds extra tarballs to the SDK",
implementation = _sdk_extend_impl,
provides = [SDKInfo],
attrs = {
"base": attr.label(
doc = """
Base SDK to derive a new SDK from.
""",
mandatory = True,
providers = [SDKInfo],
),
"extra_tarballs": attr.label_list(
allow_files = True,
mandatory = True,
doc = """
Extra files to layer onto the base SDK.
""",
),
},
)
def _sdk_install_glibc_impl(ctx):
output_prefix = ctx.attr.out or ctx.attr.name
output_root = ctx.actions.declare_directory(output_prefix)
output_log = ctx.actions.declare_file(output_prefix + ".log")
output_profile = ctx.actions.declare_file(output_prefix + ".profile.json")
args = ctx.actions.args()
args.add_all([
"--log",
output_log,
"--profile",
output_profile,
ctx.executable._sdk_install_glibc,
"--output",
output_root,
"--board",
ctx.attr.board,
], expand_directories = False)
base_sdk = ctx.attr.base[SDKInfo]
layer_inputs = base_sdk.layers
args.add_all(layer_inputs, format_each = "--layer=%s", expand_directories = False)
glibc = ctx.attr.glibc[BinaryPackageInfo].file
args.add("--glibc", glibc)
inputs = depset(
[ctx.executable._sdk_install_glibc] + layer_inputs + [glibc],
)
outputs = [output_root, output_log, output_profile]
ctx.actions.run(
inputs = inputs,
outputs = outputs,
executable = ctx.executable._action_wrapper,
tools = [ctx.executable._sdk_install_glibc],
arguments = [args],
execution_requirements = {
# Disable sandbox to avoid creating a symlink forest.
# This does not affect hermeticity since sdk_install_glibc runs in a container.
"no-sandbox": "",
# Send SIGTERM instead of SIGKILL on user interruption.
"supports-graceful-termination": "",
},
mnemonic = "SdkInstallGlibc",
progress_message = "Installing cross glibc into %{label}",
)
return [
DefaultInfo(files = depset([output_root])),
OutputGroupInfo(
logs = depset([output_log]),
traces = depset([output_profile]),
),
SDKInfo(
layers = base_sdk.layers + [output_root],
packages = depset(
[ctx.attr.glibc[BinaryPackageInfo]],
transitive = [base_sdk.packages],
),
),
]
sdk_install_glibc = rule(
implementation = _sdk_install_glibc_impl,
attrs = {
"base": attr.label(
mandatory = True,
providers = [SDKInfo],
),
"board": attr.string(
doc = "The cross-* package is installed into the board's sysroot.",
mandatory = True,
),
"glibc": attr.label(
doc = "The cross-*-cros-linux-gnu/glibc package to install",
mandatory = True,
providers = [BinaryPackageInfo],
),
"out": attr.string(
doc = "Output directory name. Defaults to the target name.",
),
"_action_wrapper": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/action_wrapper"),
),
"_sdk_install_glibc": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/sdk_install_glibc"),
),
},
)
def _remote_toolchain_inputs(ctx):
output_prefix = ctx.attr.name
output = ctx.actions.declare_file(output_prefix + ".tar.zst")
output_log = ctx.actions.declare_file(output_prefix + ".log")
output_profile = ctx.actions.declare_file(output_prefix + ".profile.json")
args = ctx.actions.args()
args.add_all([
"--log",
output_log,
"--profile",
output_profile,
ctx.executable._generate_reclient_inputs,
"--output",
output,
], expand_directories = False)
layer_inputs = ctx.attr.sdk[SDKInfo].layers + [ctx.file._chromite_src]
args.add_all(layer_inputs, format_each = "--layer=%s", expand_directories = False)
inputs = depset(
[ctx.executable._generate_reclient_inputs] + layer_inputs,
)
outputs = [output, output_log, output_profile]
ctx.actions.run(
inputs = inputs,
outputs = outputs,
executable = ctx.executable._action_wrapper,
tools = [ctx.executable._generate_reclient_inputs],
arguments = [args],
execution_requirements = {
# Disable sandbox to avoid creating a symlink forest.
# This does not affect hermeticity since generate_reclient_inputs runs in a container.
"no-sandbox": "",
# Send SIGTERM instead of SIGKILL on user interruption.
"supports-graceful-termination": "",
},
mnemonic = "GenerateReclientInputs",
progress_message = "Building %{label}",
)
return [
DefaultInfo(files = depset([output])),
OutputGroupInfo(
logs = depset([output_log]),
traces = depset([output_profile]),
),
]
remote_toolchain_inputs = rule(
implementation = _remote_toolchain_inputs,
attrs = {
"sdk": attr.label(
doc = "The SDK to generate the remote_toolchain_inputs file for.",
mandatory = True,
providers = [SDKInfo],
),
"_action_wrapper": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/action_wrapper"),
),
"_chromite_src": attr.label(
default = Label("@chromite//:src"),
allow_single_file = True,
),
"_generate_reclient_inputs": attr.label(
executable = True,
cfg = "exec",
default = Label("//bazel/portage/bin/generate_reclient_inputs"),
),
},
)