Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.3.0
8.5.1
139 changes: 114 additions & 25 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,109 @@ imagefs.toolchain(
)
use_repo(imagefs, "score_qnx_aarch64_ifs_toolchain", "score_qnx_x86_64_ifs_toolchain")

bazel_dep(name = "rules_distroless", version = "0.6.2", dev_dependency = True)
git_override(
module_name = "rules_distroless",
commit = "43dd94fd06e209a0d802a6a8543d42b74c1d8473",
remote = "https://github.com/LittleHuba/rules_distroless.git"
)

apt = use_extension(
"@rules_distroless//apt:extensions.bzl",
"apt",
dev_dependency = True,
)
apt.sources_list(
architectures = [
"amd64",
"arm64",
],
components = ["main"],
suites = [
"noble",
"noble-security",
"noble-updates",
],
types = ["deb"],
uris = ["https://snapshot.ubuntu.com/ubuntu/20260401T000000Z"],
)
apt.sources_list(
architectures = [
"amd64",
"arm64",
],
components = ["universe"],
suites = [
"noble",
"noble-security",
"noble-updates",
],
types = ["deb"],
uris = [
"https://archive.ubuntu.com/ubuntu",
"https://ports.ubuntu.com/ubuntu-ports",
],
)
apt.install(
dependency_set = "ubuntu24_04_sysroot",
packages = [
"libc6", # Core C/POSIX
"libc6-dev", # Core C/POSIX
"linux-libc-dev", # Core C/POSIX
"libstdc++6", # C++ standard library runtime
"libstdc++-13-dev", # C++ standard library headers
"libgcc-s1", # Exception unwinding
"libatomic1", # Non-lock-free atomics support
],
suites = [
"noble",
"noble-security",
"noble-updates",
],
mergedusr = True,
unpack = True,
)
apt.install(
dependency_set = "ubuntu24_04_integration_testing",
packages = [
"bash",
"binutils", # provides addr2line, required for backtraces in sanitizers
"coreutils", # for commands like `ls`
"libatomic1",
"libstdc++6",
],
suites = [
"noble",
"noble-security",
"noble-updates",
],
mergedusr = True,
)
apt.install(
dependency_set = "coverage_runtime_sysroot",
packages = [
"bash",
"coreutils",
"fakechroot", # Mandatory for exec_in_sysroot rule
"findutils",
"lcov",
"libcapture-tiny-perl",
"libdatetime-perl",
"libtimedate-perl",
"perl",
"zip",
],
suites = [
"noble",
"noble-security",
"noble-updates",
],
mergedusr = True,
unpack = True,
)
apt.lock(into = ":rules_distroless.lock.json")
use_repo(apt, "ubuntu24_04_sysroot", "ubuntu24_04_integration_testing", "coverage_runtime_sysroot")

bazel_dep(name = "toolchains_llvm", version = "1.5.0", dev_dependency = True)

llvm = use_extension(
Expand Down Expand Up @@ -173,6 +276,17 @@ llvm.toolchain(
"-latomic",
]},
llvm_version = "19.1.7",
stdlib = {"": "stdc++"},
)
llvm.sysroot(
name = "llvm_toolchain",
label = "@ubuntu24_04_sysroot//unpack_amd64",
targets = ["linux-x86_64"],
)
llvm.sysroot(
name = "llvm_toolchain",
label = "@ubuntu24_04_sysroot//unpack_arm64",
targets = ["linux-aarch64"],
)
use_repo(llvm, "llvm_toolchain")

