Skip to content

Commit d6e0f1a

Browse files
authored
Add a repository rule for efficient sysroots (#572)
This provides sysroots as a source directory rather than a filegroup, which means merkle tree computation will be more efficient
1 parent cc6cea8 commit d6e0f1a

File tree

7 files changed

+145
-32
lines changed

7 files changed

+145
-32
lines changed

MODULE.bazel

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,22 @@ module(
2121

2222
bazel_dep(name = "bazel_features", version = "1.36.0")
2323
bazel_dep(name = "bazel_skylib", version = "1.5.0")
24+
bazel_dep(name = "aspect_bazel_lib", version = "2.0.0")
2425
bazel_dep(name = "rules_cc", version = "0.2.2")
2526
bazel_dep(name = "platforms", version = "0.0.8")
2627
bazel_dep(name = "helly25_bzl", version = "0.1.2")
2728

29+
bazel_dep(name = "tar.bzl", version = "0.6.0")
30+
tar_toolchains = use_extension("@tar.bzl//tar:extensions.bzl", "toolchains")
31+
use_repo(
32+
tar_toolchains,
33+
"bsd_tar_toolchains_darwin_amd64",
34+
"bsd_tar_toolchains_darwin_arm64",
35+
"bsd_tar_toolchains_linux_amd64",
36+
"bsd_tar_toolchains_linux_arm64",
37+
"bsd_tar_toolchains_windows_amd64",
38+
"bsd_tar_toolchains_windows_arm64",
39+
)
40+
2841
# TODO: Remove when protobuf is released with a version of rules_python that supports 8.x
2942
bazel_dep(name = "rules_python", version = "1.0.0", dev_dependency = True)

tests/MODULE.bazel

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ llvm.toolchain_root(
171171
)
172172
llvm.sysroot(
173173
name = "llvm_toolchain_with_sysroot",
174-
label = "@org_chromium_sysroot_linux_x64//:sysroot",
174+
label = "@org_chromium_sysroot_linux_x64//sysroot",
175175
targets = ["linux-x86_64"],
176176
)
177177
use_repo(llvm, "llvm_toolchain_with_sysroot")
@@ -253,18 +253,11 @@ libclang_rt_wasm32 = use_repo_rule("//wasm:wasi_sdk.bzl", "libclang_rt_wasm32")
253253

254254
libclang_rt_wasm32(name = "libclang_rt_wasm32")
255255

256-
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
256+
sysroot = use_repo_rule("@toolchains_llvm//toolchain:sysroot.bzl", "sysroot")
257257

258258
# This sysroot is used by github.com/vsco/bazel-toolchains.
259-
http_archive(
259+
sysroot(
260260
name = "org_chromium_sysroot_linux_x64",
261-
build_file_content = """
262-
filegroup(
263-
name = "sysroot",
264-
srcs = glob(["*/**"]),
265-
visibility = ["//visibility:public"],
266-
)
267-
""",
268261
sha256 = "84656a6df544ecef62169cfe3ab6e41bb4346a62d3ba2a045dc5a0a2ecea94a3",
269262
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/2202c161310ffde63729f29d27fe7bb24a0bc540/debian_stretch_amd64_sysroot.tar.xz"],
270263
)

tests/WORKSPACE

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,25 @@ local_repository(
2020
)
2121

2222
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
23+
24+
http_archive(
25+
name = "aspect_bazel_lib",
26+
sha256 = "c4f36285ceed51f75da44ffcf8fa393794d0dc2e273a2e03be50462e347740cd",
27+
strip_prefix = "bazel-lib-2.0.0",
28+
url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.0.0/bazel-lib-v2.0.0.tar.gz",
29+
)
30+
31+
http_archive(
32+
name = "tar.bzl",
33+
sha256 = "a147d473a359742db2a43c8a9a8e04e31321582e6bb669dafc5ba6b2c59845d1",
34+
strip_prefix = "tar.bzl-0.6.0",
35+
url = "https://github.com/bazel-contrib/tar.bzl/releases/download/v0.6.0/tar.bzl-v0.6.0.tar.gz",
36+
)
37+
38+
load("@tar.bzl//tar:extensions.bzl", "create_repositories")
39+
40+
create_repositories()
41+
2342
load("@toolchains_llvm//toolchain:deps.bzl", "bazel_toolchain_dependencies")
2443

2544
bazel_toolchain_dependencies()
@@ -114,15 +133,10 @@ llvm_toolchain(
114133
## Toolchain example with a sysroot.
115134

116135
# This sysroot is used by github.com/vsco/bazel-toolchains.
117-
http_archive(
136+
load("@toolchains_llvm//toolchain:sysroot.bzl", "sysroot")
137+
138+
sysroot(
118139
name = "org_chromium_sysroot_linux_x64",
119-
build_file_content = """
120-
filegroup(
121-
name = "sysroot",
122-
srcs = glob(["*/**"]),
123-
visibility = ["//visibility:public"],
124-
)
125-
""",
126140
sha256 = "84656a6df544ecef62169cfe3ab6e41bb4346a62d3ba2a045dc5a0a2ecea94a3",
127141
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/2202c161310ffde63729f29d27fe7bb24a0bc540/debian_stretch_amd64_sysroot.tar.xz"],
128142
)
@@ -131,7 +145,7 @@ llvm_toolchain(
131145
name = "llvm_toolchain_with_sysroot",
132146
llvm_versions = LLVM_VERSIONS,
133147
sysroot = {
134-
"linux-x86_64": "@org_chromium_sysroot_linux_x64//:sysroot",
148+
"linux-x86_64": "@org_chromium_sysroot_linux_x64//sysroot",
135149
},
136150
# We can share the downloaded LLVM distribution with the first configuration.
137151
toolchain_roots = {

toolchain/internal/configure.bzl

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ def _cc_toolchain_str(
320320
sysroot_path = toolchain_info.sysroot_paths_dict.get(target_pair)
321321
sysroot_label = toolchain_info.sysroot_labels_dict.get(target_pair)
322322
if sysroot_label:
323-
sysroot_label_str = "\"%s\"" % str(sysroot_label)
323+
sysroot_label_str = repr(str(sysroot_label))
324324
else:
325325
sysroot_label_str = ""
326326

@@ -466,6 +466,11 @@ filegroup(
466466

467467
if use_absolute_paths_llvm:
468468
template = template + """
469+
filegroup(
470+
name = "cxx_builtin_include_files-{suffix}",
471+
srcs = [],
472+
)
473+
469474
filegroup(
470475
name = "compiler-components-{suffix}",
471476
srcs = [
@@ -499,10 +504,17 @@ filegroup(name = "strip-files-{suffix}", srcs = [{extra_files_str}])
499504
else:
500505
template = template + """
501506
filegroup(
502-
name = "compiler-components-{suffix}",
507+
name = "cxx_builtin_include_files-{suffix}",
503508
srcs = [
504509
"{llvm_dist_label_prefix}clang",
505510
"{llvm_dist_label_prefix}include",
511+
],
512+
)
513+
514+
filegroup(
515+
name = "compiler-components-{suffix}",
516+
srcs = [
517+
":cxx_builtin_include_files-{suffix}",
506518
":sysroot-components-{suffix}",
507519
{extra_compiler_files}
508520
],
@@ -539,18 +551,11 @@ filegroup(name = "strip-files-{suffix}", srcs = ["{llvm_dist_label_prefix}strip"
539551
"""
540552

541553
template = template + """
542-
filegroup(
543-
name = "include-components-{suffix}",
544-
srcs = [
545-
":compiler-components-{suffix}",
546-
":sysroot-components-{suffix}",
547-
],
548-
)
549-
550554
system_module_map(
551555
name = "module-{suffix}",
552-
cxx_builtin_include_files = ":include-components-{suffix}",
556+
cxx_builtin_include_files = ":cxx_builtin_include_files-{suffix}",
553557
cxx_builtin_include_directories = {cxx_builtin_include_directories},
558+
sysroot_files = ":sysroot-components-{suffix}",
554559
sysroot_path = "{sysroot_path}",
555560
)
556561

toolchain/internal/system_module_map.bzl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,28 @@ def _system_module_map(ctx):
5757

5858
template_dict = ctx.actions.template_dict()
5959
template_dict.add_joined(
60-
"%textual_headers%",
60+
"%cxx_builtin_include_files%",
6161
ctx.attr.cxx_builtin_include_files[DefaultInfo].files,
6262
join_with = "\n",
6363
map_each = textual_header_closure,
6464
allow_closure = True,
6565
)
66+
67+
# We don't have a good way to detect a source directory, so check if it's a single File...
68+
sysroot_files = ctx.attr.sysroot_files[DefaultInfo].files.to_list()
69+
if len(sysroot_files) == 1:
70+
path = paths.normalize(sysroot_files[0].path).replace("//", "/")
71+
template_dict.add("%sysroot%", _umbrella_submodule(execroot_prefix + path))
72+
else:
73+
print("WARNING: Sysroot {} did not resolve to a single (directory) file. Consider using the `sysroot` repository rule in @toolchains_llvm//toolchain:sysroot.bzl for more efficient builds.".format(ctx.attr.sysroot_files.label)) # buildifier: disable=print
74+
template_dict.add_joined(
75+
"%sysroot%",
76+
ctx.attr.sysroot_files[DefaultInfo].files,
77+
join_with = "\n",
78+
map_each = textual_header_closure,
79+
allow_closure = True,
80+
)
81+
6682
template_dict.add_joined(
6783
"%umbrella_submodules%",
6884
depset(absolute_path_dirs),
@@ -87,6 +103,7 @@ system_module_map = rule(
87103
attrs = {
88104
"cxx_builtin_include_files": attr.label(mandatory = True),
89105
"cxx_builtin_include_directories": attr.string_list(mandatory = True),
106+
"sysroot_files": attr.label(),
90107
"sysroot_path": attr.string(),
91108
"_module_map_template": attr.label(
92109
default = "template.modulemap",
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module "crosstool" [system] {
2-
%textual_headers%
2+
%cxx_builtin_include_files%
3+
%sysroot%
34
%umbrella_submodules%
45
}

toolchain/sysroot.bzl

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
load("@aspect_bazel_lib//lib:repo_utils.bzl", "repo_utils")
2+
3+
def _sysroot_impl(rctx):
4+
urls = rctx.attr.urls
5+
if rctx.attr.url:
6+
urls = [rctx.attr.url] + urls
7+
8+
if not urls:
9+
fail("At least one of url and urls must be provided")
10+
11+
_, _, archive = urls[0].rpartition("/")
12+
13+
rctx.download(urls, archive, sha256 = rctx.attr.sha256)
14+
15+
# Source directories are more efficient than file groups for 2 reasons:
16+
# - They can be symlinked into a local sandbox with a single symlink instead of 1-per-file
17+
# - They serve as a signal to the Merkle tree cache machinery since they can be memoized as a single node.
18+
# Since sysroots are usually a ton of files, it can improve build performance to declare them as source directories.
19+
20+
# Also, create the BUILD file before extracting because `bsdtar` expects the target
21+
# directory to exist, and this way Bazel creates it for us without needing `mkdir`.
22+
rctx.file(
23+
"sysroot/BUILD.bazel",
24+
"""filegroup(
25+
name = "sysroot",
26+
srcs = ["."],
27+
visibility = ["//visibility:public"],
28+
)""",
29+
)
30+
31+
host_bsdtar = Label("@bsd_tar_toolchains_%s//:tar" % repo_utils.platform(rctx))
32+
33+
cmd = [
34+
str(rctx.path(host_bsdtar)),
35+
"--extract",
36+
"--no-same-owner",
37+
"--no-same-permissions",
38+
"--file",
39+
archive,
40+
"--directory",
41+
"sysroot",
42+
]
43+
44+
for include in rctx.attr.include_patterns:
45+
cmd.extend(["--include", include])
46+
47+
for exclude in rctx.attr.exclude_patterns:
48+
cmd.extend(["--exclude", exclude])
49+
50+
result = rctx.execute(cmd)
51+
if result.return_code != 0:
52+
fail(result.stdout + result.stderr)
53+
54+
rctx.delete(archive)
55+
56+
if hasattr(rctx, "repo_metadata"):
57+
return rctx.repo_metadata(reproducible = True)
58+
else:
59+
return None
60+
61+
sysroot = repository_rule(
62+
implementation = _sysroot_impl,
63+
attrs = {
64+
"url": attr.string(),
65+
"urls": attr.string_list(),
66+
"sha256": attr.string(),
67+
"include_patterns": attr.string_list(),
68+
"exclude_patterns": attr.string_list(),
69+
},
70+
)

0 commit comments

Comments
 (0)