Skip to content

Commit 2521256

Browse files
committed
[libc][bazel] Use Bazel aspects to implement libc_release_library.
Instead of creating hundreds of implicit "filegroup" targets to keep track of sources and textual headers required to build each libc function or helper library, use Bazel aspects (see https://bazel.build/versions/8.0.0/extending/aspects), which enable transparent collection of transitive sources / textual headers while walking the dependency DAG, and minimizes the Starlark overhead.
1 parent 1a1698b commit 2521256

File tree

1 file changed

+112
-53
lines changed

1 file changed

+112
-53
lines changed

utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl

Lines changed: 112 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ load(":libc_configure_options.bzl", "LIBC_CONFIGURE_OPTIONS")
1010
load(":libc_namespace.bzl", "LIBC_NAMESPACE")
1111
load(":platforms.bzl", "PLATFORM_CPU_X86_64")
1212

13+
# TODO: Remove this helper function once all donwstream users are migrated.
1314
def libc_internal_target(name):
14-
return name + ".__internal__"
15+
return name
1516

1617
def libc_common_copts():
1718
root_label = Label(":libc")
@@ -44,84 +45,134 @@ def libc_release_copts():
4445
})
4546
return copts + platform_copts
4647

47-
def _libc_library(name, copts = [], deps = [], local_defines = [], **kwargs):
48+
def _libc_library(name, **kwargs):
4849
"""Internal macro to serve as a base for all other libc library rules.
4950
5051
Args:
5152
name: Target name.
52-
copts: The special compiler options for the target.
53-
deps: The list of target dependencies if any.
54-
local_defines: The list of target local_defines if any.
5553
**kwargs: All other attributes relevant for the cc_library rule.
5654
"""
5755

56+
for attr in ["copts", "local_defines"]:
57+
if attr in kwargs:
58+
fail("disallowed attribute: '{}' in rule: '{}'".format(attr, name))
5859
native.cc_library(
5960
name = name,
60-
copts = copts + libc_common_copts(),
61-
local_defines = local_defines + LIBC_CONFIGURE_OPTIONS,
62-
deps = deps,
61+
copts = libc_common_copts(),
62+
local_defines = LIBC_CONFIGURE_OPTIONS,
6363
linkstatic = 1,
6464
**kwargs
6565
)
6666

67-
def _libc_library_filegroups(
68-
name,
69-
is_function,
70-
srcs = [],
71-
hdrs = [],
72-
textual_hdrs = [],
73-
deps = [],
74-
# We're not using kwargs, but instead explicitly list all possible
75-
# arguments that can be passed to libc_support_library or
76-
# libc_function macros. This is done to limit the configurability
77-
# and ensure the consistent and tightly controlled set of flags
78-
# (see libc_common_copts and libc_release_copts above) is used to build
79-
# libc code both for tests and for release configuration.
80-
target_compatible_with = None): # @unused
81-
"""Internal macro to collect sources and headers required to build a library.
82-
"""
83-
84-
# filegroups created from "libc_function" macro has an extra "_fn" in their
85-
# name to ensure that no other libc target can depend on libc_function.
86-
prefix = name + ("_fn" if is_function else "")
87-
native.filegroup(
88-
name = prefix + "_srcs",
89-
srcs = srcs + hdrs + [dep + "_srcs" for dep in deps],
90-
)
91-
native.filegroup(
92-
name = prefix + "_textual_hdrs",
93-
srcs = textual_hdrs + [dep + "_textual_hdrs" for dep in deps],
94-
)
95-
9667
# A convenience function which should be used to list all libc support libraries.
9768
# Any library which does not define a public function should be listed with
9869
# libc_support_library.
9970
def libc_support_library(name, **kwargs):
10071
_libc_library(name = name, **kwargs)
101-
_libc_library_filegroups(name = name, is_function = False, **kwargs)
10272

10373
def libc_function(name, **kwargs):
10474
"""Add target for a libc function.
10575
10676
This macro creates an internal cc_library that can be used to test this
107-
function, and creates filegroups required to include this function into
108-
a release build of libc.
77+
function.
10978
11079
Args:
111-
name: Target name. It is normally the name of the function this target is
112-
for.
80+
name: Target name. Typically the name of the function this target is for.
11381
**kwargs: Other attributes relevant for a cc_library. For example, deps.
11482
"""
11583

116-
# Build "internal" library with a function, the target has ".__internal__" suffix and contains
117-
# C++ functions in the "LIBC_NAMESPACE" namespace. This allows us to test the function in the
84+
# Builds "internal" library with a function, exposed as a C++ function in
85+
# the "LIBC_NAMESPACE" namespace. This allows us to test the function in the
11886
# presence of another libc.
11987
_libc_library(
12088
name = libc_internal_target(name),
12189
**kwargs
12290
)
12391

