@@ -73,14 +73,16 @@ CcSharedLibraryInfo = provider(
73
73
},
74
74
)
75
75
76
+ # For each target, find out whether it should be linked statically or
77
+ # dynamically.
76
78
def _separate_static_and_dynamic_link_libraries (
77
79
direct_children ,
78
80
can_be_linked_dynamically ,
79
81
preloaded_deps_direct_labels ):
80
82
node = None
81
83
all_children = list (direct_children )
82
- link_statically_labels = {}
83
- link_dynamically_labels = {}
84
+ targets_to_be_linked_statically_map = {}
85
+ targets_to_be_linked_dynamically_set = {}
84
86
85
87
seen_labels = {}
86
88
@@ -97,12 +99,12 @@ def _separate_static_and_dynamic_link_libraries(
97
99
seen_labels [node_label ] = True
98
100
99
101
if node_label in can_be_linked_dynamically :
100
- link_dynamically_labels [node_label ] = True
102
+ targets_to_be_linked_dynamically_set [node_label ] = True
101
103
elif node_label not in preloaded_deps_direct_labels :
102
- link_statically_labels [node_label ] = node .linkable_more_than_once
104
+ targets_to_be_linked_statically_map [node_label ] = node .linkable_more_than_once
103
105
all_children .extend (node .children )
104
106
105
- return (link_statically_labels , link_dynamically_labels )
107
+ return (targets_to_be_linked_statically_map , targets_to_be_linked_dynamically_set )
106
108
107
109
def _create_linker_context (ctx , linker_inputs ):
108
110
return cc_common .create_linking_context (
@@ -142,6 +144,8 @@ def _build_exports_map_from_only_dynamic_deps(merged_shared_library_infos):
142
144
exports_map [export ] = linker_input
143
145
return exports_map
144
146
147
+ # The map points from the target that can only be linked once to the
148
+ # cc_shared_library target that already links it.
145
149
def _build_link_once_static_libs_map (merged_shared_library_infos ):
146
150
link_once_static_libs_map = {}
147
151
for entry in merged_shared_library_infos .to_list ():
@@ -251,7 +255,7 @@ def _filter_inputs(
251
255
preloaded_deps_direct_labels ,
252
256
link_once_static_libs_map ):
253
257
linker_inputs = []
254
- curr_link_once_static_libs_map = {}
258
+ curr_link_once_static_libs_set = {}
255
259
256
260
graph_structure_aspect_nodes = []
257
261
dependency_linker_inputs = []
@@ -267,16 +271,25 @@ def _filter_inputs(
267
271
if owner in transitive_exports :
268
272
can_be_linked_dynamically [owner ] = True
269
273
270
- (link_statically_labels , link_dynamically_labels ) = _separate_static_and_dynamic_link_libraries (
274
+ # The targets_to_be_linked_statically_map points to whether the target to
275
+ # be linked statically can be linked more than once.
276
+ (targets_to_be_linked_statically_map , targets_to_be_linked_dynamically_set ) = _separate_static_and_dynamic_link_libraries (
271
277
graph_structure_aspect_nodes ,
272
278
can_be_linked_dynamically ,
273
279
preloaded_deps_direct_labels ,
274
280
)
275
281
282
+ # We keep track of precompiled_only_dynamic_libraries, so that we can add
283
+ # them to runfiles.
276
284
precompiled_only_dynamic_libraries = []
277
- unaccounted_for_libs = []
278
285
exports = {}
279
286
linker_inputs_seen = {}
287
+
288
+ # We use this dictionary to give an error if a target containing only
289
+ # precompiled dynamic libraries is placed directly in roots. If such a
290
+ # precompiled dynamic library is needed it would be because a target in the
291
+ # parallel cc_library graph actually needs it. Therefore the precompiled
292
+ # dynamic library should be made a dependency of that cc_library instead.
280
293
dynamic_only_roots = {}
281
294
linked_statically_but_not_exported = {}
282
295
for linker_input in dependency_linker_inputs :
@@ -285,11 +298,21 @@ def _filter_inputs(
285
298
continue
286
299
linker_inputs_seen [stringified_linker_input ] = True
287
300
owner = str (linker_input .owner )
288
- if owner in link_dynamically_labels :
289
- dynamic_linker_input = transitive_exports [owner ]
290
- linker_inputs .append (dynamic_linker_input )
291
- elif owner in link_statically_labels :
301
+ if owner in targets_to_be_linked_dynamically_set :
302
+ # Link the library in this iteration dynamically,
303
+ # transitive_exports contains the artifacts produced by a
304
+ # cc_shared_library
305
+ linker_inputs .append (transitive_exports [owner ])
306
+ elif owner in targets_to_be_linked_statically_map :
292
307
if owner in link_once_static_libs_map :
308
+ # We are building a dictionary that will allow us to give
309
+ # proper errors for libraries that have been linked multiple
310
+ # times elsewhere but haven't been exported. The values in the
311
+ # link_once_static_libs_map dictionary are the
312
+ # cc_shared_library targets. In this iteration we know of at
313
+ # least one target (i.e. owner) which is being linked
314
+ # statically by the cc_shared_library
315
+ # link_once_static_libs_map[owner] but is not being exported
293
316
linked_statically_but_not_exported .setdefault (link_once_static_libs_map [owner ], []).append (owner )
294
317
295
318
is_direct_export = owner in direct_exports
@@ -311,41 +334,26 @@ def _filter_inputs(
311
334
if len (static_libraries ) and owner in dynamic_only_roots :
312
335
dynamic_only_roots .pop (owner )
313
336
337
+ linker_input_to_be_linked_statically = linker_input
314
338
if is_direct_export :
315
- wrapped_library = _wrap_static_library_with_alwayslink (
339
+ linker_input_to_be_linked_statically = _wrap_static_library_with_alwayslink (
316
340
ctx ,
317
341
feature_configuration ,
318
342
cc_toolchain ,
319
343
linker_input ,
320
344
)
345
+ elif _check_if_target_should_be_exported_with_filter (
346
+ linker_input .owner ,
347
+ ctx .label ,
348
+ ctx .attr .exports_filter ,
349
+ _get_permissions (ctx ),
350
+ ):
351
+ exports [owner ] = True
321
352
322
- if not link_statically_labels [owner ]:
323
- curr_link_once_static_libs_map [owner ] = True
324
- linker_inputs .append (wrapped_library )
325
- else :
326
- can_be_linked_statically = False
327
-
328
- for static_dep_path in ctx .attr .static_deps :
329
- static_dep_path_label = ctx .label .relative (static_dep_path )
330
- if _check_if_target_under_path (linker_input .owner , static_dep_path_label ):
331
- can_be_linked_statically = True
332
- break
333
-
334
- if _check_if_target_should_be_exported_with_filter (
335
- linker_input .owner ,
336
- ctx .label ,
337
- ctx .attr .exports_filter ,
338
- _get_permissions (ctx ),
339
- ):
340
- exports [owner ] = True
341
- can_be_linked_statically = True
342
-
343
- if can_be_linked_statically :
344
- if not link_statically_labels [owner ]:
345
- curr_link_once_static_libs_map [owner ] = True
346
- linker_inputs .append (linker_input )
347
- else :
348
- unaccounted_for_libs .append (linker_input .owner )
353
+ linker_inputs .append (linker_input_to_be_linked_statically )
354
+
355
+ if not targets_to_be_linked_statically_map [owner ]:
356
+ curr_link_once_static_libs_set [owner ] = True
349
357
350
358
if dynamic_only_roots :
351
359
message = ("Do not place libraries which only contain a " +
@@ -356,8 +364,7 @@ def _filter_inputs(
356
364
fail (message )
357
365
358
366
_throw_linked_but_not_exported_errors (linked_statically_but_not_exported )
359
- _throw_error_if_unaccounted_libs (unaccounted_for_libs )
360
- return (exports , linker_inputs , curr_link_once_static_libs_map .keys (), precompiled_only_dynamic_libraries )
367
+ return (exports , linker_inputs , curr_link_once_static_libs_set .keys (), precompiled_only_dynamic_libraries )
361
368
362
369
def _throw_linked_but_not_exported_errors (error_libs_dict ):
363
370
if not error_libs_dict :
@@ -376,28 +383,6 @@ def _throw_linked_but_not_exported_errors(error_libs_dict):
376
383
377
384
fail ("" .join (error_builder ))
378
385
379
- def _throw_error_if_unaccounted_libs (unaccounted_for_libs ):
380
- if not unaccounted_for_libs :
381
- return
382
- libs_message = []
383
- different_repos = {}
384
- for unaccounted_lib in unaccounted_for_libs :
385
- different_repos [unaccounted_lib .workspace_name ] = True
386
- if len (libs_message ) < 10 :
387
- libs_message .append (str (unaccounted_lib ))
388
-
389
- if len (unaccounted_for_libs ) > 10 :
390
- libs_message .append ("(and " + str (len (unaccounted_for_libs ) - 10 ) + " others)\n " )
391
-
392
- static_deps_message = []
393
- for repo in different_repos :
394
- static_deps_message .append (" \" @" + repo + "//:__subpackages__\" ," )
395
-
396
- fail ("The following libraries cannot be linked either statically or dynamically:\n " +
397
- "\n " .join (libs_message ) + "\n To ignore which libraries get linked" +
398
- " statically for now, add the following to 'static_deps':\n " +
399
- "\n " .join (static_deps_message ))
400
-
401
386
def _same_package_or_above (label_a , label_b ):
402
387
if label_a .workspace_name != label_b .workspace_name :
403
388
return False
@@ -421,6 +406,14 @@ def _get_permissions(ctx):
421
406
def _cc_shared_library_impl (ctx ):
422
407
semantics .check_experimental_cc_shared_library (ctx )
423
408
409
+ if len (ctx .attr .static_deps ) and not cc_common .check_experimental_cc_shared_library ():
410
+ fail (
411
+ "This attribute is a no-op and its usage" +
412
+ " is forbidden after cc_shared_library is no longer experimental. " +
413
+ "Remove it from every cc_shared_library target" ,
414
+ attr = "static_deps" ,
415
+ )
416
+
424
417
cc_toolchain = cc_helper .find_cpp_toolchain (ctx )
425
418
feature_configuration = cc_common .configure_features (
426
419
ctx = ctx ,
@@ -460,7 +453,7 @@ def _cc_shared_library_impl(ctx):
460
453
461
454
link_once_static_libs_map = _build_link_once_static_libs_map (merged_cc_shared_library_info )
462
455
463
- (exports , linker_inputs , link_once_static_libs , precompiled_only_dynamic_libraries ) = _filter_inputs (
456
+ (exports , linker_inputs , curr_link_once_static_libs_set , precompiled_only_dynamic_libraries ) = _filter_inputs (
464
457
ctx ,
465
458
feature_configuration ,
466
459
cc_toolchain ,
@@ -544,8 +537,8 @@ def _cc_shared_library_impl(ctx):
544
537
for export in ctx .attr .roots :
545
538
export_label = str (export .label )
546
539
if GraphNodeInfo in export and export [GraphNodeInfo ].no_exporting :
547
- if export_label in link_once_static_libs :
548
- link_once_static_libs .remove (export_label )
540
+ if export_label in curr_link_once_static_libs_set :
541
+ curr_link_once_static_libs_set .remove (export_label )
549
542
continue
550
543
exports [export_label ] = True
551
544
@@ -554,13 +547,13 @@ def _cc_shared_library_impl(ctx):
554
547
ctx .actions .write (content = "\n " .join (["Owner:" + str (ctx .label )] + exports .keys ()), output = exports_debug_file )
555
548
556
549
link_once_static_libs_debug_file = ctx .actions .declare_file (ctx .label .name + "_link_once_static_libs.txt" )
557
- ctx .actions .write (content = "\n " .join (["Owner:" + str (ctx .label )] + link_once_static_libs ), output = link_once_static_libs_debug_file )
550
+ ctx .actions .write (content = "\n " .join (["Owner:" + str (ctx .label )] + curr_link_once_static_libs_set ), output = link_once_static_libs_debug_file )
558
551
559
552
debug_files .append (exports_debug_file )
560
553
debug_files .append (link_once_static_libs_debug_file )
561
554
562
555
if not ctx .fragments .cpp .experimental_link_static_libraries_once ():
563
- link_once_static_libs = []
556
+ curr_link_once_static_libs_set = {}
564
557
565
558
library = []
566
559
if linking_outputs .library_to_link .resolved_symlink_dynamic_library != None :
@@ -589,7 +582,7 @@ def _cc_shared_library_impl(ctx):
589
582
CcSharedLibraryInfo (
590
583
dynamic_deps = merged_cc_shared_library_info ,
591
584
exports = exports .keys (),
592
- link_once_static_libs = link_once_static_libs ,
585
+ link_once_static_libs = curr_link_once_static_libs_set ,
593
586
linker_input = cc_common .create_linker_input (
594
587
owner = ctx .label ,
595
588
libraries = depset ([linking_outputs .library_to_link ] + precompiled_only_dynamic_libraries ),
0 commit comments