Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
70
vendor/cxx/tools/buck/prelude/linking/link_groups.bzl
vendored
Normal file
70
vendor/cxx/tools/buck/prelude/linking/link_groups.bzl
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//utils:dicts.bzl",
|
||||
"flatten_x",
|
||||
)
|
||||
load(
|
||||
":link_info.bzl",
|
||||
"LinkInfos",
|
||||
"LinkedObject",
|
||||
)
|
||||
|
||||
# Information about a linkable node which explicitly sets `link_group`.
|
||||
LinkGroupLib = record(
|
||||
# The label of the owning target (if any).
|
||||
label = field(["label", None], None),
|
||||
# The shared libs to package for this link group.
|
||||
shared_libs = field({str.type: LinkedObject.type}),
|
||||
# The link info to link against this link group.
|
||||
shared_link_infos = field(LinkInfos.type),
|
||||
)
|
||||
|
||||
# Provider propagating info about transitive link group libs.
|
||||
LinkGroupLibInfo = provider(fields = [
|
||||
# A map of link group names to their shared libraries.
|
||||
"libs", # {str.type: LinkGroupLib.type}
|
||||
])
|
||||
|
||||
def gather_link_group_libs(
|
||||
libs: [{str.type: LinkGroupLib.type}] = [],
|
||||
children: [LinkGroupLibInfo.type] = [],
|
||||
deps: ["dependency"] = []) -> {str.type: LinkGroupLib.type}:
|
||||
"""
|
||||
Return all link groups libs deps and top-level libs.
|
||||
"""
|
||||
return flatten_x(
|
||||
(libs +
|
||||
[c.libs for c in children] +
|
||||
[d[LinkGroupLibInfo].libs for d in deps if LinkGroupLibInfo in d]),
|
||||
fmt = "conflicting link group roots for \"{0}\": {1} != {2}",
|
||||
)
|
||||
|
||||
def merge_link_group_lib_info(
|
||||
label: ["label", None] = None,
|
||||
name: [str.type, None] = None,
|
||||
shared_libs: [{str.type: LinkedObject.type}, None] = None,
|
||||
shared_link_infos: [LinkInfos.type, None] = None,
|
||||
deps: ["dependency"] = []) -> LinkGroupLibInfo.type:
|
||||
"""
|
||||
Merge and return link group info libs from deps and the current rule wrapped
|
||||
in a provider.
|
||||
"""
|
||||
libs = {}
|
||||
if name != None:
|
||||
libs[name] = LinkGroupLib(
|
||||
label = label,
|
||||
shared_libs = shared_libs,
|
||||
shared_link_infos = shared_link_infos,
|
||||
)
|
||||
return LinkGroupLibInfo(
|
||||
libs = gather_link_group_libs(
|
||||
libs = [libs],
|
||||
deps = deps,
|
||||
),
|
||||
)
|
||||
588
vendor/cxx/tools/buck/prelude/linking/link_info.bzl
vendored
Normal file
588
vendor/cxx/tools/buck/prelude/linking/link_info.bzl
vendored
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//cxx:linker.bzl", "get_link_whole_args", "get_objects_as_library_args")
|
||||
load(
|
||||
"@prelude//utils:utils.bzl",
|
||||
"flatten",
|
||||
)
|
||||
|
||||
# Represents an archive (.a file)
|
||||
Archive = record(
|
||||
artifact = field("artifact"),
|
||||
# For a thin archive, this contains all the referenced .o files
|
||||
external_objects = field(["artifact"], []),
|
||||
)
|
||||
|
||||
# The different ways libraries can contribute towards a link.
|
||||
LinkStyle = enum(
|
||||
# Link using a static archive of non-PIC native objects.
|
||||
"static",
|
||||
# Link using a static archive containing PIC native objects.
|
||||
"static_pic",
|
||||
# Link using a native shared library.
|
||||
"shared",
|
||||
)
|
||||
|
||||
# Ways a library can request to be linked (e.g. usually specific via a rule
|
||||
# param like `preferred_linkage`. The actual link style used for a library is
|
||||
# usually determined by a combination of this and the link style being exported
|
||||
# via a provider.
|
||||
Linkage = enum(
|
||||
"static",
|
||||
"shared",
|
||||
"any",
|
||||
)
|
||||
|
||||
# This is used to mark each of the linkable types with a type so we can have
|
||||
# different behavior for different types. Ideally, starlark records would
|
||||
# each have the appropriate type automatically.
|
||||
LinkableType = enum(
|
||||
"archive",
|
||||
"frameworks",
|
||||
"shared",
|
||||
"objects",
|
||||
)
|
||||
|
||||
# An archive.
|
||||
ArchiveLinkable = record(
|
||||
archive = field(Archive.type),
|
||||
linker_type = field(str.type),
|
||||
link_whole = field(bool.type, False),
|
||||
_type = field(LinkableType.type, LinkableType("archive")),
|
||||
)
|
||||
|
||||
# A shared lib.
|
||||
SharedLibLinkable = record(
|
||||
lib = field("artifact"),
|
||||
link_without_soname = field(bool.type, False),
|
||||
_type = field(LinkableType.type, LinkableType("shared")),
|
||||
)
|
||||
|
||||
# A list of objects.
|
||||
ObjectsLinkable = record(
|
||||
objects = field([["artifact"], None], None),
|
||||
linker_type = field(str.type),
|
||||
link_whole = field(bool.type, False),
|
||||
_type = field(LinkableType.type, LinkableType("objects")),
|
||||
)
|
||||
|
||||
# Framework + library information for Apple/Cxx targets.
|
||||
FrameworksLinkable = record(
|
||||
# A list of trimmed framework paths, example: ["Foundation", "UIKit"]
|
||||
# Used to construct `-framework` args.
|
||||
framework_names = field([str.type], []),
|
||||
# A list of unresolved framework paths (i.e., containing $SDKROOT, etc).
|
||||
# Used to construct `-F` args for compilation and linking.
|
||||
#
|
||||
# Framework path resolution _must_ happen at the target site because
|
||||
# different targets might use different toolchains. For example,
|
||||
# an `apple_library()` might get _compiled_ using one toolchain
|
||||
# and then linked by as part of an `apple_binary()` using another
|
||||
# compatible toolchain. The resolved framework directories passed
|
||||
# using `-F` would be different for the compilation and the linking.
|
||||
unresolved_framework_paths = field([str.type], []),
|
||||
# A list of library names, used to construct `-l` args.
|
||||
library_names = field([str.type], []),
|
||||
_type = field(LinkableType.type, LinkableType("frameworks")),
|
||||
)
|
||||
|
||||
# Contains the information required to add an item (often corresponding to a single library) to a link command line.
|
||||
LinkInfo = record(
|
||||
# An informative name for this LinkInfo. This may be used in user messages
|
||||
# or when constructing intermediate output paths and does not need to be unique.
|
||||
name = field([str.type, None], None),
|
||||
# Opaque cmd_arg-likes to be added pre/post this item on a linker command line.
|
||||
pre_flags = field([""], []),
|
||||
post_flags = field([""], []),
|
||||
# Primary input to the linker, one of the Linkable types above.
|
||||
linkables = field([[ArchiveLinkable.type, SharedLibLinkable.type, ObjectsLinkable.type, FrameworksLinkable.type]], []),
|
||||
use_link_groups = field(bool.type, False),
|
||||
# Debug info which is referenced -- but not included -- by linkables in the
|
||||
# link info. For example, this may include `.dwo` files, or the original
|
||||
# `.o` files if they contain debug info that doesn't follow the link.
|
||||
external_debug_info = field(["_arglike"], []),
|
||||
)
|
||||
|
||||
# The ordering to use when traversing linker libs transitive sets.
|
||||
LinkOrdering = enum(
|
||||
# Preorder traversal, the default behavior which traverses depth-first returning the current
|
||||
# node, and then its children left-to-right.
|
||||
"preorder",
|
||||
# Topological sort, such that nodes are listed after all nodes that have them as descendants.
|
||||
"topological",
|
||||
)
|
||||
|
||||
def set_linkable_link_whole(
|
||||
linkable: [ArchiveLinkable.type, ObjectsLinkable.type, SharedLibLinkable.type, FrameworksLinkable.type]) -> [ArchiveLinkable.type, ObjectsLinkable.type, SharedLibLinkable.type, FrameworksLinkable.type]:
|
||||
if linkable._type == LinkableType("archive"):
|
||||
return ArchiveLinkable(
|
||||
archive = linkable.archive,
|
||||
linker_type = linkable.linker_type,
|
||||
link_whole = True,
|
||||
_type = linkable._type,
|
||||
)
|
||||
elif linkable._type == LinkableType("objects"):
|
||||
return ObjectsLinkable(
|
||||
objects = linkable.objects,
|
||||
linker_type = linkable.linker_type,
|
||||
link_whole = True,
|
||||
_type = linkable._type,
|
||||
)
|
||||
return linkable
|
||||
|
||||
# Helper to wrap a LinkInfo with additional pre/post-flags.
|
||||
def wrap_link_info(
|
||||
inner: LinkInfo.type,
|
||||
pre_flags: [""] = [],
|
||||
post_flags: [""] = []) -> LinkInfo.type:
|
||||
pre_flags = pre_flags + inner.pre_flags
|
||||
post_flags = inner.post_flags + post_flags
|
||||
return LinkInfo(
|
||||
name = inner.name,
|
||||
pre_flags = pre_flags,
|
||||
post_flags = post_flags,
|
||||
linkables = inner.linkables,
|
||||
use_link_groups = inner.use_link_groups,
|
||||
external_debug_info = inner.external_debug_info,
|
||||
)
|
||||
|
||||
# Adds approprate args representing `linkable` to `args`
|
||||
def append_linkable_args(args: "cmd_args", linkable: [ArchiveLinkable.type, SharedLibLinkable.type, ObjectsLinkable.type, FrameworksLinkable.type]):
|
||||
if linkable._type == LinkableType("archive"):
|
||||
if linkable.link_whole:
|
||||
args.add(get_link_whole_args(linkable.linker_type, [linkable.archive.artifact]))
|
||||
elif linkable.linker_type == "darwin":
|
||||
pass
|
||||
else:
|
||||
args.add(linkable.archive.artifact)
|
||||
|
||||
# When using thin archives, object files are implicitly used as inputs
|
||||
# to the link, so make sure track them as inputs so that they're
|
||||
# materialized/tracked properly.
|
||||
args.add(cmd_args().hidden(linkable.archive.external_objects))
|
||||
elif linkable._type == LinkableType("shared"):
|
||||
if linkable.link_without_soname:
|
||||
args.add(cmd_args(linkable.lib, format = "-L{}").parent())
|
||||
args.add("-l" + linkable.lib.basename.removeprefix("lib").removesuffix(linkable.lib.extension))
|
||||
else:
|
||||
args.add(linkable.lib)
|
||||
elif linkable._type == LinkableType("objects"):
|
||||
# We depend on just the filelist for darwin linker and don't add the normal args
|
||||
if linkable.linker_type != "darwin":
|
||||
# We need to export every symbol when link groups are used, but enabling
|
||||
# --whole-archive with --start-lib is undefined behavior in gnu linkers:
|
||||
# https://reviews.llvm.org/D120443. We need to export symbols from every
|
||||
# linkable in the link_info
|
||||
if not linkable.link_whole:
|
||||
args.add(get_objects_as_library_args(linkable.linker_type, linkable.objects))
|
||||
else:
|
||||
args.add(linkable.objects)
|
||||
elif linkable._type == LinkableType("frameworks"):
|
||||
# These flags are handled separately so they can be deduped.
|
||||
#
|
||||
# We've seen in apps with larger dependency graphs that failing
|
||||
# to dedupe these args results in linker.argsfile which are too big.
|
||||
pass
|
||||
else:
|
||||
fail("unreachable")
|
||||
|
||||
def link_info_to_args(value: LinkInfo.type) -> "cmd_args":
|
||||
args = cmd_args(value.pre_flags)
|
||||
for linkable in value.linkables:
|
||||
append_linkable_args(args, linkable)
|
||||
if value.post_flags != None:
|
||||
args.add(value.post_flags)
|
||||
return args
|
||||
|
||||
# List of inputs to pass to the darwin linker via the `-filelist` param.
|
||||
# TODO(agallagher): It might be nicer to leave these inlined in the args
|
||||
# above and extract them at link time via reflection. This way we'd hide
|
||||
# platform-specific details from this level.
|
||||
# NOTE(agallagher): Using filelist out-of-band means objects/archives get
|
||||
# linked out of order of their corresponding flags.
|
||||
def link_info_filelist(value: LinkInfo.type) -> ["artifact"]:
|
||||
filelists = []
|
||||
for linkable in value.linkables:
|
||||
if linkable._type == LinkableType("archive"):
|
||||
if linkable.linker_type == "darwin" and not linkable.link_whole:
|
||||
filelists.append(linkable.archive.artifact)
|
||||
elif linkable._type == LinkableType("shared"):
|
||||
pass
|
||||
elif linkable._type == LinkableType("objects"):
|
||||
if linkable.linker_type == "darwin":
|
||||
filelists += linkable.objects
|
||||
elif linkable._type == LinkableType("frameworks"):
|
||||
pass
|
||||
else:
|
||||
fail("unreachable")
|
||||
return filelists
|
||||
|
||||
# Encapsulate all `LinkInfo`s provided by a given rule's link style.
|
||||
#
|
||||
# We provide both the "default" and (optionally) a pre-"stripped" LinkInfo. For a consumer that doesn't care
|
||||
# about debug info (for example, who is going to produce stripped output anyway), it can be significantly
|
||||
# cheaper to consume the pre-stripped LinkInfo.
|
||||
LinkInfos = record(
|
||||
# Link info to use by default.
|
||||
default = field(LinkInfo.type),
|
||||
# Link info stripped of debug symbols.
|
||||
stripped = field([LinkInfo.type, None], None),
|
||||
)
|
||||
|
||||
# The output of a native link (e.g. a shared library or an executable).
|
||||
LinkedObject = record(
|
||||
output = field("artifact"),
|
||||
# the generated linked output before running bolt, may be None if bolt is not used.
|
||||
prebolt_output = field(["artifact", None], None),
|
||||
# A linked object (binary/shared library) may have an associated dwp file with
|
||||
# its corresponding DWARF debug info.
|
||||
# May be None when Split DWARF is disabled or for some types of synthetic link objects.
|
||||
dwp = field(["artifact", None], None),
|
||||
# Additional dirs or paths that contain debug info referenced by the linked
|
||||
# object (e.g. split dwarf files).
|
||||
external_debug_info = field(["_arglike"], []),
|
||||
# This argsfile is generated in the `cxx_link` step and contains a list of arguments
|
||||
# passed to the linker. It is being exposed as a sub-target for debugging purposes.
|
||||
linker_argsfile = field(["artifact", None], None),
|
||||
# This sub-target is only available for distributed thinLTO builds.
|
||||
index_argsfile = field(["artifact", None], None),
|
||||
# Import library for linking with DLL on Windows.
|
||||
# If not on Windows it's always None.
|
||||
import_library = field(["artifact", None], None),
|
||||
)
|
||||
|
||||
def _link_info_default_args(infos: "LinkInfos"):
|
||||
info = infos.default
|
||||
return link_info_to_args(info)
|
||||
|
||||
def _link_info_default_shared_link_args(infos: "LinkInfos"):
|
||||
info = infos.default
|
||||
return link_info_to_args(info)
|
||||
|
||||
def _link_info_stripped_args(infos: "LinkInfos"):
|
||||
info = infos.stripped or infos.default
|
||||
return link_info_to_args(info)
|
||||
|
||||
def _link_info_stripped_shared_link_args(infos: "LinkInfos"):
|
||||
info = infos.stripped or infos.default
|
||||
return link_info_to_args(info)
|
||||
|
||||
def _link_info_default_filelist(infos: "LinkInfos"):
|
||||
info = infos.default
|
||||
return link_info_filelist(info)
|
||||
|
||||
def _link_info_stripped_filelist(infos: "LinkInfos"):
|
||||
info = infos.stripped or infos.default
|
||||
return link_info_filelist(info)
|
||||
|
||||
def _link_info_has_default_filelist(children: [bool.type], infos: ["LinkInfos", None]) -> bool.type:
|
||||
if infos:
|
||||
info = infos.default
|
||||
if link_info_filelist(info):
|
||||
return True
|
||||
return any(children)
|
||||
|
||||
def _link_info_has_stripped_filelist(children: [bool.type], infos: ["LinkInfos", None]) -> bool.type:
|
||||
if infos:
|
||||
info = infos.stripped or infos.default
|
||||
if link_info_filelist(info):
|
||||
return True
|
||||
return any(children)
|
||||
|
||||
def _link_info_has_external_debug_info(children: [bool.type], infos: ["LinkInfos", None]) -> bool.type:
|
||||
if infos and infos.default.external_debug_info:
|
||||
return True
|
||||
return any(children)
|
||||
|
||||
def _link_info_external_debug_info(infos: "LinkInfos"):
|
||||
return infos.default.external_debug_info
|
||||
|
||||
# TransitiveSet of LinkInfos.
|
||||
LinkInfosTSet = transitive_set(
|
||||
args_projections = {
|
||||
"default": _link_info_default_args,
|
||||
"default_filelist": _link_info_default_filelist,
|
||||
"default_shared": _link_info_default_shared_link_args,
|
||||
"external_debug_info": _link_info_external_debug_info,
|
||||
"stripped": _link_info_stripped_args,
|
||||
"stripped_filelist": _link_info_stripped_filelist,
|
||||
"stripped_shared": _link_info_stripped_shared_link_args,
|
||||
},
|
||||
reductions = {
|
||||
"has_default_filelist": _link_info_has_default_filelist,
|
||||
"has_external_debug_info": _link_info_has_external_debug_info,
|
||||
"has_stripped_filelist": _link_info_has_stripped_filelist,
|
||||
},
|
||||
)
|
||||
|
||||
# A map of native linkable infos from transitive dependencies.
|
||||
MergedLinkInfo = provider(fields = [
|
||||
"_infos", # {LinkStyle.type: LinkInfosTSet.type}
|
||||
# Apple framework linker args must be deduped to avoid overflow in our argsfiles.
|
||||
#
|
||||
# To save on repeated computation of transitive LinkInfos, we store a dedupped
|
||||
# structure, based on the link-style.
|
||||
"frameworks", # {LinkStyle.type: [FrameworksLinkable.type, None]}
|
||||
])
|
||||
|
||||
# A map of linkages to all possible link styles it supports.
|
||||
_LINK_STYLE_FOR_LINKAGE = {
|
||||
Linkage("any"): [LinkStyle("static"), LinkStyle("static_pic"), LinkStyle("shared")],
|
||||
Linkage("static"): [LinkStyle("static"), LinkStyle("static_pic")],
|
||||
Linkage("shared"): [LinkStyle("shared")],
|
||||
}
|
||||
|
||||
def create_merged_link_info(
|
||||
# Target context for which to create the link info.
|
||||
ctx: "context",
|
||||
# The link infos provided by this rule, as a map from link style (as
|
||||
# used by dependents) to `LinkInfo`.
|
||||
link_infos: {LinkStyle.type: LinkInfos.type} = {},
|
||||
# How the rule requests to be linked. This will be used to determine
|
||||
# which actual link style to propagate for each "requested" link style.
|
||||
preferred_linkage: Linkage.type = Linkage("any"),
|
||||
# Link info to propagate from non-exported deps for static link styles.
|
||||
deps: ["MergedLinkInfo"] = [],
|
||||
# Link info to always propagate from exported deps.
|
||||
exported_deps: ["MergedLinkInfo"] = [],
|
||||
frameworks_linkable: [FrameworksLinkable.type, None] = None) -> "MergedLinkInfo":
|
||||
"""
|
||||
Create a `MergedLinkInfo` provider.
|
||||
"""
|
||||
|
||||
infos = {}
|
||||
frameworks = {}
|
||||
|
||||
# We don't know how this target will be linked, so we generate the possible
|
||||
# link info given the target's preferred linkage, to be consumed by the
|
||||
# ultimate linking target.
|
||||
for link_style in LinkStyle:
|
||||
actual_link_style = get_actual_link_style(link_style, preferred_linkage)
|
||||
|
||||
children = []
|
||||
framework_linkables = []
|
||||
|
||||
# When we're being linked statically, we also need to export all private
|
||||
# linkable input (e.g. so that any unresolved symbols we have are
|
||||
# resolved properly when we're linked).
|
||||
if actual_link_style != LinkStyle("shared"):
|
||||
# We never want to propogate the linkables used to build a shared library.
|
||||
#
|
||||
# Doing so breaks the encapsulation of what is in linked in the library vs. the main executable.
|
||||
framework_linkables.append(frameworks_linkable)
|
||||
framework_linkables += [dep_info.frameworks[link_style] for dep_info in exported_deps]
|
||||
|
||||
for dep_info in deps:
|
||||
children.append(dep_info._infos[link_style])
|
||||
framework_linkables.append(dep_info.frameworks[link_style])
|
||||
|
||||
# We always export link info for exported deps.
|
||||
for dep_info in exported_deps:
|
||||
children.append(dep_info._infos[link_style])
|
||||
|
||||
frameworks[link_style] = merge_framework_linkables(framework_linkables)
|
||||
infos[link_style] = ctx.actions.tset(
|
||||
LinkInfosTSet,
|
||||
value = link_infos[actual_link_style],
|
||||
children = children,
|
||||
)
|
||||
|
||||
return MergedLinkInfo(_infos = infos, frameworks = frameworks)
|
||||
|
||||
def merge_link_infos(
|
||||
ctx: "context",
|
||||
xs: ["MergedLinkInfo"]) -> "MergedLinkInfo":
|
||||
merged = {}
|
||||
frameworks = {}
|
||||
for link_style in LinkStyle:
|
||||
merged[link_style] = ctx.actions.tset(
|
||||
LinkInfosTSet,
|
||||
children = [x._infos[link_style] for x in xs],
|
||||
)
|
||||
frameworks[link_style] = merge_framework_linkables([x.frameworks[link_style] for x in xs])
|
||||
return MergedLinkInfo(_infos = merged, frameworks = frameworks)
|
||||
|
||||
def get_link_info(
|
||||
infos: LinkInfos.type,
|
||||
prefer_stripped: bool.type = False) -> LinkInfo.type:
|
||||
"""
|
||||
Helper for getting a `LinkInfo` out of a `LinkInfos`.
|
||||
"""
|
||||
|
||||
# When requested, prefer using pre-stripped link info.
|
||||
if prefer_stripped and infos.stripped != None:
|
||||
return infos.stripped
|
||||
|
||||
return infos.default
|
||||
|
||||
# An enum. Only one field should be set. The variants here represent different
|
||||
# ways in which we might obtain linker commands: through a t-set of propagated
|
||||
# dependencies (used for deps propagated unconditionally up a tree), through a
|
||||
# series of LinkInfo (used for link groups, Omnibus linking), or simply through
|
||||
# raw arguments we want to include (used for e.g. per-target link flags).
|
||||
LinkArgs = record(
|
||||
# A LinkInfosTSet + a flag indicating if stripped is preferred.
|
||||
tset = field([(LinkInfosTSet.type, bool.type), None], None),
|
||||
# A list of LinkInfos
|
||||
infos = field([[LinkInfo.type], None], None),
|
||||
# A bunch of flags.
|
||||
flags = field(["_arglike", None], None),
|
||||
)
|
||||
|
||||
def unpack_link_args(args: LinkArgs.type, is_shared: [bool.type, None] = None, link_ordering: [LinkOrdering.type, None] = None) -> "_arglike":
|
||||
if args.tset != None:
|
||||
(tset, stripped) = args.tset
|
||||
ordering = link_ordering.value if link_ordering else "preorder"
|
||||
|
||||
if is_shared:
|
||||
if stripped:
|
||||
return tset.project_as_args("stripped_shared", ordering = ordering)
|
||||
return tset.project_as_args("default_shared", ordering = ordering)
|
||||
else:
|
||||
if stripped:
|
||||
return tset.project_as_args("stripped", ordering = ordering)
|
||||
return tset.project_as_args("default", ordering = ordering)
|
||||
|
||||
if args.infos != None:
|
||||
return cmd_args([link_info_to_args(info) for info in args.infos])
|
||||
|
||||
if args.flags != None:
|
||||
return args.flags
|
||||
|
||||
fail("Unpacked invalid empty link args")
|
||||
|
||||
def unpack_link_args_filelist(args: LinkArgs.type) -> ["_arglike", None]:
|
||||
if args.tset != None:
|
||||
(tset, stripped) = args.tset
|
||||
if not tset.reduce("has_stripped_filelist" if stripped else "has_default_filelist"):
|
||||
return None
|
||||
return tset.project_as_args("stripped_filelist" if stripped else "default_filelist")
|
||||
|
||||
if args.infos != None:
|
||||
filelist = flatten([link_info_filelist(info) for info in args.infos])
|
||||
if not filelist:
|
||||
return None
|
||||
|
||||
# Actually create cmd_args so the API is consistent between the 2 branches.
|
||||
args = cmd_args()
|
||||
args.add(filelist)
|
||||
return args
|
||||
|
||||
if args.flags != None:
|
||||
return None
|
||||
|
||||
fail("Unpacked invalid empty link args")
|
||||
|
||||
def unpack_external_debug_info(args: LinkArgs.type) -> ["_arglike"]:
|
||||
if args.tset != None:
|
||||
(tset, stripped) = args.tset
|
||||
if stripped:
|
||||
return []
|
||||
if not tset.reduce("has_external_debug_info"):
|
||||
return []
|
||||
return [tset.project_as_args("external_debug_info")]
|
||||
|
||||
if args.infos != None:
|
||||
return flatten([info.external_debug_info for info in args.infos])
|
||||
|
||||
if args.flags != None:
|
||||
return []
|
||||
|
||||
fail("Unpacked invalid empty link args")
|
||||
|
||||
def map_to_link_infos(links: [LinkArgs.type]) -> ["LinkInfo"]:
|
||||
res = []
|
||||
|
||||
def append(v):
|
||||
if v.pre_flags or v.post_flags or v.linkables:
|
||||
res.append(v)
|
||||
|
||||
for link in links:
|
||||
if link.tset != None:
|
||||
tset, stripped = link.tset
|
||||
for info in tset.traverse():
|
||||
if stripped:
|
||||
append(info.stripped or info.default)
|
||||
else:
|
||||
append(info.default)
|
||||
continue
|
||||
if link.infos != None:
|
||||
for link in link.infos:
|
||||
append(link)
|
||||
continue
|
||||
if link.flags != None:
|
||||
append(LinkInfo(pre_flags = link.flags))
|
||||
continue
|
||||
fail("Unpacked invalid empty link args")
|
||||
return res
|
||||
|
||||
def get_link_args(
|
||||
merged: "MergedLinkInfo",
|
||||
link_style: LinkStyle.type,
|
||||
prefer_stripped: bool.type = False) -> LinkArgs.type:
|
||||
"""
|
||||
Return `LinkArgs` for `MergedLinkInfo` given a link style and a strip preference.
|
||||
"""
|
||||
|
||||
return LinkArgs(
|
||||
tset = (merged._infos[link_style], prefer_stripped),
|
||||
)
|
||||
|
||||
def get_actual_link_style(
|
||||
requested_link_style: LinkStyle.type,
|
||||
preferred_linkage: Linkage.type) -> LinkStyle.type:
|
||||
"""
|
||||
Return how we link a library for a requested link style and preferred linkage.
|
||||
--------------------------------------------------------
|
||||
| preferred_linkage | link_style |
|
||||
| |----------------------------------|
|
||||
| | static | static_pic | shared |
|
||||
-------------------------------------------------------|
|
||||
| static | static | static_pic | static_pic |
|
||||
| shared | shared | shared | shared |
|
||||
| any | static | static_pic | shared |
|
||||
--------------------------------------------------------
|
||||
"""
|
||||
if preferred_linkage == Linkage("any"):
|
||||
return requested_link_style
|
||||
elif preferred_linkage == Linkage("shared"):
|
||||
return LinkStyle("shared")
|
||||
else: # preferred_linkage = static
|
||||
if requested_link_style == LinkStyle("static"):
|
||||
return requested_link_style
|
||||
else:
|
||||
return LinkStyle("static_pic")
|
||||
|
||||
def get_link_styles_for_linkage(linkage: Linkage.type) -> [LinkStyle.type]:
|
||||
"""
|
||||
Return all possible `LinkStyle`s that apply for the given `Linkage`.
|
||||
"""
|
||||
return _LINK_STYLE_FOR_LINKAGE[linkage]
|
||||
|
||||
def merge_framework_linkables(linkables: [[FrameworksLinkable.type, None]]) -> FrameworksLinkable.type:
|
||||
unique_framework_names = {}
|
||||
unique_framework_paths = {}
|
||||
unique_library_names = {}
|
||||
for linkable in linkables:
|
||||
if not linkable:
|
||||
continue
|
||||
|
||||
# Avoid building a huge list and then de-duplicating, instead we
|
||||
# use a set to track each used entry, order does not matter.
|
||||
for framework in linkable.framework_names:
|
||||
unique_framework_names[framework] = True
|
||||
for framework_path in linkable.unresolved_framework_paths:
|
||||
unique_framework_paths[framework_path] = True
|
||||
for library_name in linkable.library_names:
|
||||
unique_library_names[library_name] = True
|
||||
|
||||
return FrameworksLinkable(
|
||||
framework_names = unique_framework_names.keys(),
|
||||
unresolved_framework_paths = unique_framework_paths.keys(),
|
||||
library_names = unique_library_names.keys(),
|
||||
)
|
||||
15
vendor/cxx/tools/buck/prelude/linking/link_postprocessor.bzl
vendored
Normal file
15
vendor/cxx/tools/buck/prelude/linking/link_postprocessor.bzl
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def postprocess(ctx, input, postprocessor):
|
||||
output = ctx.actions.declare_output("postprocessed/{}".format(input.short_path))
|
||||
cmd = cmd_args()
|
||||
cmd.add(postprocessor)
|
||||
cmd.add(["--input", input])
|
||||
cmd.add(["--output", output.as_output()])
|
||||
ctx.actions.run(cmd, category = "link_postprocess", identifier = input.short_path)
|
||||
return output
|
||||
227
vendor/cxx/tools/buck/prelude/linking/linkable_graph.bzl
vendored
Normal file
227
vendor/cxx/tools/buck/prelude/linking/linkable_graph.bzl
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//python:python.bzl", "PythonLibraryInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load(
|
||||
":link_info.bzl",
|
||||
"LinkInfo", # @unused Used as a type
|
||||
"LinkInfos",
|
||||
"LinkStyle",
|
||||
"Linkage",
|
||||
"LinkedObject",
|
||||
"MergedLinkInfo",
|
||||
"get_actual_link_style",
|
||||
"get_link_styles_for_linkage",
|
||||
_get_link_info = "get_link_info",
|
||||
)
|
||||
|
||||
# A provider with information used to link a rule into a shared library.
|
||||
# Potential omnibus roots must provide this so that omnibus can link them
|
||||
# here, in the context of the top-level packaging rule.
|
||||
LinkableRootInfo = provider(fields = [
|
||||
"link_infos", # LinkInfos.type
|
||||
"name", # [str.type, None]
|
||||
"deps", # ["label"]
|
||||
"shared_root", # SharedOmnibusRoot.type, either this or no_shared_root_reason is set.
|
||||
"no_shared_root_reason", # OmnibusPrivateRootProductCause.type
|
||||
])
|
||||
|
||||
# This annotation is added on an AnnotatedLinkableRoot to indicate what
|
||||
# dependend resulted in it being discovered as an implicit root. For example,
|
||||
# if Python library A depends on C++ library B, then in the
|
||||
# AnnotatedLinkableRoot for B, we'll have A as the dependent.
|
||||
LinkableRootAnnotation = record(
|
||||
dependent = field(""),
|
||||
)
|
||||
|
||||
AnnotatedLinkableRoot = record(
|
||||
root = field(LinkableRootInfo.type),
|
||||
annotation = field([LinkableRootAnnotation.type, None], None),
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Linkable Graph collects information on a node in the target graph that
|
||||
# contains linkable output. This graph information may then be provided to any
|
||||
# consumers of this target.
|
||||
###############################################################################
|
||||
|
||||
LinkableNode = record(
|
||||
# Attribute labels on the target.
|
||||
labels = field([str.type], []),
|
||||
# Prefered linkage for this target.
|
||||
preferred_linkage = field(Linkage.type, Linkage("any")),
|
||||
# Linkable deps of this target.
|
||||
deps = field(["label"], []),
|
||||
# Exported linkable deps of this target.
|
||||
#
|
||||
# We distinguish between deps and exported deps so that when creating shared
|
||||
# libraries in a large graph we only need to link each library against its
|
||||
# deps and their (transitive) exported deps. This helps keep link lines smaller
|
||||
# and produces more efficient libs (for example, DT_NEEDED stays a manageable size).
|
||||
exported_deps = field(["label"], []),
|
||||
# Link infos for all supported link styles.
|
||||
link_infos = field({LinkStyle.type: LinkInfos.type}, {}),
|
||||
# Shared libraries provided by this target. Used if this target is
|
||||
# excluded.
|
||||
shared_libs = field({str.type: LinkedObject.type}, {}),
|
||||
)
|
||||
|
||||
LinkableGraphNode = record(
|
||||
# Target/label of this node
|
||||
label = field("label"),
|
||||
|
||||
# If this node has linkable output, it's linkable data
|
||||
linkable = field([LinkableNode.type, None], None),
|
||||
|
||||
# All potential root notes for an omnibus link (e.g. C++ libraries,
|
||||
# C++ Python extensions).
|
||||
roots = field({"label": AnnotatedLinkableRoot.type}, {}),
|
||||
|
||||
# Exclusions this node adds to the Omnibus graph
|
||||
excluded = field({"label": None}, {}),
|
||||
)
|
||||
|
||||
LinkableGraphTSet = transitive_set()
|
||||
|
||||
# The LinkableGraph for a target holds all the transitive nodes, roots, and exclusions
|
||||
# from all of its dependencies.
|
||||
#
|
||||
# TODO(cjhopman): Rather than flattening this at each node, we should build up an actual
|
||||
# graph structure.
|
||||
LinkableGraph = provider(fields = [
|
||||
# Target identifier of the graph.
|
||||
"label", # "label"
|
||||
"nodes", # "LinkableGraphTSet"
|
||||
])
|
||||
|
||||
def create_linkable_node(
|
||||
ctx: "context",
|
||||
preferred_linkage: Linkage.type = Linkage("any"),
|
||||
deps: ["dependency"] = [],
|
||||
exported_deps: ["dependency"] = [],
|
||||
link_infos: {LinkStyle.type: LinkInfos.type} = {},
|
||||
shared_libs: {str.type: LinkedObject.type} = {}) -> LinkableNode.type:
|
||||
for link_style in get_link_styles_for_linkage(preferred_linkage):
|
||||
expect(
|
||||
link_style in link_infos,
|
||||
"must have {} link info".format(link_style),
|
||||
)
|
||||
return LinkableNode(
|
||||
labels = ctx.attrs.labels,
|
||||
preferred_linkage = preferred_linkage,
|
||||
deps = linkable_deps(deps),
|
||||
exported_deps = linkable_deps(exported_deps),
|
||||
link_infos = link_infos,
|
||||
shared_libs = shared_libs,
|
||||
)
|
||||
|
||||
def create_linkable_graph_node(
|
||||
ctx: "context",
|
||||
linkable_node: [LinkableNode.type, None] = None,
|
||||
roots: {"label": AnnotatedLinkableRoot.type} = {},
|
||||
excluded: {"label": None} = {}) -> LinkableGraphNode.type:
|
||||
return LinkableGraphNode(
|
||||
label = ctx.label,
|
||||
linkable = linkable_node,
|
||||
roots = roots,
|
||||
excluded = excluded,
|
||||
)
|
||||
|
||||
def create_linkable_graph(
|
||||
ctx: "context",
|
||||
node: [LinkableGraphNode.type, None] = None,
|
||||
deps: ["dependency"] = [],
|
||||
children: [LinkableGraph.type] = []) -> LinkableGraph.type:
|
||||
all_children_graphs = filter(None, [x.get(LinkableGraph) for x in deps]) + children
|
||||
kwargs = {
|
||||
"children": [child_node.nodes for child_node in all_children_graphs],
|
||||
}
|
||||
if node:
|
||||
kwargs["value"] = node
|
||||
return LinkableGraph(
|
||||
label = ctx.label,
|
||||
nodes = ctx.actions.tset(LinkableGraphTSet, **kwargs),
|
||||
)
|
||||
|
||||
def get_linkable_graph_node_map_func(graph: LinkableGraph.type):
|
||||
def get_linkable_graph_node_map() -> {"label": LinkableNode.type}:
|
||||
nodes = graph.nodes.traverse()
|
||||
linkable_nodes = {}
|
||||
for node in filter(None, nodes):
|
||||
if node.linkable:
|
||||
linkable_nodes[node.label] = node.linkable
|
||||
return linkable_nodes
|
||||
|
||||
return get_linkable_graph_node_map
|
||||
|
||||
def linkable_deps(deps: ["dependency"]) -> ["label"]:
|
||||
labels = []
|
||||
|
||||
for dep in deps:
|
||||
dep_info = linkable_graph(dep)
|
||||
if dep_info != None:
|
||||
labels.append(dep_info.label)
|
||||
|
||||
return labels
|
||||
|
||||
def linkable_graph(dep: "dependency") -> [LinkableGraph.type, None]:
|
||||
"""
|
||||
Helper to extract `LinkableGraph` from a dependency which also
|
||||
provides `MergedLinkInfo`.
|
||||
"""
|
||||
|
||||
# We only care about "linkable" deps.
|
||||
if PythonLibraryInfo in dep or MergedLinkInfo not in dep:
|
||||
return None
|
||||
|
||||
expect(
|
||||
LinkableGraph in dep,
|
||||
"{} provides `MergedLinkInfo`".format(dep.label) +
|
||||
" but doesn't also provide `LinkableGraph`",
|
||||
)
|
||||
|
||||
return dep[LinkableGraph]
|
||||
|
||||
def get_link_info(
|
||||
node: LinkableNode.type,
|
||||
link_style: LinkStyle.type,
|
||||
prefer_stripped: bool.type = False,
|
||||
force_no_link_groups = False) -> LinkInfo.type:
|
||||
info = _get_link_info(
|
||||
node.link_infos[link_style],
|
||||
prefer_stripped = prefer_stripped,
|
||||
)
|
||||
|
||||
if force_no_link_groups and info.use_link_groups:
|
||||
return LinkInfo(
|
||||
name = info.name,
|
||||
pre_flags = info.pre_flags,
|
||||
post_flags = info.post_flags,
|
||||
linkables = info.linkables,
|
||||
use_link_groups = False,
|
||||
)
|
||||
return info
|
||||
|
||||
def get_deps_for_link(
|
||||
node: LinkableNode.type,
|
||||
link_style: LinkStyle.type) -> ["label"]:
|
||||
"""
|
||||
Return deps to follow when linking against this node with the given link
|
||||
style.
|
||||
"""
|
||||
|
||||
# Avoid making a copy of the list until we know have to modify it.
|
||||
deps = node.exported_deps
|
||||
|
||||
# If we're linking statically, include non-exported deps.
|
||||
actual = get_actual_link_style(link_style, node.preferred_linkage)
|
||||
if actual != LinkStyle("shared") and node.deps:
|
||||
# Important that we don't mutate deps, but create a new list
|
||||
deps = deps + node.deps
|
||||
|
||||
return deps
|
||||
53
vendor/cxx/tools/buck/prelude/linking/linkables.bzl
vendored
Normal file
53
vendor/cxx/tools/buck/prelude/linking/linkables.bzl
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//utils:utils.bzl",
|
||||
"expect",
|
||||
)
|
||||
load(
|
||||
":link_groups.bzl",
|
||||
"LinkGroupLibInfo",
|
||||
)
|
||||
load(
|
||||
":link_info.bzl",
|
||||
"MergedLinkInfo",
|
||||
)
|
||||
load(
|
||||
":linkable_graph.bzl",
|
||||
"LinkableGraph",
|
||||
"LinkableRootInfo",
|
||||
)
|
||||
load(
|
||||
":shared_libraries.bzl",
|
||||
"SharedLibraryInfo",
|
||||
)
|
||||
|
||||
# A record containing all provider types used for linking in the prelude. This
|
||||
# is essentially the minimal subset of a "linkable" `dependency` that user rules
|
||||
# need to implement linking, and avoids needing functions to take the heavier-
|
||||
# weight `dependency` type.
|
||||
LinkableProviders = record(
|
||||
link_group_lib_info = field(LinkGroupLibInfo.type),
|
||||
linkable_graph = field(LinkableGraph.type),
|
||||
merged_link_info = field(MergedLinkInfo.type),
|
||||
shared_library_info = field(SharedLibraryInfo.type),
|
||||
linkable_root_info = field([LinkableRootInfo.type, None], None),
|
||||
)
|
||||
|
||||
def linkable(dep: "dependency") -> LinkableProviders.type:
|
||||
expect(LinkGroupLibInfo in dep, str(dep.label.raw_target()))
|
||||
return LinkableProviders(
|
||||
shared_library_info = dep[SharedLibraryInfo],
|
||||
linkable_graph = dep[LinkableGraph],
|
||||
merged_link_info = dep[MergedLinkInfo],
|
||||
link_group_lib_info = dep[LinkGroupLibInfo],
|
||||
linkable_root_info = dep.get(LinkableRootInfo),
|
||||
)
|
||||
|
||||
def linkables(deps: ["dependency"]) -> [LinkableProviders.type]:
|
||||
return [linkable(dep) for dep in deps if MergedLinkInfo in dep]
|
||||
19
vendor/cxx/tools/buck/prelude/linking/lto.bzl
vendored
Normal file
19
vendor/cxx/tools/buck/prelude/linking/lto.bzl
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# Styles of LTO.
|
||||
LtoMode = enum(
|
||||
# No LTO
|
||||
"none",
|
||||
# Object files contain both LTO IR and native code to allow binaries to link
|
||||
# either via standard or LTO.
|
||||
"fat",
|
||||
# Traditional, monolithic LTO.
|
||||
"monolithic",
|
||||
# https://clang.llvm.org/docs/ThinLTO.html
|
||||
"thin",
|
||||
)
|
||||
120
vendor/cxx/tools/buck/prelude/linking/shared_libraries.bzl
vendored
Normal file
120
vendor/cxx/tools/buck/prelude/linking/shared_libraries.bzl
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxToolchainInfo")
|
||||
load(
|
||||
"@prelude//linking:link_info.bzl",
|
||||
"LinkedObject", # @unused Used as a type
|
||||
)
|
||||
load("@prelude//linking:strip.bzl", "strip_shared_library")
|
||||
load(
|
||||
"@prelude//utils:types.bzl",
|
||||
"unchecked", # @unused Used as a type
|
||||
)
|
||||
|
||||
SharedLibrary = record(
|
||||
lib = field(LinkedObject.type),
|
||||
stripped_lib = field(["artifact", None]),
|
||||
can_be_asset = field(bool.type),
|
||||
for_primary_apk = field(bool.type),
|
||||
label = field("label"),
|
||||
)
|
||||
|
||||
SharedLibraries = record(
|
||||
# A mapping of shared library SONAME (e.g. `libfoo.so.2`) to the artifact.
|
||||
# Since the SONAME is what the dynamic loader uses to uniquely identify
|
||||
# libraries, using this as the key allows easily detecting conflicts from
|
||||
# dependencies.
|
||||
libraries = field({str.type: SharedLibrary.type}),
|
||||
)
|
||||
|
||||
# T-set of SharedLibraries
|
||||
SharedLibrariesTSet = transitive_set()
|
||||
|
||||
# Shared libraries required by top-level packaging rules (e.g. shared libs
|
||||
# for Python binary, symlink trees of shared libs for C++ binaries)
|
||||
SharedLibraryInfo = provider(fields = [
|
||||
"set", # [SharedLibrariesTSet.type, None]
|
||||
])
|
||||
|
||||
def create_shared_libraries(
|
||||
ctx: "context",
|
||||
libraries: {str.type: LinkedObject.type}) -> SharedLibraries.type:
|
||||
"""
|
||||
Take a mapping of dest -> src and turn it into a mapping that will be
|
||||
passed around in providers. Used for both srcs, and resources.
|
||||
"""
|
||||
cxx_toolchain = getattr(ctx.attrs, "_cxx_toolchain", None)
|
||||
return SharedLibraries(
|
||||
libraries = {name: SharedLibrary(
|
||||
lib = shlib,
|
||||
stripped_lib = strip_shared_library(
|
||||
ctx,
|
||||
cxx_toolchain[CxxToolchainInfo],
|
||||
shlib.output,
|
||||
cmd_args(["--strip-unneeded"]),
|
||||
) if cxx_toolchain != None else None,
|
||||
can_be_asset = getattr(ctx.attrs, "can_be_asset", False) or False,
|
||||
for_primary_apk = getattr(ctx.attrs, "used_by_wrap_script", False),
|
||||
label = ctx.label,
|
||||
) for (name, shlib) in libraries.items()},
|
||||
)
|
||||
|
||||
# We do a lot of merging library maps, so don't use O(n) type annotations
|
||||
def _merge_lib_map(
|
||||
dest_mapping: unchecked({str.type: SharedLibrary.type}),
|
||||
mapping_to_merge: unchecked({str.type: SharedLibrary.type})) -> None:
|
||||
"""
|
||||
Merges a mapping_to_merge into `dest_mapping`. Fails if different libraries
|
||||
map to the same name.
|
||||
"""
|
||||
for (name, src) in mapping_to_merge.items():
|
||||
existing = dest_mapping.get(name)
|
||||
if existing != None and existing.lib != src.lib:
|
||||
error = (
|
||||
"Duplicate library {}! Conflicting mappings:\n" +
|
||||
"{} from {}\n" +
|
||||
"{} from {}"
|
||||
)
|
||||
fail(
|
||||
error.format(
|
||||
name,
|
||||
existing.lib,
|
||||
existing.label,
|
||||
src.lib,
|
||||
src.label,
|
||||
),
|
||||
)
|
||||
dest_mapping[name] = src
|
||||
|
||||
# Merge multiple SharedLibraryInfo. The value in `node` represents a set of
|
||||
# SharedLibraries that is provided by the target being analyzed. It's optional
|
||||
# because that might not always exist, e.g. a Python library can pass through
|
||||
# SharedLibraryInfo but it cannot produce any. The value in `deps` represents
|
||||
# all the inherited shared libraries for this target.
|
||||
def merge_shared_libraries(
|
||||
actions: "actions",
|
||||
node: ["SharedLibraries", None] = None,
|
||||
deps: ["SharedLibraryInfo"] = []) -> "SharedLibraryInfo":
|
||||
kwargs = {}
|
||||
|
||||
children = filter(None, [dep.set for dep in deps])
|
||||
if children:
|
||||
kwargs["children"] = children
|
||||
if node:
|
||||
kwargs["value"] = node
|
||||
|
||||
set = actions.tset(SharedLibrariesTSet, **kwargs) if kwargs else None
|
||||
return SharedLibraryInfo(set = set)
|
||||
|
||||
def traverse_shared_library_info(
|
||||
info: "SharedLibraryInfo"): # -> {str.type: SharedLibrary.type}:
|
||||
libraries = {}
|
||||
if info.set:
|
||||
for libs in info.set.traverse():
|
||||
_merge_lib_map(libraries, libs.libraries)
|
||||
return libraries
|
||||
35
vendor/cxx/tools/buck/prelude/linking/strip.bzl
vendored
Normal file
35
vendor/cxx/tools/buck/prelude/linking/strip.bzl
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//cxx:cxx_context.bzl", "get_cxx_toolchain_info")
|
||||
|
||||
def strip_debug_info(ctx: "context", name: str.type, obj: "artifact") -> "artifact":
|
||||
"""
|
||||
Strip debug information from an object.
|
||||
"""
|
||||
strip = get_cxx_toolchain_info(ctx).binary_utilities_info.strip
|
||||
output = ctx.actions.declare_output(name)
|
||||
cmd = cmd_args([strip, "-S", "-o", output.as_output(), obj])
|
||||
ctx.actions.run(cmd, category = "strip_debug", identifier = name)
|
||||
return output
|
||||
|
||||
def strip_shared_library(ctx: "context", cxx_toolchain: "CxxToolchainInfo", shared_lib: "artifact", strip_flags: "cmd_args") -> "artifact":
|
||||
"""
|
||||
Strip unneeded information from a shared library.
|
||||
"""
|
||||
strip = cxx_toolchain.binary_utilities_info.strip
|
||||
stripped_lib = ctx.actions.declare_output("stripped/{}".format(shared_lib.short_path))
|
||||
|
||||
# TODO(T109996375) support configuring the flags used for stripping
|
||||
cmd = cmd_args()
|
||||
cmd.add(strip)
|
||||
cmd.add(strip_flags)
|
||||
cmd.add([shared_lib, "-o", stripped_lib.as_output()])
|
||||
|
||||
ctx.actions.run(cmd, category = "strip_shared_lib", identifier = shared_lib.short_path)
|
||||
|
||||
return stripped_lib
|
||||
Loading…
Add table
Add a link
Reference in a new issue