124-
_libc_library_filegroups(name = name, is_function = True, **kwargs)
92+
# LibcLibraryInfo is used to collect all sources and textual headers required
93+
# to build a particular libc_function or libc_support_library.
94+
LibcLibraryInfo = provider(
95+
fields = ["srcs", "textual_hdrs"],
96+
)
97+
98+
def _get_libc_info_aspect_impl(target, ctx):
99+
maybe_srcs = getattr(ctx.rule.attr, "srcs", [])
100+
maybe_hdrs = getattr(ctx.rule.attr, "hdrs", [])
101+
maybe_textual_hdrs = getattr(ctx.rule.attr, "textual_hdrs", [])
102+
maybe_deps = getattr(ctx.rule.attr, "deps", [])
103+
return LibcLibraryInfo(
104+
srcs = depset(
105+
[
106+
f
107+
for src in maybe_srcs + maybe_hdrs
108+
for f in src.files.to_list()
109+
if f.is_source
110+
],
111+
transitive = [
112+
dep[LibcLibraryInfo].srcs
113+
for dep in maybe_deps
114+
if LibcLibraryInfo in dep
115+
],
116+
),
117+
textual_hdrs = depset(
118+
[
119+
f
120+
for hdr in maybe_textual_hdrs
121+
for f in hdr.files.to_list()
122+
if f.is_source
123+
],
124+
transitive = [
125+
dep[LibcLibraryInfo].textual_hdrs
126+
for dep in maybe_deps
127+
if LibcLibraryInfo in dep
128+
],
129+
),
130+
)
131+
132+
_get_libc_info_aspect = aspect(
133+
implementation = _get_libc_info_aspect_impl,
134+
attr_aspects = ["deps"],
135+
)
136+
137+
def _get_libc_srcs_impl(ctx):
138+
return DefaultInfo(
139+
files = depset(transitive = [
140+
fn[LibcLibraryInfo].srcs
141+
for fn in ctx.attr.libs
142+
]),
143+
)
144+
145+
# get_libc_srcs returns the list of sources required to build all
146+
# specified libraries.
147+
get_libc_srcs = rule(
148+
implementation = _get_libc_srcs_impl,
149+
attrs = {
150+
"libs": attr.label_list(
151+
mandatory = True,
152+
aspects = [_get_libc_info_aspect],
153+
),
154+
},
155+
)
156+
157+
def _get_libc_textual_hdrs_impl(ctx):
158+
return DefaultInfo(
159+
files = depset(transitive = [
160+
fn[LibcLibraryInfo].textual_hdrs
161+
for fn in ctx.attr.libs
162+
]),
163+
)
164+
165+
# get_libc_textual_hdrs returns the list of textual headers required to compile
166+
# all specified libraries.
167+
get_libc_textual_hdrs = rule(
168+
implementation = _get_libc_textual_hdrs_impl,
169+
attrs = {
170+
"libs": attr.label_list(
171+
mandatory = True,
172+
aspects = [_get_libc_info_aspect],
173+
),
174+
},
175+
)
125176

126177
def libc_release_library(
127178
name,
@@ -138,15 +189,18 @@ def libc_release_library(
138189
**kwargs: Other arguments relevant to cc_library.
139190
"""
140191

141-
# Combine all sources into a single filegroup to avoid repeated sources error.
142-
native.filegroup(
192+
get_libc_srcs(
143193
name = name + "_srcs",
144-
srcs = [function + "_fn_srcs" for function in libc_functions],
194+
libs = libc_functions,
145195
)
146196

197+
get_libc_textual_hdrs(
198+
name = name + "_textual_hdrs",
199+
libs = libc_functions,
200+
)
147201
native.cc_library(
148202
name = name + "_textual_hdr_library",
149-
textual_hdrs = [function + "_fn_textual_hdrs" for function in libc_functions],
203+
textual_hdrs = [":" + name + "_textual_hdrs"],
150204
)
151205

152206
weak_attributes = [
@@ -175,15 +229,20 @@ def libc_header_library(name, hdrs, deps = [], **kwargs):
175229
**kwargs: All other attributes relevant for the cc_library rule.
176230
"""
177231

178-
# Combine sources from dependencies to create a single cc_library target.
179-
native.filegroup(
232+
get_libc_srcs(
180233
name = name + "_hdr_deps",
181-
srcs = [dep + "_srcs" for dep in deps],
234+
libs = deps,
235+
)
236+
237+
get_libc_textual_hdrs(
238+
name = name + "_textual_hdrs",
239+
libs = deps,
182240
)
183241
native.cc_library(
184242
name = name + "_textual_hdr_library",
185-
textual_hdrs = [dep + "_textual_hdrs" for dep in deps],
243+
textual_hdrs = [":" + name + "_textual_hdrs"],
186244
)
245+
187246
native.cc_library(
188247
name = name,
189248
# Technically speaking, we should put _hdr_deps in srcs, as they are

0 commit comments

Comments
 (0)