Skip to content

Commit 087976d

Browse files
committed
Define toolchain options to use a host clang executable.
These toolchains are registered with lower priority than the downloaded prebuilt LLVM/clang, but can be selected using the `--extra-toolchains` flag, e.g. ``` bazel build //cuttlefish/package:cvd \ --extra_toolchains=//toolchain:linux_local_clang_19 ``` Note that if the clang executable for the requested version is missing, the toolchain will silently be excluded from toolchain resolution, so requesting `//toolchain:linux_local_clang_11` on a system without /usr/bin/clang-11 will fall through to the next supported toolchain following the normal resolution order. See https://bazel.build/extending/toolchains#toolchain-resolution Bug: b/407854179
1 parent 82d9441 commit 087976d

File tree

5 files changed

+372
-2
lines changed

5 files changed

+372
-2
lines changed

base/cvd/MODULE.bazel

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,51 @@ git_override(
4343
remote = "https://github.com/mikael-s-persson/bazel-compile-commands-extractor",
4444
)
4545

46-
# Configure and register the toolchain.
4746
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
4847
llvm.toolchain(
4948
llvm_version = "18.1.8",
5049
)
5150

5251
use_repo(llvm, "llvm_toolchain")
5352

54-
register_toolchains("@llvm_toolchain//:all")
53+
file_detector = use_repo_rule("//toolchain:file_detector.bzl", "file_detector")
54+
55+
file_detector(
56+
name = "clang_detector",
57+
files = {
58+
"/usr/bin/clang-11": "clang_11",
59+
"/usr/bin/clang-12": "clang_12",
60+
"/usr/bin/clang-13": "clang_13",
61+
"/usr/bin/clang-14": "clang_14",
62+
"/usr/bin/clang-15": "clang_15",
63+
"/usr/bin/clang-16": "clang_16",
64+
"/usr/bin/clang-17": "clang_17",
65+
"/usr/bin/clang-18": "clang_18",
66+
"/usr/bin/clang-19": "clang_19",
67+
},
68+
)
69+
70+
# The first toolchain that satisfies platform constraints is chosen.
71+
# Alternatively, a specific toolchain can be chosen with the
72+
# `--extra_toolchains` flag, e.g.
73+
# ```
74+
# bazel build //cuttlefish/package:cvd \
75+
# --extra_toolchains=//toolchain:linux_local_clang_19
76+
# ```
77+
#
78+
# For more information, see https://bazel.build/extending/toolchains
79+
register_toolchains(
80+
"@llvm_toolchain//:all", # TODO: b/407854179 - demote after testing others
81+
"//toolchain:linux_local_clang_19",
82+
"//toolchain:linux_local_clang_18",
83+
"//toolchain:linux_local_clang_17",
84+
"//toolchain:linux_local_clang_16",
85+
"//toolchain:linux_local_clang_15",
86+
"//toolchain:linux_local_clang_14",
87+
"//toolchain:linux_local_clang_13",
88+
"//toolchain:linux_local_clang_12",
89+
"//toolchain:linux_local_clang_11",
90+
)
5591

