Skip to main content
Glama
cxx_executable.bzl37.8 kB
# 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//:artifact_tset.bzl", "ArtifactTSet", "make_artifact_tset", "project_artifacts", ) load("@prelude//:local_only.bzl", "get_resolved_cxx_binary_link_execution_preference") load( "@prelude//:resources.bzl", "create_resource_db", "gather_resources", ) load( "@prelude//apple:apple_frameworks.bzl", "apple_build_link_args_with_deduped_flags", "apple_create_frameworks_linkable", "apple_get_link_info_by_deduping_link_infos", ) load( "@prelude//cxx:cxx_bolt.bzl", "cxx_use_bolt", ) load( "@prelude//cxx:cxx_toolchain_types.bzl", "PicBehavior", ) load( "@prelude//cxx:link_groups_types.bzl", "LinkGroupsDebugLinkInfo", "LinkGroupsDebugLinkableItem", ) load( "@prelude//cxx:runtime_dependency_handling.bzl", "RuntimeDependencyHandling", ) load( "@prelude//dist:dist_info.bzl", "DistInfo", ) load( "@prelude//ide_integrations/xcode:argsfiles.bzl", "XCODE_ARGSFILES_SUB_TARGET", ) load( "@prelude//ide_integrations/xcode:data.bzl", "XCODE_DATA_SUB_TARGET", "XcodeDataInfo", "generate_xcode_data", ) load( "@prelude//linking:link_groups.bzl", "gather_link_group_libs", ) load( "@prelude//linking:link_info.bzl", "LibOutputStyle", "LinkArgs", "LinkCommandDebugOutput", "LinkInfo", "LinkOrdering", # @unused Used as a type "LinkStrategy", "LinkedObject", # @unused Used as a type "ObjectsLinkable", "get_lib_output_style", "make_link_command_debug_output", "make_link_command_debug_output_json_info", "process_link_strategy_for_pic_behavior", "to_link_strategy", ) load( "@prelude//linking:linkable_graph.bzl", "create_linkable_graph", "get_linkable_graph_node_map_func", "reduce_linkable_graph", ) load( "@prelude//linking:linkables.bzl", "linkables", ) load( "@prelude//linking:shared_libraries.bzl", "SharedLibrary", # @unused Used as a type "merge_shared_libraries", "traverse_shared_library_info", ) load("@prelude//utils:arglike.bzl", "ArgLike") # @unused Used as a type load( "@prelude//utils:utils.bzl", "flatten_dict", "map_val", ) load( ":argsfiles.bzl", "ARGSFILES_SUBTARGET", "get_argsfiles_output", ) load( ":comp_db.bzl", "CxxCompilationDbInfo", # @unused Used as a type "create_compilation_database", "make_compilation_db_info", ) load( ":compile.bzl", "compile_cxx", "create_compile_cmds", "cxx_objects_sub_targets", ) load(":compile_types.bzl", "CxxCompileFlavor") load(":cxx_context.bzl", "get_cxx_platform_info", "get_cxx_toolchain_info") load( ":cxx_instrumentation.bzl", "is_coverage_enabled_by_any_dep", ) load( ":cxx_library_utility.bzl", "OBJECTS_SUBTARGET", "cxx_attr_deps", "cxx_attr_link_style", "cxx_attr_linker_flags", "cxx_attr_resources", "cxx_is_gnu", ) load( ":cxx_link_utility.bzl", "executable_shared_lib_arguments", ) load( ":cxx_types.bzl", "CxxRuleConstructorParams", # @unused Used as a type ) load(":diagnostics.bzl", "check_sub_target") load(":groups.bzl", "get_dedupped_roots_from_groups") load( ":link.bzl", "CxxLinkerMapData", "cxx_link_into", ) load( ":link_groups.bzl", "BuildLinkGroupsContext", "FinalLabelsToLinks", "LINK_GROUP_MAPPINGS_FILENAME_SUFFIX", "LINK_GROUP_MAPPINGS_SUB_TARGET", "LINK_GROUP_MAP_DATABASE_SUB_TARGET", "LinkGroupContext", "build_shared_libs_for_symlink_tree", "collect_linkables", "create_debug_linkable_entries", "create_link_groups", "find_relevant_roots", "get_filtered_labels_to_links_map", "get_filtered_links", "get_filtered_targets", "get_link_group", "get_link_group_map_json", "get_link_group_preferred_linkage", "get_public_link_group_nodes", "get_transitive_deps_matching_labels", ) load( ":link_types.bzl", "CxxLinkResultType", "LinkOptions", "link_options", "merge_link_options", ) load( ":linker.bzl", "DUMPBIN_SUB_TARGET", "PDB_SUB_TARGET", "get_dumpbin_providers", "get_pdb_providers", "get_shared_library_name", ) load( ":preprocessor.bzl", "cxx_inherited_preprocessor_infos", "cxx_private_preprocessor_info", ) CxxExecutableOutput = record( binary = Artifact, unstripped_binary = Artifact, bitcode_bundle = field(Artifact | None, None), dwp = field(Artifact | None), # Files that must be present for the executable to run successfully. These # are always materialized, whether the executable is the output of a build # or executed as a host tool. They become hidden= arguments when executing # the executable via RunInfo(). runtime_files = list[ArgLike], sub_targets = dict[str, list[DefaultInfo]], # The LinkArgs used to create the final executable in 'binary'. link_args = list[LinkArgs], # External components needed to debug the executable. external_debug_info = field(ArtifactTSet, ArtifactTSet()), # The projection of `external_debug_info`. These files need to be # materialized when this executable is the output of a build, not when it is # used by other rules. They become other_outputs on DefaultInfo. external_debug_info_artifacts = list[TransitiveSetArgsProjection], shared_libs = list[SharedLibrary], # All link group links that were generated in the executable. auto_link_groups = field(dict[str, LinkedObject], {}), compilation_db = CxxCompilationDbInfo, xcode_data = XcodeDataInfo, linker_map_data = [CxxLinkerMapData, None], link_command_debug_output = field([LinkCommandDebugOutput, None], None), dist_info = DistInfo, sanitizer_runtime_files = field(list[Artifact], []), index_stores = field(list[Artifact], []), ) def cxx_executable(ctx: AnalysisContext, impl_params: CxxRuleConstructorParams, is_cxx_test: bool = False) -> CxxExecutableOutput: # Gather preprocessor inputs. preprocessor_deps = cxx_attr_deps(ctx) + filter(None, [ctx.attrs.precompiled_header]) (own_preprocessor_info, test_preprocessor_infos) = cxx_private_preprocessor_info( ctx, impl_params.headers_layout, raw_headers = ctx.attrs.raw_headers, extra_preprocessors = impl_params.extra_preprocessors, non_exported_deps = preprocessor_deps, is_test = is_cxx_test, ) inherited_preprocessor_infos = cxx_inherited_preprocessor_infos(preprocessor_deps) + impl_params.extra_preprocessors_info # The link style to use. link_strategy = to_link_strategy(cxx_attr_link_style(ctx)) link_strategy = process_link_strategy_for_pic_behavior(link_strategy, get_cxx_toolchain_info(ctx).pic_behavior) sub_targets = {} # Compile objects. compile_cmd_output = create_compile_cmds( ctx, impl_params, [own_preprocessor_info] + test_preprocessor_infos, inherited_preprocessor_infos, is_coverage_enabled_by_any_dep(ctx, preprocessor_deps), ) compile_flavor = CxxCompileFlavor("pic") if link_strategy != LinkStrategy("static") else CxxCompileFlavor("default") cxx_outs = compile_cxx( ctx = ctx, src_compile_cmds = compile_cmd_output.src_compile_cmds, flavor = compile_flavor, provide_syntax_only = True, use_header_units = impl_params.use_header_units, ) sub_targets[ARGSFILES_SUBTARGET] = [get_argsfiles_output(ctx, compile_cmd_output.argsfiles.relative, ARGSFILES_SUBTARGET)] sub_targets[XCODE_ARGSFILES_SUB_TARGET] = [get_argsfiles_output(ctx, compile_cmd_output.argsfiles.xcode, XCODE_ARGSFILES_SUB_TARGET)] sub_targets[OBJECTS_SUBTARGET] = [DefaultInfo(sub_targets = cxx_objects_sub_targets(cxx_outs))] diagnostics = { compile_cmd.src.short_path: out.diagnostics for compile_cmd, out in zip(compile_cmd_output.src_compile_cmds, cxx_outs) if out.diagnostics != None } if len(diagnostics) > 0: sub_targets["check"] = check_sub_target(ctx, diagnostics) # Compilation DB. comp_db = create_compilation_database(ctx, compile_cmd_output.src_compile_cmds, "compilation-database") sub_targets["compilation-database"] = [comp_db] # Compilation DB including headers. comp_db = create_compilation_database(ctx, compile_cmd_output.comp_db_compile_cmds, "full-compilation-database") sub_targets["full-compilation-database"] = [comp_db] # comp_db_compile_cmds can include header files being compiled as C++ which should not be exposed in the [compilation-database] subtarget comp_db_info = make_compilation_db_info(compile_cmd_output.comp_db_compile_cmds, get_cxx_toolchain_info(ctx), get_cxx_platform_info(ctx)) # Index Stores created by cxx compile index_stores = [out.index_store for out in cxx_outs if out.index_store] # Link deps link_deps = linkables(cxx_attr_deps(ctx)) + impl_params.extra_link_deps # Link Groups link_group = get_link_group(ctx) link_group_info = impl_params.link_group_info if link_group_info: link_groups = link_group_info.groups link_group_mappings = link_group_info.mappings link_group_deps = [link_group_info.graph] else: link_groups = {} link_group_mappings = {} link_group_deps = [] link_group_preferred_linkage = get_link_group_preferred_linkage(link_groups.values()) # Create the linkable graph with the binary's deps and any link group deps. linkable_graph = create_linkable_graph( ctx, deps = filter( None, # Some subtargets (like :Foo[headers]) do not have a linkable_graph. [d.linkable_graph for d in link_deps] + # We also need to include additional link roots, so that we find # deps that might need to be linked into the main executable. [d.linkable_graph for d in impl_params.extra_link_roots] + # For non-auto-link-group cases, also search the targets specified # in the link group mappings, as they won't be available in other # ways. link_group_deps, ), ) # Gather link inputs. own_link_flags = ( get_cxx_toolchain_info(ctx).linker_info.binary_linker_flags + cxx_attr_linker_flags(ctx) + impl_params.extra_link_flags + impl_params.extra_exported_link_flags ) # ctx.attrs.binary_linker_flags should come after default link flags so it can be used to override default settings own_exe_link_flags = impl_params.extra_binary_link_flags + own_link_flags + ctx.attrs.binary_linker_flags deps_merged_link_infos = [d.merged_link_info for d in link_deps] frameworks_linkable = apple_create_frameworks_linkable(ctx) swiftmodule_linkable = impl_params.swiftmodule_linkable # Link group libs. link_group_libs = {} # Target label to which link group it was included targets_consumed_by_link_groups = {} auto_link_groups = {} labels_to_links = FinalLabelsToLinks( map = {}, ) if not link_group_mappings: # We cannot support deriving link execution preference off the included links, as we've already # lost the information on what is in the link. # TODO(T152860998): Derive link_execution_preference based upon the included links link_execution_preference = get_resolved_cxx_binary_link_execution_preference(ctx, [], impl_params.force_full_hybrid_if_capable) dep_links = apple_build_link_args_with_deduped_flags( ctx, deps_merged_link_infos, frameworks_linkable, link_strategy, swiftmodule_linkable, prefer_stripped = impl_params.prefer_stripped_objects, ) else: reduced_linkable_graph = reduce_linkable_graph(linkable_graph) linkable_graph_node_map = reduced_linkable_graph.nodes # Although these aren't really deps, we need to search from the # extra link group roots to make sure we find additional libs # that should be linked into the main link group. link_group_extra_link_roots = [d.linkable_graph.nodes.value.label for d in impl_params.extra_link_roots if d.linkable_graph != None] exec_dep_roots = [d.linkable_graph.nodes.value.label for d in link_deps if d.linkable_graph != None] # If we're using auto-link-groups, where we generate the link group links # in the prelude, the link group map will give us the link group libs. # Otherwise, pull them from the `LinkGroupLibInfo` provider from out deps. public_link_group_nodes = get_public_link_group_nodes( linkable_graph_node_map, link_group_mappings, exec_dep_roots + link_group_extra_link_roots, link_group, ) link_group_libs_debug_info = {} if impl_params.auto_link_group_specs != None: linked_link_groups = create_link_groups( ctx = ctx, link_groups = link_groups, link_strategy = link_strategy, linkable_graph = reduced_linkable_graph, link_group_mappings = link_group_mappings, link_group_preferred_linkage = link_group_preferred_linkage, executable_deps = exec_dep_roots, linker_flags = own_link_flags, link_group_specs = impl_params.auto_link_group_specs, other_roots = link_group_extra_link_roots, prefer_stripped_objects = impl_params.prefer_stripped_objects, anonymous = ctx.attrs.anonymous_link_groups, allow_cache_upload = impl_params.exe_allow_cache_upload, public_nodes = public_link_group_nodes, error_handler = impl_params.error_handler, ) link_group_libs_debug_info = linked_link_groups.libs_debug_info for name, linked_link_group in linked_link_groups.libs.items(): auto_link_groups[name] = linked_link_group.artifact if linked_link_group.library != None: link_group_libs[name] = linked_link_group.library own_exe_link_flags += linked_link_groups.symbol_ldflags targets_consumed_by_link_groups = linked_link_groups.targets_consumed_by_link_groups else: # NOTE(agallagher): We don't use version scripts and linker scripts # for non-auto-link-group flow, as it's note clear it's useful (e.g. # it's mainly for supporting dlopen-enabled libs and extensions). link_group_libs = gather_link_group_libs( children = [d.link_group_lib_info for d in link_deps], ) pic_behavior = get_cxx_toolchain_info(ctx).pic_behavior roots = set( exec_dep_roots + find_relevant_roots( link_group = link_group, linkable_graph_node_map = linkable_graph_node_map, link_group_mappings = link_group_mappings, roots = link_group_extra_link_roots, ), ) is_executable_link = True exec_linkables = collect_linkables( reduced_linkable_graph, is_executable_link, link_strategy, link_group_preferred_linkage, pic_behavior, roots, ) build_context = BuildLinkGroupsContext( public_nodes = public_link_group_nodes, linkable_graph = reduced_linkable_graph, link_groups = link_groups, link_group_mappings = link_group_mappings, link_group_preferred_linkage = link_group_preferred_linkage, link_strategy = link_strategy, pic_behavior = pic_behavior, link_group_libs = { name: (lib.label, lib.shared_link_infos) for name, lib in link_group_libs.items() }, prefer_stripped = impl_params.prefer_stripped_objects, prefer_optimized = False, ) # TODO(T110378098): Similar to shared libraries, we need to identify all the possible # scenarios for which we need to propagate up link info and simplify this logic. For now # base which links to use based on whether link groups are defined. labels_to_links = get_filtered_labels_to_links_map( link_group, linkables = exec_linkables, is_executable_link = is_executable_link, build_context = build_context, force_static_follows_dependents = impl_params.link_groups_force_static_follows_dependents, ) link_groups_binary_debug_info = LinkGroupsDebugLinkableItem( ordered_linkables = create_debug_linkable_entries(labels_to_links.map, root = None), ) link_groups_debug_info = LinkGroupsDebugLinkInfo( binary = link_groups_binary_debug_info, libs = link_group_libs_debug_info, ) link_groups_libs_sub_targets = {} for name, lib in link_group_libs_debug_info.items(): link_groups_libs_sub_targets[name] = [ DefaultInfo( default_output = ctx.actions.write_json( ctx.label.name + ".link-groups-info.libs.{}.json".format(name), lib, ), ), ] sub_targets["link-groups-info"] = [DefaultInfo( default_output = ctx.actions.write_json( ctx.label.name + ".link-groups-info.json", link_groups_debug_info, ), sub_targets = { "bin": [DefaultInfo( default_output = ctx.actions.write_json( ctx.label.name + ".link-groups-info.bin.json", link_groups_binary_debug_info, ), )], "shared-libraries": [DefaultInfo(sub_targets = link_groups_libs_sub_targets)], }, )] if is_cxx_test and link_group != None: # if a cpp_unittest is part of the link group, we need to traverse through all deps # from the root again to ensure we link in gtest deps roots = set([d.linkable_graph.nodes.value.label for d in link_deps]) exec_linkables = collect_linkables( linkable_graph_node_map, is_executable_link, link_strategy, link_group_preferred_linkage, pic_behavior, roots, ) labels_to_links_to_merge = get_filtered_labels_to_links_map( link_group = None, linkables = exec_linkables, is_executable_link = False, build_context = build_context, ) labels_to_links.map |= labels_to_links_to_merge.map # NOTE: Our Haskell DLL support impl currently links transitive haskell # deps needed by DLLs which get linked into the main executable as link- # whole. To emulate this, we mark Haskell rules with a special label # and traverse this to find all the nodes we need to link whole. public_nodes = [] if ctx.attrs.link_group_public_deps_label != None: public_nodes = get_transitive_deps_matching_labels( linkable_graph_node_map = linkable_graph_node_map, label = ctx.attrs.link_group_public_deps_label, roots = get_dedupped_roots_from_groups(link_group_info.groups.values()), ) filtered_links = get_filtered_links(labels_to_links.map, set(public_nodes)) filtered_targets = get_filtered_targets(labels_to_links.map) link_execution_preference = get_resolved_cxx_binary_link_execution_preference(ctx, labels_to_links.map.keys(), impl_params.force_full_hybrid_if_capable) # Unfortunately, link_groups does not use MergedLinkInfo to represent the args # for the resolved nodes in the graph. # Thus, we have no choice but to traverse all the nodes to dedupe the framework linker args. additional_links = apple_get_link_info_by_deduping_link_infos(ctx, filtered_links, frameworks_linkable, swiftmodule_linkable) if additional_links: filtered_links.append(additional_links) dep_links = LinkArgs(infos = filtered_links) sub_targets[LINK_GROUP_MAP_DATABASE_SUB_TARGET] = [get_link_group_map_json(ctx, filtered_targets)] # Only setup a shared library symlink tree when shared linkage or link_groups is used gnu_use_link_groups = cxx_is_gnu(ctx) and len(link_group_mappings) > 0 shlib_deps = [] if link_strategy == LinkStrategy("shared") or gnu_use_link_groups: shlib_deps = ( [d.shared_library_info for d in link_deps] + [d.shared_library_info for d in impl_params.extra_link_roots] ) elif impl_params.runtime_dependency_handling == RuntimeDependencyHandling("symlink"): for linkable_node in linkable_graph.nodes.traverse(): if linkable_node.linkable == None: continue preferred_linkage = linkable_node.linkable.preferred_linkage output_style = get_lib_output_style(link_strategy, preferred_linkage, PicBehavior("supported")) if output_style == LibOutputStyle("shared_lib") and not linkable_node.linkable.stub: shlib_deps.append(merge_shared_libraries(ctx.actions, node = linkable_node.linkable.shared_libs)) elif impl_params.runtime_dependency_handling == RuntimeDependencyHandling("symlink_single_level_only"): for d in link_deps + impl_params.extra_link_roots: if d.linkable_graph == None: continue preferred_linkage = d.linkable_graph.nodes.value.linkable.preferred_linkage output_style = get_lib_output_style(link_strategy, preferred_linkage, PicBehavior("supported")) if output_style == LibOutputStyle("shared_lib"): shlib_deps.append(d.shared_library_info) shlib_info = merge_shared_libraries(ctx.actions, deps = shlib_deps) link_group_ctx = LinkGroupContext( link_group_mappings = link_group_mappings, link_group_libs = link_group_libs, link_group_preferred_linkage = link_group_preferred_linkage, labels_to_links_map = labels_to_links.map, targets_consumed_by_link_groups = targets_consumed_by_link_groups, ) # Set up shared libraries symlink tree only when needed shared_libs = build_shared_libs_for_symlink_tree( gnu_use_link_groups, link_group_ctx, link_strategy, traverse_shared_library_info(shlib_info), impl_params.extra_shared_libs, ) toolchain_info = get_cxx_toolchain_info(ctx) linker_info = toolchain_info.linker_info links = [ LinkArgs(infos = [ LinkInfo( dist_thin_lto_codegen_flags = getattr(ctx.attrs, "dist_thin_lto_codegen_flags", []), pre_flags = own_exe_link_flags, linkables = [ObjectsLinkable( objects = [out.object for out in cxx_outs] + impl_params.extra_link_input, linker_type = linker_info.type, link_whole = True, )], external_debug_info = make_artifact_tset( actions = ctx.actions, label = ctx.label, artifacts = ( [out.object for out in cxx_outs if out.object_has_external_debug_info] + [out.external_debug_info for out in cxx_outs if out.external_debug_info != None] + (impl_params.extra_link_input if impl_params.extra_link_input_has_external_debug_info else []) ), ), ), ]), dep_links, ] + impl_params.extra_link_args # If there are hidden dependencies to this target then add them as # hidden link args. if impl_params.extra_hidden: links.append( LinkArgs(flags = cmd_args(hidden = impl_params.extra_hidden)), ) link_result = _link_into_executable( ctx, # If shlib lib tree generation is enabled, pass in the shared libs (which # will trigger the necessary link tree and link args). shared_libs if impl_params.exe_shared_libs_link_tree else [], impl_params.executable_name, linker_info.binary_extension, link_options( links = links, link_weight = linker_info.link_weight, link_ordering = map_val(LinkOrdering, ctx.attrs.link_ordering), link_execution_preference = link_execution_preference, enable_distributed_thinlto = ctx.attrs.enable_distributed_thinlto, strip = impl_params.strip_executable, strip_args_factory = impl_params.strip_args_factory, category_suffix = impl_params.exe_category_suffix, allow_cache_upload = impl_params.exe_allow_cache_upload, error_handler = impl_params.error_handler, extra_linker_outputs_factory = impl_params.extra_linker_outputs_factory, extra_linker_outputs_flags_factory = impl_params.extra_linker_outputs_flags_factory, ), ) binary = link_result.exe runtime_files = link_result.runtime_files shared_libs_symlink_tree = link_result.shared_libs_symlink_tree linker_map_data = link_result.linker_map_data # Define the xcode data sub target xcode_data_default_info, xcode_data_info = generate_xcode_data( ctx, rule_type = impl_params.rule_type, output = binary.output, populate_rule_specific_attributes_func = impl_params.cxx_populate_xcode_attributes_func, srcs = impl_params.srcs + impl_params.additional.srcs, argsfiles = compile_cmd_output.argsfiles.xcode, product_name = get_cxx_executable_product_name(ctx), ) sub_targets[XCODE_DATA_SUB_TARGET] = xcode_data_default_info # Info about dynamic-linked libraries for fbpkg integration: # - the symlink dir that's part of RPATH # - sub-sub-targets that reference shared library dependencies and their respective dwp # - [shared-libraries] - a json map that references the above rules. if isinstance(shared_libs_symlink_tree, Artifact): sub_targets["rpath-tree"] = [DefaultInfo( default_output = shared_libs_symlink_tree, other_outputs = [ shlib.lib.output for shlib in shared_libs ] + [ shlib.lib.dwp for shlib in shared_libs if shlib.lib.dwp ], )] # TODO(agallagher) There appears to be pre-existing soname conflicts # when building this (when using link groups), which prevents using # `with_unique_str_sonames`. str_soname_shlibs = { shlib.soname.ensure_str(): shlib for shlib in shared_libs if shlib.soname.is_str } readable_mappings = {} soname_to_group_mappings = {} if link_group_mappings: for node, group in link_group_mappings.items(): soname = get_shared_library_name(linker_info, group, True) soname_to_group_mappings[soname] = group readable_mappings.setdefault(group, []).append(node.raw_target()) sub_targets[LINK_GROUP_MAPPINGS_SUB_TARGET] = [DefaultInfo( default_output = ctx.actions.write_json( binary.output.basename + LINK_GROUP_MAPPINGS_FILENAME_SUFFIX, readable_mappings, ), )] linkable_graph_node_map = get_linkable_graph_node_map_func(linkable_graph)() sub_targets["binary_node_count"] = [DefaultInfo( default_output = ctx.actions.write_json( binary.output.basename + ".binary_node_count.json", { "binary_node_count": len(linkable_graph_node_map), }, ), )] shared_libraries_sub_targets = {} for soname, shlib in str_soname_shlibs.items(): targets = {"dwp": [DefaultInfo(default_output = shlib.lib.dwp)]} if shlib.lib.dwp else {} group = soname_to_group_mappings.get(soname) if group in readable_mappings: output_json_file = binary.output.basename + "." + group + LINK_GROUP_MAPPINGS_FILENAME_SUFFIX targets[LINK_GROUP_MAPPINGS_SUB_TARGET] = [DefaultInfo( default_output = ctx.actions.write_json( output_json_file, {group: readable_mappings[group]}, ), )] shared_libraries_sub_targets[soname] = [DefaultInfo( default_output = shlib.lib.output, sub_targets = targets, )] sub_targets["shared-libraries"] = [DefaultInfo( default_output = ctx.actions.write_json( binary.output.basename + ".shared-libraries.json", { "libraries": [ "{}:{}[shared-libraries][{}]".format(ctx.label.path, ctx.label.name, soname) for soname in str_soname_shlibs ], "librariesdwp": [ "{}:{}[shared-libraries][{}][dwp]".format(ctx.label.path, ctx.label.name, soname) for soname, shlib in str_soname_shlibs.items() if shlib.lib.dwp ], "rpathtree": ["{}:{}[rpath-tree]".format(ctx.label.path, ctx.label.name)] if shared_libs_symlink_tree else [], }, ), sub_targets = shared_libraries_sub_targets, )] # If we have some resources, write it to the resources JSON file and add # it and all resources to "runtime_files" so that we make to materialize # them with the final binary. resources = flatten_dict(gather_resources( label = ctx.label, resources = cxx_attr_resources(ctx), deps = cxx_attr_deps(ctx), ).values()) if resources: runtime_files.append(create_resource_db( ctx = ctx, name = binary.output.basename + ".resources.json", binary = binary.output, resources = resources, )) for resource in resources.values(): runtime_files.append(resource.default_output) runtime_files.extend(resource.other_outputs) if binary.dwp: # A `dwp` sub-target which generates the `.dwp` file for this binary and its shared lib dependencies. shared_libraries_dwp = [ shlib.lib.dwp for shlib in shared_libs if shlib.lib.dwp ] + ([link_result.dwp_symlink_tree] if link_result.dwp_symlink_tree else []) sub_targets["dwp"] = [ DefaultInfo( default_output = binary.dwp, other_outputs = shared_libraries_dwp, ), ] if binary.pdb: # A `pdb` sub-target which generates the `.pdb` file for this binary. sub_targets[PDB_SUB_TARGET] = get_pdb_providers(pdb = binary.pdb, binary = binary.output) if toolchain_info.dumpbin_toolchain_path: sub_targets[DUMPBIN_SUB_TARGET] = get_dumpbin_providers(ctx, binary.output, toolchain_info.dumpbin_toolchain_path) # If bolt is not ran, binary.prebolt_output will be the same as binary.output. Only # expose binary.prebolt_output if cxx_use_bolt(ctx) is True to avoid confusion if cxx_use_bolt(ctx): sub_targets["prebolt"] = [DefaultInfo(default_output = binary.prebolt_output)] if linker_map_data: sub_targets["linker-map"] = [DefaultInfo(default_output = linker_map_data.map, other_outputs = [linker_map_data.binary])] sub_targets["linker.argsfile"] = [DefaultInfo( default_output = binary.linker_argsfile, )] link_cmd_debug_output = make_link_command_debug_output(binary) if link_cmd_debug_output != None: link_cmd_debug_output_file = make_link_command_debug_output_json_info(ctx, [link_cmd_debug_output]) sub_targets["linker.command"] = [DefaultInfo( default_outputs = filter(None, [link_cmd_debug_output_file]), )] if linker_info.supports_distributed_thinlto and ctx.attrs.enable_distributed_thinlto: sub_targets["index.argsfile"] = [DefaultInfo( default_output = binary.index_argsfile, )] # Provide a debug info target to make sure unpacked external debug info # (dwo) is materialized. external_debug_info = make_artifact_tset( actions = ctx.actions, children = ( [binary.external_debug_info] + [s.lib.external_debug_info for s in shared_libs] + impl_params.additional.static_external_debug_info ), ) external_debug_info_artifacts = project_artifacts(ctx.actions, [external_debug_info]) materialize_external_debug_info = ctx.actions.write( "debuginfo.artifacts", external_debug_info_artifacts, with_inputs = True, ) sub_targets["debuginfo"] = [DefaultInfo( default_output = materialize_external_debug_info, )] sub_targets["debug_coverage_instrumentation"] = [DefaultInfo( default_output = materialize_external_debug_info, )] sub_targets["exe"] = [DefaultInfo( default_output = binary.output, other_outputs = runtime_files, )] for additional_subtarget, subtarget_providers in impl_params.additional.subtargets.items(): sub_targets[additional_subtarget] = subtarget_providers sub_targets.update(link_result.extra_outputs) return CxxExecutableOutput( binary = binary.output, unstripped_binary = binary.unstripped_output, dwp = binary.dwp, runtime_files = runtime_files, sub_targets = sub_targets, link_args = links, external_debug_info = external_debug_info, external_debug_info_artifacts = external_debug_info_artifacts, shared_libs = shared_libs, auto_link_groups = auto_link_groups, compilation_db = comp_db_info, xcode_data = xcode_data_info, linker_map_data = linker_map_data, link_command_debug_output = link_cmd_debug_output, dist_info = DistInfo( shared_libs = shlib_info.set, nondebug_runtime_files = runtime_files, ), sanitizer_runtime_files = link_result.sanitizer_runtime_files, index_stores = index_stores, ) _CxxLinkExecutableResult = record( # The resulting executable exe = LinkedObject, # Files that must be present for the executable to run successfully. These # are always materialized, whether the executable is the output of a build # or executed as a host tool. runtime_files = list[ArgLike], # Files needed to debug the executable. These need to be materialized when # this executable is the output of a build, but not when it is used by other # rules. external_debug_info = list[TransitiveSetArgsProjection], dwp_symlink_tree = field(list[Artifact] | Artifact | None), # Optional shared libs symlink tree symlinked_dir action shared_libs_symlink_tree = [list[Artifact], Artifact, None], linker_map_data = [CxxLinkerMapData, None], sanitizer_runtime_files = list[Artifact], # Extra output providers produced by extra_linker_outputs_factory extra_outputs = dict[str, list[DefaultInfo]], ) def _link_into_executable( ctx: AnalysisContext, shared_libs: list[SharedLibrary], executable_name: [str, None], binary_extension: str, opts: LinkOptions) -> _CxxLinkExecutableResult: if executable_name and binary_extension and executable_name.endswith(binary_extension): # don't append .exe if it already is .exe output_name = executable_name else: output_name = "{}{}".format(executable_name if executable_name else get_cxx_executable_product_name(ctx), "." + binary_extension if binary_extension else "") output = ctx.actions.declare_output(output_name) executable_args = executable_shared_lib_arguments( ctx, get_cxx_toolchain_info(ctx), output, shared_libs, ) link_result = cxx_link_into( ctx = ctx, output = output, result_type = CxxLinkResultType("executable"), opts = merge_link_options( opts, links = [LinkArgs(flags = executable_args.extra_link_args)] + opts.links, ), ) return _CxxLinkExecutableResult( exe = link_result.linked_object, runtime_files = executable_args.runtime_files + link_result.sanitizer_runtime_files, external_debug_info = executable_args.external_debug_info, shared_libs_symlink_tree = executable_args.shared_libs_symlink_tree, dwp_symlink_tree = executable_args.dwp_symlink_tree, linker_map_data = link_result.linker_map_data, sanitizer_runtime_files = link_result.sanitizer_runtime_files, extra_outputs = link_result.extra_outputs if link_result.extra_outputs else {}, ) def get_cxx_executable_product_name(ctx: AnalysisContext) -> str: return ctx.label.name + ("-wrapper" if cxx_use_bolt(ctx) else "")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server