Expand Down Expand Up @@ -210,17 +324,6 @@ use_repo(

# We use here a pre-compiled fully static and hermetic clang_format binary
# and not the one provided by llvm_toolchain, because the one from llvm_toolchain is not fully hermetic (and different version for now)
###############################################################################
# lcov deb package (provides genhtml + lcov for coverage HTML reports)
###############################################################################
deb = use_repo_rule("@download_utils//download/deb:defs.bzl", "download_deb")

deb(
name = "lcov_deb",
dev_dependency = True,
integrity = "sha256-Ip14IkKavqBtkQ7mh6AXzr/6YyHpvSAZ0veMmw1+N80=",
urls = ["https://archive.ubuntu.com/ubuntu/pool/universe/l/lcov/lcov_2.0-4ubuntu2_all.deb"],
)

download_file = use_repo_rule("@download_utils//download/file:defs.bzl", "download_file")

Expand Down Expand Up @@ -318,20 +421,6 @@ pip.parse(
use_repo(pip, "lobster_dependencies")

bazel_dep(name = "rules_oci", version = "2.2.7", dev_dependency = True)
bazel_dep(name = "rules_distroless", version = "0.6.2", dev_dependency = True)

apt = use_extension(
"@rules_distroless//apt:extensions.bzl",
"apt",
dev_dependency = True,
)
apt.install(
name = "ubuntu24_04",
lock = "@@//quality/integration_testing/environments/ubuntu24_04_docker:ubuntu24_04.lock.json",
manifest = "//quality/integration_testing/environments/ubuntu24_04_docker:ubuntu24_04.yaml",
mergedusr = True,
)
use_repo(apt, "ubuntu24_04")

bazel_dep(name = "rules_pkg", version = "1.2.0", dev_dependency = True)

Expand Down
19 changes: 19 additions & 0 deletions bazel/rules/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@rules_shell//shell:sh_binary.bzl", "sh_binary")

sh_binary(
name = "exec_in_sysroot",
srcs = ["exec_in_sysroot.sh"],
)
154 changes: 154 additions & 0 deletions bazel/rules/exec_in_sysroot.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

def _merge_default_and_data_runfiles(target, runfiles):
default_info = target[DefaultInfo]
if default_info.default_runfiles:
runfiles = runfiles.merge(default_info.default_runfiles)
if default_info.data_runfiles:
runfiles = runfiles.merge(default_info.data_runfiles)
return runfiles

def _exec_in_sysroot_impl(ctx):
if len(ctx.files.sysroot) != 1:
fail("sysroot '{}' must provide exactly one directory artifact".format(ctx.attr.sysroot.label))

sysroot = ctx.files.sysroot[0]
sysroot_runfiles_path = sysroot.short_path
if sysroot_runfiles_path.startswith("../"):
sysroot_runfiles_path = sysroot_runfiles_path[3:]

executable_file = ctx.executable.executable
if executable_file == None:
fail("executable must provide a runnable target")
executable_short_path = executable_file.short_path
if executable_short_path.startswith("../"):
executable_runfiles_path = executable_short_path[3:]
else:
executable_runfiles_path = ctx.workspace_name + "/" + executable_short_path

out = ctx.actions.declare_file(ctx.label.name)

# Build exclude paths string - colon-separated list
exclude_paths = ":".join(ctx.attr.exclude_paths) if ctx.attr.exclude_paths else ""

wrapper_script = """#!/usr/bin/env bash
set -euo pipefail

# --- begin runfiles.bash initialization ---
if [[ ! -d "${{RUNFILES_DIR:-/dev/null}}" && ! -f "${{RUNFILES_MANIFEST_FILE:-/dev/null}}" ]]; then
if [[ -f "$0.runfiles_manifest" ]]; then
export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
elif [[ -f "$0.runfiles/MANIFEST" ]]; then
export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
export RUNFILES_DIR="$0.runfiles"
fi
fi
if [[ -f "${{RUNFILES_DIR:-/dev/null}}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
source "${{RUNFILES_DIR}}/bazel_tools/tools/bash/runfiles/runfiles.bash"
elif [[ -f "${{RUNFILES_MANIFEST_FILE:-/dev/null}}" ]]; then
source "$(grep -m1 '^bazel_tools/tools/bash/runfiles/runfiles.bash ' "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
else
echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
exit 1
fi
# --- end runfiles.bash initialization ---

FAKECHROOT_WRAPPER="$(rlocation '{wrapper_short_path}')"
SYSROOT_DIR="$(rlocation '{sysroot_short_path}')"
EXECUTABLE_FILE="$(rlocation '{executable_runfiles_path}')"

if [[ -z "${{FAKECHROOT_WRAPPER}}" || ! -x "${{FAKECHROOT_WRAPPER}}" ]]; then
echo "ERROR: could not resolve fakechroot wrapper: {wrapper_short_path}" >&2
exit 1
fi

if [[ -z "${{SYSROOT_DIR}}" || ! -d "${{SYSROOT_DIR}}" ]]; then
echo "ERROR: could not resolve sysroot directory: {sysroot_short_path}" >&2
exit 1
fi

if [[ ! -x "${{SYSROOT_DIR}}/usr/bin/fakechroot" ]]; then
echo "ERROR: sysroot does not provide /usr/bin/fakechroot: ${{SYSROOT_DIR}}" >&2
exit 1
fi

if [[ -z "${{EXECUTABLE_FILE}}" || ! -f "${{EXECUTABLE_FILE}}" ]]; then
echo "ERROR: could not resolve executable target: {executable_runfiles_path}" >&2
exit 1
fi

export SYSROOT_DIR
if [[ -n "{exclude_paths}" ]]; then
export FAKECHROOT_EXCLUDE_PATH="{exclude_paths}"
fi

# The executable lives in host runfiles, not in the sysroot. Exclude its path so
# chrooted execution can still open and execute it.
EXECUTABLE_DIR="$(dirname "${{EXECUTABLE_FILE}}")"
if [[ -n "${{FAKECHROOT_EXCLUDE_PATH:-}}" ]]; then
export FAKECHROOT_EXCLUDE_PATH="${{EXECUTABLE_DIR}}:${{EXECUTABLE_FILE}}:${{FAKECHROOT_EXCLUDE_PATH}}"
else
export FAKECHROOT_EXCLUDE_PATH="${{EXECUTABLE_DIR}}:${{EXECUTABLE_FILE}}"
fi

exec "${{FAKECHROOT_WRAPPER}}" "${{EXECUTABLE_FILE}}" "$@"
""".format(
wrapper_short_path = ctx.workspace_name + "/" + ctx.executable._fakechroot_wrapper.short_path,
sysroot_short_path = sysroot_runfiles_path,
executable_runfiles_path = executable_runfiles_path,
exclude_paths = exclude_paths,
)
ctx.actions.write(output = out, content = wrapper_script, is_executable = True)

runfiles = ctx.runfiles(
files = [out, ctx.executable._fakechroot_wrapper, sysroot, executable_file] + ctx.files._bash_runfiles,
)
runfiles = _merge_default_and_data_runfiles(ctx.attr.executable, runfiles)
runfiles = _merge_default_and_data_runfiles(ctx.attr._fakechroot_wrapper, runfiles)
runfiles = _merge_default_and_data_runfiles(ctx.attr._bash_runfiles, runfiles)
runfiles = _merge_default_and_data_runfiles(ctx.attr.sysroot, runfiles)

return [DefaultInfo(
executable = out,
files = depset([out]),
runfiles = runfiles,
)]


exec_in_sysroot = rule(
implementation = _exec_in_sysroot_impl,
executable = True,
attrs = {
"executable": attr.label(mandatory = True, executable = True, cfg = "exec"),
"sysroot": attr.label(mandatory = True, allow_files = True),
"exclude_paths": attr.string_list(
default = [],
doc = "Paths to exclude from fakechroot (colon-separated in the env var)",
),
"_bash_runfiles": attr.label(
default = Label("@bazel_tools//tools/bash/runfiles"),
allow_files = True,
),
"_fakechroot_wrapper": attr.label(
default = Label("//bazel/rules:exec_in_sysroot"),
executable = True,
cfg = "exec",
),
},
doc = """
Produces an executable wrapper that runs a given executable target using the supplied sysroot.
The wrapped executable runs within fakechroot, allowing access to sysroot tools.
""",
)
Loading
Loading