@@ -37,7 +37,7 @@ GraphNodeInfo = provider(
37
37
"Nodes in the graph of shared libraries." ,
38
38
fields = {
39
39
"children" : "Other GraphNodeInfo from dependencies of this target" ,
40
- "label " : "Label of the target visited" ,
40
+ "owners " : "Owners of the linker inputs in the targets visited" ,
41
41
"linkable_more_than_once" : "Linkable into more than a single cc_shared_library" ,
42
42
},
43
43
)
@@ -54,6 +54,42 @@ CcSharedLibraryInfo = provider(
54
54
},
55
55
)
56
56
57
+ CcSharedLibraryHintInfo = provider (
58
+ doc = """
59
+ This provider should be used by rules that provide C++ linker inputs and
60
+ want to guide what the cc_shared_library uses. The reason for this may be
61
+ for example because the rule is not providing a standard provider like
62
+ CcInfo or ProtoInfo or because the rule does not want certain attributes
63
+ to be used for linking into shared libraries. It may also be needed if the
64
+ rule is using non-standard linker_input.owner names.
65
+
66
+ Propagation of the cc_shared_library aspect will always happen via all
67
+ attributes that provide either CcInfo, ProtoInfo or
68
+ CcSharedLibraryHintInfo, the hints control whether the result of that
69
+ propagation actually gets used.
70
+ """ ,
71
+ fields = {
72
+ "attributes" : ("[String] - If not set, the aspect will use the result of every " +
73
+ "dependency that provides CcInfo, ProtoInfo or CcSharedLibraryHintInfo. " +
74
+ "If empty list, the aspect will not use the result of any dependency. If " +
75
+ "the list contains a list of attribute names, the aspect will only use the " +
76
+ "dependencies corresponding to those attributes as long as they provide CcInfo, " +
77
+ "ProtoInfo or CcSharedLibraryHintInfo" ),
78
+ "owners" : ("[Label] - cc_shared_library will know which linker_inputs to link based on the owners " +
79
+ "field of each linker_input. Most rules will simply use the ctx.label but certain " +
80
+ "APIs like cc_common.create_linker_input(owner=) accept any label. " +
81
+ "cc_common.create_linking_context_from_compilation_outputs() accepts a `name` which " +
82
+ "will then be used to create the owner of the linker_input together with ctx.package." +
83
+ "For these cases, since the cc_shared_library cannot guess, the rule author should " +
84
+ "provide a hint with the owners of the linker inputs. If the value of owners is not set, then " +
85
+ "ctx.label will be used. If the rule author passes a list and they want ctx.label plus some other " +
86
+ "label then they will have to add ctx.label explicitly. If you want to use custom owners from C++ " +
87
+ "rules keep as close to the original ctx.label as possible, to avoid conflicts with linker_inputs " +
88
+ "created by other targets keep the original repository name, the original package name and re-use " +
89
+ "the original name as part of your new name, limiting your custom addition to a prefix or suffix." ),
90
+ },
91
+ )
92
+
57
93
# For each target, find out whether it should be linked statically or
58
94
# dynamically.
59
95
def _separate_static_and_dynamic_link_libraries (
@@ -72,16 +108,46 @@ def _separate_static_and_dynamic_link_libraries(
72
108
break
73
109
74
110
node = all_children [i ]
75
- node_label = str (node .label )
76
111
77
- if node_label in seen_labels :
78
- continue
79
- seen_labels [node_label ] = True
80
-
81
- if node_label in can_be_linked_dynamically :
82
- targets_to_be_linked_dynamically_set [node_label ] = True
83
- else :
84
- targets_to_be_linked_statically_map [node_label ] = node .linkable_more_than_once
112
+ must_add_children = False
113
+
114
+ # The *_seen variables are used to track a programmatic error and fail
115
+ # if it happens. Every value in node.owners presumably corresponds to
116
+ # a linker_input in the same exact target. Therefore if we have seen
117
+ # any of the owners already, then we must have also seen all the other
118
+ # owners in the same node. Viceversa when we haven't seen them yet. If
119
+ # both of these values are non-zero after the loop, the most likely
120
+ # reason would be a bug in the implementation. It could potentially be
121
+ # triggered by users if they use owner labels that do not keep most of
122
+ # the ctx.label.package and ctx.label.name which then clash with other
123
+ # target's owners (unlikely). For now though if the error is
124
+ # triggered, it's reasonable to require manual revision by
125
+ # the cc_shared_library implementation owners.
126
+ has_owners_seen = False
127
+ has_owners_not_seen = False
128
+ for owner in node .owners :
129
+ # TODO(bazel-team): Do not convert Labels to string to save on
130
+ # garbage string allocations.
131
+ owner_str = str (owner )
132
+
133
+ if owner_str in seen_labels :
134
+ has_owners_seen = True
135
+ continue
136
+
137
+ has_owners_not_seen = True
138
+ seen_labels [owner_str ] = True
139
+
140
+ if owner_str in can_be_linked_dynamically :
141
+ targets_to_be_linked_dynamically_set [owner_str ] = True
142
+ else :
143
+ targets_to_be_linked_statically_map [owner_str ] = node .linkable_more_than_once
144
+ must_add_children = True
145
+
146
+ if has_owners_seen and has_owners_not_seen :
147
+ fail ("Your build has triggered a programmatic error in the cc_shared_library rule. " +
148
+ "Please file an issue in https://github.com/bazelbuild/bazel" )
149
+
150
+ if must_add_children :
85
151
all_children .extend (node .children )
86
152
87
153
return (targets_to_be_linked_statically_map , targets_to_be_linked_dynamically_set )
@@ -209,20 +275,22 @@ def _find_top_level_linker_input_labels(
209
275
break
210
276
211
277
node = nodes_to_check [i ]
212
- node_label = str (node .label )
213
- if node_label in linker_inputs_to_be_linked_statically_map :
214
- has_code_to_link = False
215
- for linker_input in linker_inputs_to_be_linked_statically_map [node_label ]:
216
- if _contains_code_to_link (linker_input ):
217
- top_level_linker_input_labels_set [node_label ] = True
218
- has_code_to_link = True
219
- break
220
-
221
- if not has_code_to_link :
222
- nodes_to_check .extend (node .children )
223
- elif node_label not in targets_to_be_linked_dynamically_set :
224
- # This can happen when there was a target in the graph that exported other libraries'
225
- # linker_inputs but didn't contribute any linker_input of its own.
278
+ must_add_children = False
279
+ for owner in node .owners :
280
+ owner_str = str (owner )
281
+ if owner_str in linker_inputs_to_be_linked_statically_map :
282
+ must_add_children = True
283
+ for linker_input in linker_inputs_to_be_linked_statically_map [owner_str ]:
284
+ if _contains_code_to_link (linker_input ):
285
+ top_level_linker_input_labels_set [owner_str ] = True
286
+ must_add_children = False
287
+ break
288
+ elif owner_str not in targets_to_be_linked_dynamically_set :
289
+ # This can happen when there was a target in the graph that exported other libraries'
290
+ # linker_inputs but didn't contribute any linker_input of its own.
291
+ must_add_children = True
292
+
293
+ if must_add_children :
226
294
nodes_to_check .extend (node .children )
227
295
228
296
return top_level_linker_input_labels_set
@@ -590,10 +658,16 @@ def _cc_shared_library_impl(ctx):
590
658
def _graph_structure_aspect_impl (target , ctx ):
591
659
children = []
592
660
661
+ attributes = dir (ctx .rule .attr )
662
+ owners = [ctx .label ]
663
+ if CcSharedLibraryHintInfo in target :
664
+ attributes = getattr (target [CcSharedLibraryHintInfo ], "attributes" , dir (ctx .rule .attr ))
665
+ owners = getattr (target [CcSharedLibraryHintInfo ], "owners" , [ctx .label ])
666
+
593
667
# Collect graph structure info from any possible deplike attribute. The aspect
594
668
# itself applies across every deplike attribute (attr_aspects is *), so enumerate
595
669
# over all attributes and consume GraphNodeInfo if available.
596
- for fieldname in dir ( ctx . rule . attr ) :
670
+ for fieldname in attributes :
597
671
deps = getattr (ctx .rule .attr , fieldname , None )
598
672
if type (deps ) == "list" :
599
673
for dep in deps :
@@ -609,17 +683,16 @@ def _graph_structure_aspect_impl(target, ctx):
609
683
for tag in ctx .rule .attr .tags :
610
684
if tag == LINKABLE_MORE_THAN_ONCE :
611
685
linkable_more_than_once = True
612
-
613
686
return [GraphNodeInfo (
614
- label = ctx . label ,
687
+ owners = owners ,
615
688
children = children ,
616
689
linkable_more_than_once = linkable_more_than_once ,
617
690
)]
618
691
619
692
graph_structure_aspect = aspect (
620
693
attr_aspects = ["*" ],
621
- required_providers = [[CcInfo ], [ProtoInfo ]],
622
- required_aspect_providers = [[CcInfo ]],
694
+ required_providers = [[CcInfo ], [ProtoInfo ], [ CcSharedLibraryHintInfo ] ],
695
+ required_aspect_providers = [[CcInfo ], [ CcSharedLibraryHintInfo ] ],
623
696
implementation = _graph_structure_aspect_impl ,
624
697
)
625
698
@@ -654,3 +727,4 @@ merge_cc_shared_library_infos = _merge_cc_shared_library_infos
654
727
build_link_once_static_libs_map = _build_link_once_static_libs_map
655
728
build_exports_map_from_only_dynamic_deps = _build_exports_map_from_only_dynamic_deps
656
729
throw_linked_but_not_exported_errors = _throw_linked_but_not_exported_errors
730
+ separate_static_and_dynamic_link_libraries = _separate_static_and_dynamic_link_libraries
0 commit comments