Skip to content

[libc][bazel] Use Bazel aspects to implement libc_release_library. #134948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 9, 2025
Merged
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
158 changes: 105 additions & 53 deletions utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ load(":libc_configure_options.bzl", "LIBC_CONFIGURE_OPTIONS")
load(":libc_namespace.bzl", "LIBC_NAMESPACE")
load(":platforms.bzl", "PLATFORM_CPU_X86_64")

# TODO: Remove this helper function once all donwstream users are migrated.
def libc_internal_target(name):
return name + ".__internal__"
return name

def libc_common_copts():
root_label = Label(":libc")
Expand Down Expand Up @@ -44,84 +45,127 @@ def libc_release_copts():
})
return copts + platform_copts

def _libc_library(name, copts = [], deps = [], local_defines = [], **kwargs):
def _libc_library(name, **kwargs):
"""Internal macro to serve as a base for all other libc library rules.

Args:
name: Target name.
copts: The special compiler options for the target.
deps: The list of target dependencies if any.
local_defines: The list of target local_defines if any.
**kwargs: All other attributes relevant for the cc_library rule.
"""

for attr in ["copts", "local_defines"]:
if attr in kwargs:
fail("disallowed attribute: '{}' in rule: '{}'".format(attr, name))
native.cc_library(
name = name,
copts = copts + libc_common_copts(),
local_defines = local_defines + LIBC_CONFIGURE_OPTIONS,
deps = deps,
copts = libc_common_copts(),
local_defines = LIBC_CONFIGURE_OPTIONS,
linkstatic = 1,
**kwargs
)

def _libc_library_filegroups(
name,
is_function,
srcs = [],
hdrs = [],
textual_hdrs = [],
deps = [],
# We're not using kwargs, but instead explicitly list all possible
# arguments that can be passed to libc_support_library or
# libc_function macros. This is done to limit the configurability
# and ensure the consistent and tightly controlled set of flags
# (see libc_common_copts and libc_release_copts above) is used to build
# libc code both for tests and for release configuration.
target_compatible_with = None): # @unused
"""Internal macro to collect sources and headers required to build a library.
"""

# filegroups created from "libc_function" macro has an extra "_fn" in their
# name to ensure that no other libc target can depend on libc_function.
prefix = name + ("_fn" if is_function else "")
native.filegroup(
name = prefix + "_srcs",
srcs = srcs + hdrs + [dep + "_srcs" for dep in deps],
)
native.filegroup(
name = prefix + "_textual_hdrs",
srcs = textual_hdrs + [dep + "_textual_hdrs" for dep in deps],
)

# A convenience function which should be used to list all libc support libraries.
# Any library which does not define a public function should be listed with
# libc_support_library.
def libc_support_library(name, **kwargs):
_libc_library(name = name, **kwargs)
_libc_library_filegroups(name = name, is_function = False, **kwargs)

def libc_function(name, **kwargs):
"""Add target for a libc function.

This macro creates an internal cc_library that can be used to test this
function, and creates filegroups required to include this function into
a release build of libc.
function.

Args:
name: Target name. It is normally the name of the function this target is
for.
name: Target name. Typically the name of the function this target is for.
**kwargs: Other attributes relevant for a cc_library. For example, deps.
"""

# Build "internal" library with a function, the target has ".__internal__" suffix and contains
# C++ functions in the "LIBC_NAMESPACE" namespace. This allows us to test the function in the
# Builds "internal" library with a function, exposed as a C++ function in
# the "LIBC_NAMESPACE" namespace. This allows us to test the function in the
# presence of another libc.
_libc_library(
name = libc_internal_target(name),
**kwargs
)

_libc_library_filegroups(name = name, is_function = True, **kwargs)
LibcLibraryInfo = provider(
"All source files and textual headers for building a particular library.",
fields = ["srcs", "textual_hdrs"],
)

def _get_libc_info_aspect_impl(
target, # @unused
ctx):
maybe_srcs = getattr(ctx.rule.attr, "srcs", [])
maybe_hdrs = getattr(ctx.rule.attr, "hdrs", [])
maybe_textual_hdrs = getattr(ctx.rule.attr, "textual_hdrs", [])
maybe_deps = getattr(ctx.rule.attr, "deps", [])
return LibcLibraryInfo(
srcs = depset(
transitive = [
dep[LibcLibraryInfo].srcs
for dep in maybe_deps
if LibcLibraryInfo in dep
] + [
src.files
for src in maybe_srcs + maybe_hdrs
],
),
textual_hdrs = depset(
transitive = [
dep[LibcLibraryInfo].textual_hdrs
for dep in maybe_deps
if LibcLibraryInfo in dep
] + [
hdr.files
for hdr in maybe_textual_hdrs
],
),
)

_get_libc_info_aspect = aspect(
implementation = _get_libc_info_aspect_impl,
attr_aspects = ["deps"],
)

def _libc_srcs_filegroup_impl(ctx):
return DefaultInfo(
files = depset(transitive = [
fn[LibcLibraryInfo].srcs
for fn in ctx.attr.libs
]),
)

_libc_srcs_filegroup = rule(
doc = "Returns all sources for building the specified libraries.",
implementation = _libc_srcs_filegroup_impl,
attrs = {
"libs": attr.label_list(
mandatory = True,
aspects = [_get_libc_info_aspect],
),
},
)

def _libc_textual_hdrs_filegroup_impl(ctx):
return DefaultInfo(
files = depset(transitive = [
fn[LibcLibraryInfo].textual_hdrs
for fn in ctx.attr.libs
]),
)

_libc_textual_hdrs_filegroup = rule(
doc = "Returns all textual headers for compiling the specified libraries.",
implementation = _libc_textual_hdrs_filegroup_impl,
attrs = {
"libs": attr.label_list(
mandatory = True,
aspects = [_get_libc_info_aspect],
),
},
)

def libc_release_library(
name,
Expand All @@ -138,15 +182,18 @@ def libc_release_library(
**kwargs: Other arguments relevant to cc_library.
"""

# Combine all sources into a single filegroup to avoid repeated sources error.
native.filegroup(
_libc_srcs_filegroup(
name = name + "_srcs",
srcs = [function + "_fn_srcs" for function in libc_functions],
libs = libc_functions,
)

_libc_textual_hdrs_filegroup(
name = name + "_textual_hdrs",
libs = libc_functions,
)
native.cc_library(
name = name + "_textual_hdr_library",
textual_hdrs = [function + "_fn_textual_hdrs" for function in libc_functions],
textual_hdrs = [":" + name + "_textual_hdrs"],
)

weak_attributes = [
Expand Down Expand Up @@ -175,15 +222,20 @@ def libc_header_library(name, hdrs, deps = [], **kwargs):
**kwargs: All other attributes relevant for the cc_library rule.
"""

# Combine sources from dependencies to create a single cc_library target.
native.filegroup(
_libc_srcs_filegroup(
name = name + "_hdr_deps",
srcs = [dep + "_srcs" for dep in deps],
libs = deps,
)

_libc_textual_hdrs_filegroup(
name = name + "_textual_hdrs",
libs = deps,
)
native.cc_library(
name = name + "_textual_hdr_library",
textual_hdrs = [dep + "_textual_hdrs" for dep in deps],
textual_hdrs = [":" + name + "_textual_hdrs"],
)

native.cc_library(
name = name,
# Technically speaking, we should put _hdr_deps in srcs, as they are
Expand Down