Skip to content
Merged
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
53 changes: 53 additions & 0 deletions internal/clang_resource_headers.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Clang resource-header discovery for hermetic Linux compile actions."""

visibility("//internal/...")

def _is_clang_resource_include(path):
"""Whether path is Clang's compiler-provided resource header directory."""
normalized = path.replace("\\", "/")
marker = "/lib/clang/"
marker_index = normalized.rfind(marker)
if marker_index < 0:
return False
suffix = normalized[marker_index + len(marker):].split("/")
return len(suffix) == 2 and bool(suffix[0]) and suffix[1] == "include"

def _has_clang_resource_include(flags):
for index in range(len(flags) - 3):
if (
flags[index] == "-Xclang" and
flags[index + 1] == "-internal-isystem" and
flags[index + 2] == "-Xclang" and
_is_clang_resource_include(flags[index + 3])
):
return True
return False

def _ensure_clang_resource_include(flags, toolchain_files):
"""Adds the unique declared Clang resource include when flags omit it."""
if _has_clang_resource_include(flags):
return flags

resource_includes = sorted({
file.path: True
for file in toolchain_files
if _is_clang_resource_include(file.path)
}.keys())
if len(resource_includes) > 1:
fail(
"selected C/C++ toolchain provides multiple Clang resource include directories: %s" %
", ".join(resource_includes),
)
if not resource_includes:
return flags
return flags + [
"-Xclang",
"-internal-isystem",
"-Xclang",
resource_includes[0],
]

clang_resource_headers = struct(
ensure_include = _ensure_clang_resource_include,
is_include = _is_clang_resource_include,
)
14 changes: 3 additions & 11 deletions internal/linux_object_groups.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ load(
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain")
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
load(":architecture_profiles.bzl", "linux_arch_values", "linux_architecture_profile_for_arch")
load(":clang_resource_headers.bzl", "clang_resource_headers")
load(
":linux_objects.bzl",
"LinuxCompileEnvironmentIndexInfo",
Expand Down Expand Up @@ -161,16 +162,6 @@ def _drop_toolchain_include(path):
"llvm++kernel_headers+linux_kernel_headers_" in path
)

def _clang_resource_include(path):
"""Whether path is Clang's compiler-provided resource header directory."""
normalized = path.replace("\\", "/")
marker = "/lib/clang/"
marker_index = normalized.rfind(marker)
if marker_index < 0:
return False
suffix = normalized[marker_index + len(marker):].split("/")
return len(suffix) == 2 and bool(suffix[0]) and suffix[1] == "include"

def _compile_flags(ctx, cc_toolchain, feature_configuration):
variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
Expand Down Expand Up @@ -199,7 +190,7 @@ def _compile_flags(ctx, cc_toolchain, feature_configuration):
resource_path = ""
if index + 3 < len(flags) and flags[index + 2] == "-Xclang":
resource_path = flags[index + 3]
if not _clang_resource_include(resource_path):
if not clang_resource_headers.is_include(resource_path):
drop_count = 3
continue
if index + 1 < len(flags) and flags[index + 1] == "-fno-cxx-modules":
Expand Down Expand Up @@ -236,6 +227,7 @@ def _compile_flags(ctx, cc_toolchain, feature_configuration):
if flag.startswith("-isystem") and _drop_toolchain_include(flag[len("-isystem"):]):
continue
out.append(flag)
out = clang_resource_headers.ensure_include(out, cc_toolchain.all_files.to_list())
if "-nostdinc" not in out:
out.append("-nostdinc")
if "-fintegrated-as" not in out:
Expand Down
18 changes: 6 additions & 12 deletions internal/linux_objects.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolch
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
load(":architecture_linking.bzl", "linux_vmlinux_link_spec")
load(":architecture_profiles.bzl", "linux_architecture_profile_for_arch")
load(":clang_resource_headers.bzl", "clang_resource_headers")
load(":host_cc_toolchain.bzl", "host_cc_toolchain_attr")
load(":kconfig.bzl", "KconfigInfo")
load(":linux_module_actions.bzl", "linux_module_actions")
Expand Down Expand Up @@ -352,7 +353,7 @@ def _linux_compile_flags(ctx, cc_toolchain, feature_configuration):
resource_path = ""
if index + 3 < len(flags) and flags[index + 2] == "-Xclang":
resource_path = flags[index + 3]
if not _linux_clang_resource_include(resource_path):
if not clang_resource_headers.is_include(resource_path):
drop_count = 3
continue
if index + 1 < len(flags) and flags[index + 1] == "-fno-cxx-modules":
Expand Down Expand Up @@ -391,6 +392,7 @@ def _linux_compile_flags(ctx, cc_toolchain, feature_configuration):
if flag.startswith("-isystem") and _linux_drop_toolchain_include(flag[len("-isystem"):]):
continue
out.append(flag)
out = clang_resource_headers.ensure_include(out, cc_toolchain.all_files.to_list())
if "-nostdinc" not in out:
out.append("-nostdinc")
if "-fintegrated-as" not in out:
Expand Down Expand Up @@ -435,16 +437,6 @@ def _linux_drop_toolchain_include(path):
"llvm++kernel_headers+linux_kernel_headers_" in path
)

