Create deferred implementation wrappers and add implicit dep. A future change will use these wrapped functions instead of directly loading the implementation. Also delete some duplicate definitions introduced in the previous change. PiperOrigin-RevId: 874599289 Change-Id: I1934885db00044e9d40ba2b12973ca9e185636fa
diff --git a/cc/private/rules_impl/BUILD b/cc/private/rules_impl/BUILD index d924c5e..1bbece7 100644 --- a/cc/private/rules_impl/BUILD +++ b/cc/private/rules_impl/BUILD
@@ -18,6 +18,7 @@ "**/BUILD", ]) + [ "//cc/private/rules_impl/fdo:srcs", + "//cc/private/rules_impl/wrappers:srcs", ], ) @@ -57,6 +58,7 @@ "@cc_compatibility_proxy//:__pkg__", ], deps = [ + ":function_providing_rule_bzl", ":objc_common", ":objc_compilation_support_bzl", "//cc:action_names_bzl", @@ -145,3 +147,9 @@ "@cc_compatibility_proxy//:__pkg__", ], ) + +bzl_library( + name = "function_providing_rule_bzl", + srcs = ["function_providing_rule.bzl"], + visibility = ["//cc:__subpackages__"], +)
diff --git a/cc/private/rules_impl/cc_binary.bzl b/cc/private/rules_impl/cc_binary.bzl index cb11b07..d5f0b71 100644 --- a/cc/private/rules_impl/cc_binary.bzl +++ b/cc/private/rules_impl/cc_binary.bzl
@@ -49,7 +49,10 @@ empty file.</li> </ul> """ + semantics.cc_binary_extra_docs, - attrs = cc_binary_attrs, + attrs = cc_binary_attrs | {"_impl_delegate": attr.label( + default = Label("//cc/private/rules_impl/wrappers:cc_binary_impl_wrapper"), + cfg = "exec", + )}, outputs = { "dwp_file": "%{name}.dwp", "stripped_binary": "%{name}.stripped",
diff --git a/cc/private/rules_impl/cc_binary_impl.bzl b/cc/private/rules_impl/cc_binary_impl.bzl index fb4ef55..2306143 100644 --- a/cc/private/rules_impl/cc_binary_impl.bzl +++ b/cc/private/rules_impl/cc_binary_impl.bzl
@@ -23,11 +23,10 @@ load("//cc/common:debug_package_info.bzl", "DebugPackageInfo") load("//cc/common:semantics.bzl", "semantics") load("//cc/private:graph_node_info.bzl", "GraphNodeInfo") -load(":cc_shared_library.bzl", "add_unused_dynamic_deps", "build_exports_map_from_only_dynamic_deps", "build_link_once_static_libs_map", "merge_cc_shared_library_infos", "separate_static_and_dynamic_link_libraries", "sort_linker_inputs", "throw_linked_but_not_exported_errors") +load(":cc_shared_library_impl.bzl", "add_unused_dynamic_deps", "build_exports_map_from_only_dynamic_deps", "build_link_once_static_libs_map", "merge_cc_shared_library_infos", "separate_static_and_dynamic_link_libraries", "sort_linker_inputs", "throw_linked_but_not_exported_errors") +load(":function_providing_rule.bzl", "wrap_starlark_function") -visibility("private") - -_CcLauncherInfo = cc_common.launcher_provider +_CcLauncherInfo = getattr(cc_common, "launcher_provider", None) # TODO(blaze-team): cleanup lint target types _EXECUTABLE = "executable" @@ -871,3 +870,4 @@ return providers impl = _impl +cc_binary_impl_wrapper = wrap_starlark_function(_impl)
diff --git a/cc/private/rules_impl/cc_library.bzl b/cc/private/rules_impl/cc_library.bzl index 2536893..2c0530a 100755 --- a/cc/private/rules_impl/cc_library.bzl +++ b/cc/private/rules_impl/cc_library.bzl
@@ -419,6 +419,10 @@ "_stl": semantics.get_stl(), "_def_parser": semantics.get_def_parser(), "_use_auto_exec_groups": attr.bool(default = True), + "_impl_delegate": attr.label( + default = Label("//cc/private/rules_impl/wrappers:cc_library_impl_wrapper"), + cfg = "exec", + ), } | semantics.get_implementation_deps_allowed_attr() | semantics.get_nocopts_attr(), # buildifier: disable=attr-licenses toolchains = use_cc_toolchain() + semantics.get_runtimes_toolchain(), fragments = ["cpp"] + semantics.additional_fragments(),
diff --git a/cc/private/rules_impl/cc_library_impl.bzl b/cc/private/rules_impl/cc_library_impl.bzl index f17c75b..dabef76 100755 --- a/cc/private/rules_impl/cc_library_impl.bzl +++ b/cc/private/rules_impl/cc_library_impl.bzl
@@ -19,8 +19,7 @@ load("//cc/common:cc_helper.bzl", "cc_helper") load("//cc/common:cc_info.bzl", "CcInfo") load("//cc/common:semantics.bzl", "semantics") - -visibility("private") +load(":function_providing_rule.bzl", "wrap_starlark_function") def _cc_library_impl(ctx): semantics.validate(ctx, "cc_library") @@ -556,3 +555,4 @@ LINKER_SCRIPT = [".ld", ".lds", ".ldscript"] cc_library_impl = _cc_library_impl +cc_library_impl_wrapper = wrap_starlark_function(_cc_library_impl)
diff --git a/cc/private/rules_impl/cc_shared_library.bzl b/cc/private/rules_impl/cc_shared_library.bzl index 4284d75..0d53754 100644 --- a/cc/private/rules_impl/cc_shared_library.bzl +++ b/cc/private/rules_impl/cc_shared_library.bzl
@@ -32,291 +32,6 @@ # used sparingly after making sure it's safe to use. LINKABLE_MORE_THAN_ONCE = "LINKABLE_MORE_THAN_ONCE" -def _programmatic_error(message = ""): - fail("Your build has triggered a programmatic error in the cc_shared_library rule. " + - "Please file an issue in https://github.com/bazelbuild/bazel : {}".format(message)) - -def _sort_linker_inputs(topologically_sorted_labels, label_to_linker_inputs, linker_inputs_count): - # len(label_to_linker_inputs) might not match the topologically_sorted_labels - # size. The latter is looking at nodes in the graph but a node may not - # necessarily contribute any linker_inputs. For example a cc_library with - # no sources and only deps. Every linker_input.owner must be in - # topologically_sorted_labels otherwise there is an error in the rule - # implementation of the target providing that linker_input, e.g. it's - # missing a CcSharedLibraryHintInfo if it had custom owner names for linker - # inputs. - sorted_linker_inputs = [] - for label in topologically_sorted_labels: - if label not in label_to_linker_inputs: - # This is ok. It can happen if no linker_inputs - # were added by a node in the graph. - continue - sorted_linker_inputs.extend(label_to_linker_inputs[label]) - - if len(sorted_linker_inputs) != linker_inputs_count: - owners = [] - for sorted_linker_input in sorted_linker_inputs: - owners.append(str(sorted_linker_input.owner)) - _programmatic_error("{} vs {}".format(",".join(owners), linker_inputs_count)) - - return sorted_linker_inputs - -# For each target, find out whether it should be linked statically or -# dynamically. The transitive_dynamic_dep_labels parameter is only needed for -# binaries because they link all dynamic_deps (cc_binary|cc_test). -def _separate_static_and_dynamic_link_libraries( - dynamic_deps, - deps_graph_nodes, - can_be_linked_dynamically): - ( - transitive_dynamic_dep_labels, - all_dynamic_dep_linker_inputs, - ) = _build_map_direct_dynamic_dep_to_transitive_dynamic_deps(dynamic_deps) - - node = None - deps_graph_nodes_to_process = reversed(deps_graph_nodes) - targets_to_be_linked_statically_map = {} - targets_to_be_linked_dynamically_set = {} - seen_labels = {} - - # The cc_shared_library graph is parallel to the cc_library graph. - # Propagation of linker inputs between cc_libraries happens via the CcInfo - # provider. Parallel to this we have cc_shared_libraries which may decide - # different partitions of the cc_library graph. - # - # In a previous implementation of cc_shared_library we relied on the - # topological sort given by flattening - # cc_info.linking_context.linker_inputs.to_list(), however this was wrong - # because the dependencies of a shared library (i.e. a pruned node here) - # influenced the final order. - # - # In order to fix this, the pruning below was changed from breadth-first - # traversal to depth-first traversal. While doing this we also recreate a - # depset with topological order that takes into account the pruned nodes - # and which will later be used to order the libraries in the linking - # command line. This will be in topological order and will respect the - # order of the deps as listed on the BUILD file as much as possible. - # - # Here we say "first_owner" because each node (see GraphNodeInfo) may have - # more than one linker_input (each potentially with a different owner) but - # using only the first owner as a key is enough. - first_owner_to_depset = {} - - # Horrible I know. Perhaps Starlark team gives me a way to prune a tree. - for _unused in range(2147483647): - if not len(deps_graph_nodes_to_process): - break - - node = deps_graph_nodes_to_process[-1] - - must_add_children = False - - # The *_seen variables are used to track a programmatic error and fail - # if it happens. Every value in node.owners presumably corresponds to - # a linker_input in the same exact target. Therefore if we have seen - # any of the owners already, then we must have also seen all the other - # owners in the same node. Viceversa when we haven't seen them yet. If - # both of these values are non-zero after the loop, the most likely - # reason would be a bug in the implementation. It could potentially be - # triggered by users if they use owner labels that do not keep most of - # the ctx.label.package and ctx.label.name which then clash with other - # target's owners (unlikely). For now though if the error is - # triggered, it's reasonable to require manual revision by - # the cc_shared_library implementation owners. - has_owners_seen = False - has_owners_not_seen = False - linked_dynamically = False - linked_statically = False - for owner in node.owners: - # TODO(bazel-team): Do not convert Labels to string to save on - # garbage string allocations. - owner_str = str(owner) - - if owner_str in seen_labels: - has_owners_seen = True - continue - - has_owners_not_seen = True - seen_labels[owner_str] = True - - if owner_str in can_be_linked_dynamically: - targets_to_be_linked_dynamically_set[owner_str] = True - linked_dynamically = True - else: - targets_to_be_linked_statically_map[owner_str] = node.linkable_more_than_once - must_add_children = True - linked_statically = True - - if has_owners_seen and has_owners_not_seen: - _programmatic_error() - - if linked_dynamically and linked_statically: - error_owners_list = [str(owner) for owner in node.owners] - - # Our granularity is target level. Unless there is a different - # unsupported custom implementation of this rule it should be - # impossible for two linker_inputs from the same target to be - # linked differently, one statically and the other dynamically. - _programmatic_error( - message = "Nodes with linker_inputs linked statically and dynamically:" + - "\n{}".format("\n".join(error_owners_list)), - ) - - if must_add_children: - # The order in which we process the children matter. all_children - # is being used as a stack, we will process first the nodes at the - # top of the stack (last in the list). The children are the - # dependencies of the current node, in order to respect the order - # in which dependencies were listed in the deps attribute in the - # BUILD file we must reverse the list so that the first one listed - # in the BUILD file is processed first. - deps_graph_nodes_to_process.extend(reversed(node.children)) - else: - if node.owners[0] not in first_owner_to_depset: - # We have 3 cases in this branch: - # 1. Node has no children - # 2. The children have been pruned because the node is linked dynamically - # 3. Node has children that have been processed - # For case 3 we add the children's depsets. For case 2 we add the dynamic - # dep labels for transitive dynamic deps. - transitive = [] - if str(node.owners[0]) in targets_to_be_linked_statically_map: - for child in node.children: - transitive.append(first_owner_to_depset[child.owners[0]]) - elif str(node.owners[0]) in transitive_dynamic_dep_labels: - transitive.append(transitive_dynamic_dep_labels[str(node.owners[0])]) - - first_owner_to_depset[node.owners[0]] = depset(direct = node.owners, transitive = transitive, order = "topological") - deps_graph_nodes_to_process.pop() - - topologically_sorted_labels = [] - if deps_graph_nodes: - transitive = [] - for child in deps_graph_nodes: - transitive.append(first_owner_to_depset[child.owners[0]]) - topologically_sorted_labels = depset(transitive = transitive, order = "topological").to_list() - - return (targets_to_be_linked_statically_map, targets_to_be_linked_dynamically_set, topologically_sorted_labels, all_dynamic_dep_linker_inputs) - -def _merge_cc_shared_library_infos(ctx): - dynamic_deps = [] - transitive_dynamic_deps = [] - for dep in ctx.attr.dynamic_deps: - dynamic_dep_entry = struct( - exports = dep[CcSharedLibraryInfo].exports, - linker_input = dep[CcSharedLibraryInfo].linker_input, - link_once_static_libs = dep[CcSharedLibraryInfo].link_once_static_libs, - ) - dynamic_deps.append(dynamic_dep_entry) - transitive_dynamic_deps.append(dep[CcSharedLibraryInfo].dynamic_deps) - - return depset(direct = dynamic_deps, transitive = transitive_dynamic_deps, order = "topological") - -def _build_exports_map_from_only_dynamic_deps(merged_cc_shared_library_infos_list): - exports_map = {} - for entry in merged_cc_shared_library_infos_list: - exports = entry.exports - linker_input = entry.linker_input - for export in exports: - if export in exports_map: - fail("Two shared libraries in dependencies export the same symbols. Both " + - exports_map[export].libraries[0].dynamic_library.short_path + - " and " + linker_input.libraries[0].dynamic_library.short_path + - " export " + export) - exports_map[export] = linker_input - return exports_map - -# The map points from the target that can only be linked once to the -# cc_shared_library target that already links it. -def _build_link_once_static_libs_map(merged_cc_shared_library_infos_list): - link_once_static_libs_map = {} - for entry in merged_cc_shared_library_infos_list: - link_once_static_libs = entry.link_once_static_libs - linker_input = entry.linker_input - for static_lib in link_once_static_libs: - if static_lib in link_once_static_libs_map: - fail("Two shared libraries in dependencies link the same " + - " library statically. Both " + link_once_static_libs_map[static_lib] + - " and " + str(linker_input.owner) + - " link statically " + static_lib) - link_once_static_libs_map[static_lib] = str(linker_input.owner) - return link_once_static_libs_map - -def _check_if_target_under_path(value, pattern): - if pattern.workspace_name != value.workspace_name: - return False - if pattern.name == "__pkg__": - return pattern.package == value.package - if pattern.name == "__subpackages__": - return _same_package_or_above(pattern, value) - - return pattern.package == value.package and pattern.name == value.name - -def _throw_linked_but_not_exported_errors(error_libs_dict): - if not error_libs_dict: - return - - error_builder = ["The following libraries were linked statically by different cc_shared_libraries but not exported:\n"] - for cc_shared_library_target, error_libs in error_libs_dict.items(): - error_builder.append("cc_shared_library %s:\n" % str(cc_shared_library_target)) - for error_lib in error_libs: - error_builder.append(" \"%s\",\n" % str(error_lib)) - - error_builder.append("If you are sure that the previous libraries are exported by the cc_shared_libraries because:\n") - error_builder.append(" 1. You have visibility declarations in the source code\n") - error_builder.append(" 2. Or you are passing a visibility script to the linker to export symbols from them\n") - error_builder.append("then add those libraries to roots or exports_filter for each cc_shared_library.\n") - - fail("".join(error_builder)) - -def _same_package_or_above(label_a, label_b): - if label_a.workspace_name != label_b.workspace_name: - return False - package_a_tokenized = label_a.package.split("/") - package_b_tokenized = label_b.package.split("/") - if len(package_b_tokenized) < len(package_a_tokenized): - return False - - if package_a_tokenized[0] != "": - for i in range(len(package_a_tokenized)): - if package_a_tokenized[i] != package_b_tokenized[i]: - return False - - return True - -def _build_map_direct_dynamic_dep_to_transitive_dynamic_deps(direct_dynamic_deps): - all_dynamic_dep_linker_inputs = {} - direct_dynamic_dep_to_transitive_dynamic_deps = {} - for dep in direct_dynamic_deps: - owner = dep[CcSharedLibraryInfo].linker_input.owner - all_dynamic_dep_linker_inputs[owner] = dep[CcSharedLibraryInfo].linker_input - transitive_dynamic_dep_labels = [] - for dynamic_dep in dep[CcSharedLibraryInfo].dynamic_deps.to_list(): - all_dynamic_dep_linker_inputs[dynamic_dep.linker_input.owner] = dynamic_dep.linker_input - transitive_dynamic_dep_labels.append(dynamic_dep.linker_input.owner) - transitive_dynamic_dep_labels_set = depset(transitive_dynamic_dep_labels, order = "topological") - for export in dep[CcSharedLibraryInfo].exports: - direct_dynamic_dep_to_transitive_dynamic_deps[export] = transitive_dynamic_dep_labels_set - - return direct_dynamic_dep_to_transitive_dynamic_deps, all_dynamic_dep_linker_inputs - -def _add_unused_dynamic_deps(ctx, unused_dynamic_linker_inputs, add_linker_inputs_lambda, topologically_sorted_labels, link_indirect_deps): - linker_inputs_count = 0 - direct_dynamic_dep_labels = {dep[CcSharedLibraryInfo].linker_input.owner: True for dep in ctx.attr.dynamic_deps} - topologically_sorted_labels_set = {label: True for label in topologically_sorted_labels} - for dynamic_linker_input_owner, unused_linker_input in unused_dynamic_linker_inputs.items(): - should_link_input = (unused_linker_input and - (link_indirect_deps or dynamic_linker_input_owner in direct_dynamic_dep_labels)) - if should_link_input: - add_linker_inputs_lambda( - dynamic_linker_input_owner, - unused_dynamic_linker_inputs[dynamic_linker_input_owner], - ) - linker_inputs_count += 1 - if dynamic_linker_input_owner not in topologically_sorted_labels_set: - topologically_sorted_labels.append(dynamic_linker_input_owner) - return linker_inputs_count - def _graph_structure_aspect_impl(target, ctx): children = [] @@ -605,6 +320,10 @@ ) </code></pre>"""), "_def_parser": semantics.get_def_parser(), + "_impl_delegate": attr.label( + default = Label("//cc/private/rules_impl/wrappers:cc_shared_library_impl_wrapper"), + cfg = "exec", + ), }, # buildifier: disable=unsorted-dict-items toolchains = use_cc_toolchain() + semantics.get_runtimes_toolchain(), fragments = ["cpp"] + semantics.additional_fragments(), @@ -659,12 +378,3 @@ aspects = [graph_structure_aspect], ), } - -for_testing_dont_use_check_if_target_under_path = _check_if_target_under_path -merge_cc_shared_library_infos = _merge_cc_shared_library_infos -build_link_once_static_libs_map = _build_link_once_static_libs_map -build_exports_map_from_only_dynamic_deps = _build_exports_map_from_only_dynamic_deps -throw_linked_but_not_exported_errors = _throw_linked_but_not_exported_errors -separate_static_and_dynamic_link_libraries = _separate_static_and_dynamic_link_libraries -sort_linker_inputs = _sort_linker_inputs -add_unused_dynamic_deps = _add_unused_dynamic_deps
diff --git a/cc/private/rules_impl/cc_shared_library_impl.bzl b/cc/private/rules_impl/cc_shared_library_impl.bzl index 18b6103..9b017c7 100644 --- a/cc/private/rules_impl/cc_shared_library_impl.bzl +++ b/cc/private/rules_impl/cc_shared_library_impl.bzl
@@ -15,17 +15,14 @@ """Implementation of cc_shared_library""" load("@bazel_skylib//lib:paths.bzl", "paths") -load("@com_google_protobuf//bazel/common:proto_info.bzl", "ProtoInfo") -load("//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") +load("//cc:find_cc_toolchain.bzl", "find_cc_toolchain") load("//cc/common:cc_common.bzl", "cc_common") load("//cc/common:cc_helper.bzl", "cc_helper") load("//cc/common:cc_info.bzl", "CcInfo") -load("//cc/common:cc_shared_library_hint_info.bzl", "CcSharedLibraryHintInfo") load("//cc/common:cc_shared_library_info.bzl", "CcSharedLibraryInfo") load("//cc/common:semantics.bzl", "semantics") load("//cc/private:graph_node_info.bzl", "GraphNodeInfo") - -visibility("private") +load(":function_providing_rule.bzl", "wrap_starlark_function") # TODO(#5200): Add export_define to library_to_link and cc_library @@ -785,349 +782,6 @@ ), ] -def _graph_structure_aspect_impl(target, ctx): - children = [] - - attributes = dir(ctx.rule.attr) - owners = [ctx.label] - if CcSharedLibraryHintInfo in target: - attributes = getattr(target[CcSharedLibraryHintInfo], "attributes", dir(ctx.rule.attr)) - owners = getattr(target[CcSharedLibraryHintInfo], "owners", [ctx.label]) - - # Collect graph structure info from any possible deplike attribute. The aspect - # itself applies across every deplike attribute (attr_aspects is *), so enumerate - # over all attributes and consume GraphNodeInfo if available. - for fieldname in attributes: - deps = getattr(ctx.rule.attr, fieldname, None) - if type(deps) == "list": - for dep in deps: - if type(dep) == "Target" and GraphNodeInfo in dep: - children.append(dep[GraphNodeInfo]) - elif type(deps) == "Target" and GraphNodeInfo in deps: - children.append(deps[GraphNodeInfo]) - - # TODO(bazel-team): Add flag to Bazel that can toggle the initialization of - # linkable_more_than_once. - linkable_more_than_once = False - if hasattr(ctx.rule.attr, "tags"): - for tag in ctx.rule.attr.tags: - if tag == LINKABLE_MORE_THAN_ONCE: - linkable_more_than_once = True - return [GraphNodeInfo( - owners = owners, - children = children, - linkable_more_than_once = linkable_more_than_once, - )] - -graph_structure_aspect = aspect( - attr_aspects = ["*"], - required_providers = [[CcInfo], [CcSharedLibraryHintInfo], [ProtoInfo]], - required_aspect_providers = [[CcInfo], [CcSharedLibraryHintInfo]], - implementation = _graph_structure_aspect_impl, -) - -def _cc_shared_library_initializer(**kwargs): - """Converts labels in exports_filter into canonical form relative to the current repository. - - This conversion can only be done in a macro as it requires access to the repository mapping of - the repository containing the cc_shared_library target. This mapping is automatically - applied to label attributes, but exports_filter is a list of strings attribute. - """ - if "exports_filter" not in kwargs: - return kwargs - - raw_exports_filter = kwargs["exports_filter"] - if type(raw_exports_filter) != type([]): - # TODO: Also canonicalize labels in selects once macros can operate on them. - # https://github.com/bazelbuild/bazel/issues/14157 - return kwargs - - canonical_exports_filter = [ - str(native.package_relative_label(s)) - for s in raw_exports_filter - ] - return kwargs | {"exports_filter": canonical_exports_filter} - -cc_shared_library = rule( - implementation = _cc_shared_library_impl, - initializer = _cc_shared_library_initializer, - doc = """ -<p>It produces a shared library.</p> - -<h4 id="cc_shard_library_examples">Example</h4> - -<pre class="code"> -cc_shared_library( - name = "foo_shared", - deps = [ - ":foo", - ], - dynamic_deps = [ - ":bar_shared", - ], - additional_linker_inputs = [ - ":foo.lds", - ], - user_link_flags = [ - "-Wl,--version-script=$(location :foo.lds)", - ], -) -cc_library( - name = "foo", - srcs = ["foo.cc"], - hdrs = ["foo.h"], - deps = [ - ":bar", - ":baz", - ], -) -cc_shared_library( - name = "bar_shared", - shared_lib_name = "bar.so", - deps = [":bar"], -) -cc_library( - name = "bar", - srcs = ["bar.cc"], - hdrs = ["bar.h"], -) -cc_library( - name = "baz", - srcs = ["baz.cc"], - hdrs = ["baz.h"], -) -</pre> - -<p>In the example <code>foo_shared</code> statically links <code>foo</code> -and <code>baz</code>, the latter being a transitive dependency. It doesn't -link <code>bar</code> because it is already provided dynamically by the -<code>dynamic_dep</code> <code>bar_shared</code>.</p> - -<p><code>foo_shared</code> uses a linker script *.lds file to control which -symbols should be exported. The <code>cc_shared_library</code> rule logic does -not control which symbols get exported, it only uses what is assumed to be -exported to give errors during analysis phase if two shared libraries export the -same targets.</p> - -<p>Every direct dependency of <code>cc_shared_library</code> is assumed to be -exported. Therefore, Bazel assumes during analysis that <code>foo</code> is being -exported by <code>foo_shared</code>. <code>baz</code> is not assumed to be exported -by <code>foo_shared</code>. Every target matched by the <code>exports_filter</code> -is also assumed to be exported.</p> - -<p>Every single <code>cc_library</code> in the example should appear at most in one -<code>cc_shared_library</code>. If we wanted to link <code>baz</code> also into -<code>bar_shared</code> we would need to add -<code>tags = ["LINKABLE_MORE_THAN_ONCE"]</code> to <code>baz</code>.</p> - -<p>Due to the <code>shared_lib_name</code> attribute, the file produced by -<code>bar_shared</code> will have the name <code>bar.so</code> as opposed -to the name <code>libbar.so</code> that it would have by default on Linux.</p> - -<h4 id="cc_shard_library_examples">Errors</h4> -<h5><code>Two shared libraries in dependencies export the same symbols.</code></h5> - -<p>This will happen whenever you are creating a target with two different -<code>cc_shared_library</code> dependencies that export the same target. To fix this -you need to stop the libraries from being exported in one of the -<code>cc_shared_library</code> dependencies.</p> - -<h5><code>Two shared libraries in dependencies link the same library statically</code></h5> - -<p>This will happen whenever you are creating a new <code>cc_shared_library</code> with two -different <code>cc_shared_library</code> dependencies that link the same target statically. -Similar to the error with exports.</p> - -<p>One way to fix this is to stop linking the library into one of the -<code>cc_shared_library</code> dependencies. At the same time, the one that still links it -needs to export the library so that the one not linking it keeps visibility to -the symbols. Another way is to pull out a third library that exports the target. -A third way is to tag the culprit <code>cc_library</code> with <code>LINKABLE_MORE_THAN_ONCE</code> -but this fix should be rare and you should absolutely make sure that the -<code>cc_library</code> is indeed safe to link more than once.</p> - -<h5><code>'//foo:foo' is already linked statically in '//bar:bar' but not exported`</code></h5> - -<p>This means that a library in the transitive closure of your <code>deps</code> is reachable -without going through one of the <code>cc_shared_library</code> dependencies but is already -linked into a different <code>cc_shared_library</code> in <code>dynamic_deps</code> and is not -exported.</p> - -<p>The solution is to export it from the <code>cc_shared_library</code> dependency or pull out -a third <code>cc_shared_library</code> that exports it.</p> - -<h5><code>Do not place libraries which only contain a precompiled dynamic library in deps. -</code></h5> - -<p>If you have a precompiled dynamic library, this doesn't need to and cannot be -linked statically into the current <code>cc_shared_library</code> target that you are -currently creating. Therefore, it doesn't belong in <code>deps</code> of the -<code>cc_shared_library</code>. If this precompiled dynamic library is a dependency of one -of your <code>cc_libraries</code>, then the <code>cc_library</code> needs to depend on it -directly.</p> - -<h5><code>Trying to export a library already exported by a different shared library</code></h5> - -<p>You will see this error if on the current rule you are claiming to export a -target that is already being exported by one of your dynamic dependencies.</p> - -<p>To fix this, remove the target from <code>deps</code> and just rely on it from the dynamic -dependency or make sure that the <code>exports_filter</code> doesn't catch this target.</p>""", - attrs = { - "additional_linker_inputs": attr.label_list(allow_files = True, doc = """ -Any additional files that you may want to pass to the linker, for example, linker scripts. -You have to separately pass any linker flags that the linker needs in order to be aware -of this file. You can do so via the <code>user_link_flags</code> attribute."""), - "shared_lib_name": attr.string(doc = """ -By default cc_shared_library will use a name for the shared library output file based on -the target's name and the platform. This includes an extension and sometimes a prefix. -Sometimes you may not want the default name, for example, when loading C++ shared libraries -for Python the default lib* prefix is often not desired, in which case you can use this -attribute to choose a custom name."""), - "dynamic_deps": attr.label_list(providers = [CcSharedLibraryInfo], doc = """ -These are other <code>cc_shared_library</code> dependencies the current target depends on. - -<p> -The <code>cc_shared_library</code> implementation will use the list of -<code>dynamic_deps</code> (transitively, i.e. also the <code>dynamic_deps</code> of the -current target's <code>dynamic_deps</code>) to decide which <code>cc_libraries</code> in -the transitive <code>deps</code> should not be linked in because they are already provided -by a different <code>cc_shared_library</code>. -</p>"""), - "exports_filter": attr.string_list(doc = """ -This attribute contains a list of targets that are claimed to be exported by the current -shared library. - -<p> -Any target <code>deps</code> is already understood to be exported by the shared library. -This attribute should be used to list any targets that are exported by the shared library -but are transitive dependencies of <code>deps</code>. -</p> - -<p> -Note that this attribute is not actually adding a dependency edge to those targets, the -dependency edge should instead be created by <code>deps</code>.The entries in this -attribute are just strings. Keep in mind that when placing a target in this attribute, -this is considered a claim that the shared library exports the symbols from that target. -The <code>cc_shared_library</code> logic doesn't actually handle telling the linker which -symbols should be exported. -</p> - -<p>The following syntax is allowed:</p> -<p><code>//foo:__pkg__</code> to account for any target in foo/BUILD</p> -<p><code>//foo:__subpackages__</code> to account for any target in foo/BUILD or any other -package below foo/ like foo/bar/BUILD</p>"""), - "win_def_file": attr.label(allow_single_file = [".def"], doc = """ -The Windows DEF file to be passed to linker. -<p>This attribute should only be used when Windows is the target platform. -It can be used to <a href="https://msdn.microsoft.com/en-us/library/d91k01sh.aspx"> -export symbols</a> during linking a shared library.</p>"""), - "roots": attr.label_list(providers = [CcInfo], aspects = [graph_structure_aspect]), - "deps": attr.label_list(providers = [CcInfo], aspects = [graph_structure_aspect], doc = """ -Top level libraries that will unconditionally be statically linked into the shared library -after being whole-archived. - -<p> -Any transitive library dependency of these direct deps will be linked into this shared -library as long as they have not already been linked by a <code>cc_shared_library</code> -in <code>dynamic_deps</code>.</p> - -<p> -During analysis, the rule implementation will consider any target listed in -<code>deps</code> as being exported by the shared library in order to give errors when -multiple <code>cc_shared_libraries</code> export the same targets. The rule implementation -does not take care of informing the linker about which symbols should be exported by the -shared object. The user should take care of this via linker scripts or visibility -declarations in the source code.</p> - -<p> -The implementation will also trigger errors whenever the same library is linked statically -into more than one <code>cc_shared_library</code>. This can be avoided by adding -<code>"LINKABLE_MORE_THAN_ONCE"</code> to the <code>cc_library.tags</code> or by listing -the `cc_library` as an export of one of the shared libraries so that one can be made a -<code>dynamic_dep</code> of the other. -</p>"""), - "static_deps": attr.string_list(), - "user_link_flags": attr.string_list(doc = """ -Any additional flags that you may want to pass to the linker. For example, to make the -linker aware of a linker script passed via additional_linker_inputs you can use the -following: - -<pre><code class="lang-starlark"> - cc_shared_library( - name = "foo_shared", - additional_linker_inputs = select({ - "//src/conditions:linux": [ - ":foo.lds", - ":additional_script.txt", - ], - "//conditions:default": []}), - user_link_flags = select({ - "//src/conditions:linux": [ - "-Wl,-rpath,kittens", - "-Wl,--version-script=$(location :foo.lds)", - "-Wl,--script=$(location :additional_script.txt)", - ], - "//conditions:default": []}), - ... - ) -</code></pre>"""), - "_def_parser": semantics.get_def_parser(), - }, # buildifier: disable=unsorted-dict-items - toolchains = use_cc_toolchain() + semantics.get_runtimes_toolchain(), - fragments = ["cpp"] + semantics.additional_fragments(), -) - -def dynamic_deps_initializer(**kwargs): - """Initializes dynamic_deps_attrs - - Args: - **kwargs: (dict) - - Returns: - (dict) - """ - if "dynamic_deps" in kwargs and cc_helper.is_non_empty_list_or_select(kwargs["dynamic_deps"], "dynamic_deps"): - # Propagate an aspect if dynamic_deps attribute is specified. - # Use += for lists rather than extend or append to allow for the case where deps - # is a select. - all_deps = [] - if "deps" in kwargs: - all_deps += kwargs["deps"] - - if "linkshared" not in kwargs or not kwargs["linkshared"]: - # The += [...] pattern below doesn't work if malloc or link_extra_lib are - # themselves selects, but as of March 2024, there is no way to combine mixed - # selects and these attributes usually point to label flags anyway. - if "link_extra_lib" in kwargs: - all_deps += [kwargs["link_extra_lib"]] # buildifier: disable=list-append - if "malloc" in kwargs: - all_deps += [kwargs["malloc"]] # buildifier: disable=list-append - - return kwargs | {"_deps_analyzed_by_graph_structure_aspect": all_deps} - return kwargs - -dynamic_deps_attrs = { - "dynamic_deps": attr.label_list( - allow_files = False, - providers = [CcSharedLibraryInfo], - doc = """ -These are other <code>cc_shared_library</code> dependencies the current target depends on. - -<p> -The <code>cc_shared_library</code> implementation will use the list of -<code>dynamic_deps</code> (transitively, i.e. also the <code>dynamic_deps</code> of the -current target's <code>dynamic_deps</code>) to decide which <code>cc_libraries</code> in -the transitive <code>deps</code> should not be linked in because they are already provided -by a different <code>cc_shared_library</code>. - """ + semantics.dynamic_deps_extra_docs, - ), - "_deps_analyzed_by_graph_structure_aspect": attr.label_list( - providers = [CcInfo], - aspects = [graph_structure_aspect], - ), -} - for_testing_dont_use_check_if_target_under_path = _check_if_target_under_path merge_cc_shared_library_infos = _merge_cc_shared_library_infos build_link_once_static_libs_map = _build_link_once_static_libs_map @@ -1138,3 +792,4 @@ add_unused_dynamic_deps = _add_unused_dynamic_deps cc_shared_library_impl = _cc_shared_library_impl +cc_shared_library_impl_wrapper = wrap_starlark_function(_cc_shared_library_impl)
diff --git a/cc/private/rules_impl/cc_test.bzl b/cc/private/rules_impl/cc_test.bzl index e02be7e..375ff0f 100644 --- a/cc/private/rules_impl/cc_test.bzl +++ b/cc/private/rules_impl/cc_test.bzl
@@ -40,6 +40,10 @@ env_inherit = attr.string_list(), stamp = attr.int(values = [-1, 0, 1], default = 0, doc = stamp_doc), linkstatic = attr.bool(default = False, doc = linkstatic_doc), + _impl_delegate = attr.label( + default = Label("//cc/private/rules_impl/wrappers:cc_test_impl_wrapper"), + cfg = "exec", + ), ) _cc_test_attrs.update(semantics.get_test_malloc_attr()) _cc_test_attrs.update(semantics.get_coverage_attrs())
diff --git a/cc/private/rules_impl/cc_test_impl.bzl b/cc/private/rules_impl/cc_test_impl.bzl index 4636534..d223169 100644 --- a/cc/private/rules_impl/cc_test_impl.bzl +++ b/cc/private/rules_impl/cc_test_impl.bzl
@@ -16,10 +16,8 @@ load("//cc/common:cc_helper.bzl", "cc_helper") load("//cc/common:semantics.bzl", "semantics") -load(":attrs.bzl", "cc_binary_attrs", "linkstatic_doc", "stamp_doc") load(":cc_binary_impl.bzl", "cc_binary_impl") - -visibility("private") +load(":function_providing_rule.bzl", "wrap_starlark_function") _CC_TEST_TOOLCHAIN_TYPE = "@bazel_tools//tools/cpp:test_runner_toolchain_type" @@ -74,25 +72,5 @@ providers.extend(test_providers) return providers -_cc_test_attrs = dict(cc_binary_attrs) - -# Update cc_test defaults: -_cc_test_attrs.update( - _is_test = attr.bool(default = True), - _apple_constraints = attr.label_list( - default = [ - "@platforms//os:ios", - "@platforms//os:macos", - "@platforms//os:tvos", - "@platforms//os:watchos", - ], - ), - # Starlark tests don't get `env_inherit` by default. - env_inherit = attr.string_list(), - stamp = attr.int(values = [-1, 0, 1], default = 0, doc = stamp_doc), - linkstatic = attr.bool(default = False, doc = linkstatic_doc), -) -_cc_test_attrs.update(semantics.get_test_malloc_attr()) -_cc_test_attrs.update(semantics.get_coverage_attrs()) - impl = _impl +cc_test_impl_wrapper = wrap_starlark_function(_impl)
diff --git a/cc/private/rules_impl/function_providing_rule.bzl b/cc/private/rules_impl/function_providing_rule.bzl new file mode 100644 index 0000000..950e10c --- /dev/null +++ b/cc/private/rules_impl/function_providing_rule.bzl
@@ -0,0 +1,30 @@ +# Copyright 2020 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Trivially simple rule to provide a Starlark function via a target""" + +visibility([ + "//third_party/bazel_rules/rules_cc/private/rules_impl", +]) + +FunctionInfo = provider("Wraps a Starlark function", fields = ["func"]) + +def wrap_starlark_function(func): + return rule( + implementation = lambda _unused_ctx: FunctionInfo(func = func), + provides = [FunctionInfo], + ) + +def proxy(ctx): + return ctx.attr._impl_delegate[FunctionInfo].func(ctx)
diff --git a/cc/private/rules_impl/wrappers/BUILD b/cc/private/rules_impl/wrappers/BUILD new file mode 100644 index 0000000..c16cf37 --- /dev/null +++ b/cc/private/rules_impl/wrappers/BUILD
@@ -0,0 +1,38 @@ +load("//cc/private/rules_impl:cc_binary_impl.bzl", "cc_binary_impl_wrapper") +load("//cc/private/rules_impl:cc_library_impl.bzl", "cc_library_impl_wrapper") +load("//cc/private/rules_impl:cc_shared_library_impl.bzl", "cc_shared_library_impl_wrapper") +load("//cc/private/rules_impl:cc_test_impl.bzl", "cc_test_impl_wrapper") + +licenses(["notice"]) + +filegroup( + name = "srcs", + srcs = [ + "BUILD", + ], + visibility = ["//cc/private/rules_impl:__pkg__"], +) + +cc_binary_impl_wrapper( + name = "cc_binary_impl_wrapper", + applicable_licenses = [], + visibility = ["//visibility:public"], +) + +cc_library_impl_wrapper( + name = "cc_library_impl_wrapper", + applicable_licenses = [], + visibility = ["//visibility:public"], +) + +cc_test_impl_wrapper( + name = "cc_test_impl_wrapper", + applicable_licenses = [], + visibility = ["//visibility:public"], +) + +cc_shared_library_impl_wrapper( + name = "cc_shared_library_impl_wrapper", + applicable_licenses = [], + visibility = ["//visibility:public"], +)