5692
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
5793
python.toolchain(

base/cvd/toolchain/BUILD.bazel

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load(":cc_toolchain_macro.bzl", "linux_local_clang")
4+
5+
filegroup(name = "empty")
6+
7+
linux_local_clang(
8+
name = "linux_local_clang_19",
9+
exec_compatible_with = [
10+
"@clang_detector//:clang_19_present",
11+
"@platforms//os:linux",
12+
],
13+
version = 19,
14+
)
15+
16+
linux_local_clang(
17+
name = "linux_local_clang_18",
18+
exec_compatible_with = [
19+
"@clang_detector//:clang_18_present",
20+
"@platforms//os:linux",
21+
],
22+
version = 18,
23+
)
24+
25+
linux_local_clang(
26+
name = "linux_local_clang_17",
27+
exec_compatible_with = [
28+
"@clang_detector//:clang_17_present",
29+
"@platforms//os:linux",
30+
],
31+
version = 17,
32+
)
33+
34+
linux_local_clang(
35+
name = "linux_local_clang_16",
36+
exec_compatible_with = [
37+
"@clang_detector//:clang_16_present",
38+
"@platforms//os:linux",
39+
],
40+
version = 16,
41+
)
42+
43+
linux_local_clang(
44+
name = "linux_local_clang_15",
45+
exec_compatible_with = [
46+
"@clang_detector//:clang_15_present",
47+
"@platforms//os:linux",
48+
],
49+
version = 15,
50+
)
51+
52+
linux_local_clang(
53+
name = "linux_local_clang_14",
54+
exec_compatible_with = [
55+
"@clang_detector//:clang_14_present",
56+
"@platforms//os:linux",
57+
],
58+
version = 14,
59+
)
60+
61+
linux_local_clang(
62+
name = "linux_local_clang_13",
63+
exec_compatible_with = [
64+
"@clang_detector//:clang_13_present",
65+
"@platforms//os:linux",
66+
],
67+
version = 13,
68+
)
69+
70+
linux_local_clang(
71+
name = "linux_local_clang_12",
72+
exec_compatible_with = [
73+
"@clang_detector//:clang_12_present",
74+
"@platforms//os:linux",
75+
],
76+
version = 12,
77+
)
78+
79+
linux_local_clang(
80+
name = "linux_local_clang_11",
81+
exec_compatible_with = [
82+
"@clang_detector//:clang_11_present",
83+
"@platforms//os:linux",
84+
],
85+
version = 11,
86+
)
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
2+
load(
3+
"@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
4+
"feature",
5+
"flag_group",
6+
"flag_set",
7+
"tool_path",
8+
)
9+
10+
all_link_actions = [
11+
ACTION_NAMES.cpp_link_executable,
12+
ACTION_NAMES.cpp_link_dynamic_library,
13+
ACTION_NAMES.cpp_link_nodeps_dynamic_library,
14+
]
15+
16+
# Relevant documentation:
17+
# - https://bazel.build/rules/lib/providers/CcToolchainInfo
18+
# - https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info
19+
# - https://bazel.build/tutorials/ccp-toolchain-config
20+
def _impl(ctx):
21+
tool_paths = [
22+
tool_path(
23+
name = "gcc",
24+
path = "/usr/bin/clang-%d" % ctx.attr.version,
25+
),
26+
tool_path(
27+
name = "ld",
28+
path = "/usr/bin/ld",
29+
),
30+
tool_path(
31+
name = "ar",
32+
path = "/usr/bin/ar",
33+
),
34+
tool_path(
35+
name = "cpp",
36+
path = "/bin/false",
37+
),
38+
tool_path(
39+
name = "gcov",
40+
path = "/bin/false",
41+
),
42+
tool_path(
43+
name = "nm",
44+
path = "/bin/false",
45+
),
46+
tool_path(
47+
name = "objdump",
48+
path = "/bin/false",
49+
),
50+
tool_path(
51+
name = "strip",
52+
path = "/bin/false",
53+
),
54+
]
55+
56+
features = [
57+
feature(
58+
name = "default_linker_flags",
59+
enabled = True,
60+
flag_sets = [
61+
flag_set(
62+
actions = [ACTION_NAMES.cpp_compile],
63+
flag_groups = ([
64+
flag_group(
65+
flags = [
66+
"-fPIC",
67+
],
68+
),
69+
]),
70+
),
71+
flag_set(
72+
actions = all_link_actions,
73+
flag_groups = ([
74+
flag_group(
75+
flags = [
76+
"-lm",
77+
"-lstdc++",
78+
],
79+
),
80+
]),
81+
),
82+
],
83+
),
84+
]
85+
86+
return cc_common.create_cc_toolchain_config_info(
87+
ctx = ctx,
88+
features = features,
89+
cxx_builtin_include_directories = [
90+
"/usr/lib/llvm-%d/lib/clang/" % ctx.attr.version,
91+
"/usr/include",
92+
],
93+
toolchain_identifier = "local",
94+
host_system_name = "local",
95+
target_system_name = "local",
96+
target_cpu = "k8",
97+
target_libc = "unknown",
98+
compiler = "clang",
99+
abi_version = "unknown",
100+
abi_libc_version = "unknown",
101+
tool_paths = tool_paths,
102+
)
103+
104+
# Relevant documentation:
105+
# - https://bazel.build/rules/lib/globals/bzl.html#rule
106+
# - https://bazel.build/rules/lib/toplevel/attr.html#int
107+
linux_local_clang_toolchain_config = rule(
108+
implementation = _impl,
109+
attrs = {
110+
"version": attr.int(mandatory = True),
111+
},
112+
provides = [CcToolchainConfigInfo],
113+
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
load(":cc_toolchain_config.bzl", "linux_local_clang_toolchain_config")
2+
3+
# Relevant documentation:
4+
# - https://bazel.build/extending/macros
5+
# - https://bazel.build/extending/toolchains
6+
# - https://bazel.build/reference/be/platforms-and-toolchains#toolchain
7+
# - https://bazel.build/tutorials/ccp-toolchain-config
8+
def _linux_local_clang_impl(name, visibility, exec_compatible_with, version, **kwargs):
9+
linux_local_clang_toolchain_config(
10+
name = name + "_config",
11+
visibility = ["//visibility:private"],
12+
version = version,
13+
)
14+
native.cc_toolchain(
15+
name = name + "_cc_toolchain",
16+
visibility = ["//visibility:private"],
17+
toolchain_identifier = name,
18+
toolchain_config = ":" + name + "_config",
19+
all_files = ":empty",
20+
compiler_files = ":empty",
21+
dwp_files = ":empty",
22+
linker_files = ":empty",
23+
objcopy_files = ":empty",
24+
strip_files = ":empty",
25+
supports_param_files = 0,
26+
)
27+
native.toolchain(
28+
name = name,
29+
visibility = visibility,
30+
toolchain = ":" + name + "_cc_toolchain",
31+
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
32+
exec_compatible_with = exec_compatible_with,
33+
target_compatible_with = ["@platforms//os:linux"],
34+
**kwargs,
35+
)
36+
37+
# Defines a compiler toolchain that calls /usr/bin/clang-{version} to compile and link c++.
38+
#
39+
# Relevant documentation:
40+
# - https://bazel.build/rules/lib/globals/bzl.html#macro
41+
# - https://bazel.build/rules/lib/toplevel/attr#int
42+
# - https://bazel.build/rules/lib/toplevel/attr#label_list
43+
linux_local_clang = macro(
44+
attrs = {
45+
"exec_compatible_with": attr.label_list(configurable = False),
46+
"version": attr.int(configurable = False, mandatory = True),
47+
},
48+
implementation = _linux_local_clang_impl,
49+
)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Relevant documentation:
2+
# - https://bazel.build/reference/be/platforms-and-toolchains
3+
# - https://bazel.build/rules/lib/builtins/path.html
4+
# - https://bazel.build/rules/lib/builtins/repository_ctx
5+
# - https://bazel.build/rules/lib/globals/bzl.html#repository_rule
6+
def _file_detector_impl(repository_ctx):
7+
root_build_file = 'package(default_visibility = ["//visibility:public"])\n\n'
8+
for (filename, constraint_setting) in repository_ctx.attr.files.items():
9+
file_path = repository_ctx.path(filename)
10+
repository_ctx.watch(file_path)
11+
if file_path.exists:
12+
exists_str = "present"
13+
else:
14+
exists_str = "absent"
15+
build_fragment = """
16+
constraint_setting(
17+
name = "{0}",
18+
default_constraint_value = ":{0}_{1}"
19+
)
20+
constraint_value(
21+
name = "{0}_present",
22+
constraint_setting = ":{0}",
23+
)
24+
constraint_value(
25+
name = "{0}_absent",
26+
constraint_setting = ":{0}",
27+
)
28+
""".strip().format(constraint_setting, exists_str)
29+
root_build_file += "\n" + build_fragment + "\n"
30+
build_file = repository_ctx.path("BUILD.bazel")
31+
repository_ctx.file(build_file, root_build_file, False)
32+
33+
# Creates a repository that defines `constraint_setting`s and
34+
# `constraint_value`s based on the existence of some files on the host.
35+
#
36+
# Example usage:
37+
# ```
38+
# file_detector = use_repo_rule("//toolchain:file_detector.bzl", "file_detector")
39+
#
40+
# file_detector(
41+
# name = "clang_detector",
42+
# files = {
43+
# "/usr/bin/clang-11": "clang_11",
44+
# },
45+
# ),
46+
# ```
47+
# This expands to a repository `@clang_detector` defining the following
48+
# targets:
49+
# ```
50+
# constraint_setting(
51+
# name = "clang_11",
52+
# default_constraint_value = ":clang_11_present",
53+
# )
54+
# constraint_value(
55+
# name = "clang_11_present",
56+
# constraint_setting = ":clang_11",
57+
# )
58+
# constraint_value(
59+
# name = "clang_11_absent",
60+
# constraint_setting = ":clang_11",
61+
# )
62+
# ```
63+
# The default constraint value of the "@clang_detector//:clang_11" setting is
64+
# set to either "@clang_detector//:clang_11_present" or
65+
# "@clang_detector//:clang_11_absent" depending on whether the file
66+
# /usr/bin/clang-11 is present on the host.
67+
#
68+
# This is helpful for toolchain resolution. A toolchain relying on host
69+
# executables can reference these constraints in its `exec_compatible_with`
70+
# list, which is used to report availability.
71+
#
72+
# Relevant documentation:
73+
# - https://bazel.build/extending/toolchains
74+
# - https://bazel.build/reference/be/platforms-and-toolchains
75+
# - https://bazel.build/rules/lib/globals/bzl.html#repository_rule
76+
# - https://bazel.build/rules/lib/toplevel/attr#string_dict
77+
file_detector = repository_rule(
78+
implementation = _file_detector_impl,
79+
attrs = {
80+
"files": attr.string_dict(
81+
allow_empty = False,
82+
configurable = False,
83+
mandatory = True,
84+
),
85+
},
86+
)

0 commit comments

Comments
 (0)