def _linux_clang_resource_include(path):
"""Whether path is Clang's compiler-provided resource header directory."""
normalized = path.replace("\\", "/")
marker = "/lib/clang/"
marker_index = normalized.rfind(marker)
if marker_index < 0:
return False
suffix = normalized[marker_index + len(marker):].split("/")
return len(suffix) == 2 and bool(suffix[0]) and suffix[1] == "include"

def _cc_target_flags(ctx, cc_toolchain, feature_configuration):
flags = _linux_compile_flags(ctx, cc_toolchain, feature_configuration)
target_flags = []
Expand Down Expand Up @@ -8603,14 +8595,16 @@ def _linux_x86_bzimage(ctx, setup_bin, vmlinux_bin):

def _linux_x86_inat_tables(ctx):
opcode_map = _source_tree_file(ctx, "arch/x86/lib/x86-opcode-map.txt")
inat_h = _source_tree_file(ctx, "arch/x86/include/asm/inat.h")
out = ctx.actions.declare_file(ctx.label.name + ".obj/arch/x86/lib/inat-tables.c")
args = ctx.actions.args()
args.add("-in", opcode_map)
args.add("-inat_h", inat_h)
args.add("-out", out)
path_mapped_run(
ctx.actions,
executable = ctx.executable._insnattr,
inputs = [opcode_map],
inputs = [inat_h, opcode_map],
outputs = [out],
arguments = [args],
mnemonic = "LinuxX86InsnAttr",
Expand Down
3 changes: 3 additions & 0 deletions internal/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load(
"linux_config",
)
load(":architecture_linking_test.bzl", "architecture_linking_test_suite")
load(":clang_resource_headers_test.bzl", "clang_resource_headers_test")
load(":compact_generator_test.bzl", "compact_generator_test_suite")
load(":config_validation_test.bzl", "config_validation_test_suite")
load(":host_cc_toolchain_test.bzl", "host_cc_toolchain_test")
Expand All @@ -25,6 +26,8 @@ compact_generator_test_suite(name = "compact_generator_tests")

architecture_linking_test_suite(name = "architecture_linking_tests")

clang_resource_headers_test(name = "clang_resource_headers_test")

action_group_validation_test(name = "action_group_validation_test")

config_validation_test_suite(name = "config_validation_tests")
Expand Down
54 changes: 54 additions & 0 deletions internal/tests/clang_resource_headers_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Unit tests for Clang resource-header discovery."""

load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
load("//internal:clang_resource_headers.bzl", "clang_resource_headers")

visibility("private")

def _clang_resource_headers_test_impl(ctx):
env = unittest.begin(ctx)
resource = "bazel-out/k8-fastbuild/bin/external/llvm/lib/clang/21/include"
fallback = clang_resource_headers.ensure_include(
["--target=aarch64-linux-gnu"],
[struct(path = resource)],
)
asserts.equals(
env,
[
"--target=aarch64-linux-gnu",
"-Xclang",
"-internal-isystem",
"-Xclang",
resource,
],
fallback,
)

existing = [
"-Xclang",
"-internal-isystem",
"-Xclang",
resource,
"-nostdinc",
]
asserts.equals(
env,
existing,
clang_resource_headers.ensure_include(
existing,
[struct(path = "external/other/lib/clang/20/include")],
),
)
asserts.equals(
env,
["-nostdinc"],
clang_resource_headers.ensure_include(
["-nostdinc"],
[struct(path = "external/llvm/bin/clang")],
),
)
asserts.true(env, clang_resource_headers.is_include("C:\\llvm\\lib\\clang\\21\\include"))
asserts.false(env, clang_resource_headers.is_include("C:\\llvm\\lib\\clang\\21\\include\\arm_neon.h"))
return unittest.end(env)

clang_resource_headers_test = unittest.make(_clang_resource_headers_test_impl)