Skip to content

Commit 9815b76

Browse files
oquenchilcopybara-github
authored andcommitted
Remove the static_deps attribute from cc_shared_library.
The idea behind this attribute was to force a user creating a shared library to account for every library that was linked statically into it, so that a new dependency further upstream wouldn't end up being linked without previous approval from the shared library owner. However, in the real world this attribute has turned out to be more of a pain than useful for users. Users will wildcard as much as possible using the @repo_name//:__subpackages__ syntax and will often get errors due to a new dependency from a different repository. At the same time, if any users (haven't seen any so far) have any interest in this restriction where an allowlist is required for libraries linked statically, then they can still do so by either writing a Starlark test which looks at the CcSharedLibraryInfo provider (which is public API) or they can write a test that reads the targets written to the debug *_link_once_static_libs.txt files. With this change the static_deps attribute will still be present but it will be a no-op as long as you are using the --experimental_cc_shared_library flag. Using the attribute will be an error without the experimental flag. In a follow up change we will not require the experimental flag to use the rule. Some time later the flag will be removed (therefore the static_deps attribute should be removed from targets). RELNOTES[inc]: cc_shared_library.static_deps attribute is removed PiperOrigin-RevId: 505107353 Change-Id: I438a1e47451ac53375dbe7940f238473807a0acc
1 parent 9234250 commit 9815b76

File tree

3 files changed

+63
-127
lines changed

3 files changed

+63
-127
lines changed

src/main/starlark/builtins_bzl/common/cc/experimental_cc_shared_library.bzl

+63-70
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,16 @@ CcSharedLibraryInfo = provider(
7373
},
7474
)
7575

76+
# For each target, find out whether it should be linked statically or
77+
# dynamically.
7678
def _separate_static_and_dynamic_link_libraries(
7779
direct_children,
7880
can_be_linked_dynamically,
7981
preloaded_deps_direct_labels):
8082
node = None
8183
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 = {}
8486

8587
seen_labels = {}
8688

@@ -97,12 +99,12 @@ def _separate_static_and_dynamic_link_libraries(
9799
seen_labels[node_label] = True
98100

99101
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
101103
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
103105
all_children.extend(node.children)
104106

105-
return (link_statically_labels, link_dynamically_labels)
107+
return (targets_to_be_linked_statically_map, targets_to_be_linked_dynamically_set)
106108

107109
def _create_linker_context(ctx, linker_inputs):
108110
return cc_common.create_linking_context(
@@ -142,6 +144,8 @@ def _build_exports_map_from_only_dynamic_deps(merged_shared_library_infos):
142144
exports_map[export] = linker_input
143145
return exports_map
144146

147+
# The map points from the target that can only be linked once to the
148+
# cc_shared_library target that already links it.
145149
def _build_link_once_static_libs_map(merged_shared_library_infos):
146150
link_once_static_libs_map = {}
147151
for entry in merged_shared_library_infos.to_list():
@@ -251,7 +255,7 @@ def _filter_inputs(
251255
preloaded_deps_direct_labels,
252256
link_once_static_libs_map):
253257
linker_inputs = []
254-
curr_link_once_static_libs_map = {}
258+
curr_link_once_static_libs_set = {}
255259

256260
graph_structure_aspect_nodes = []
257261
dependency_linker_inputs = []
@@ -267,16 +271,25 @@ def _filter_inputs(
267271
if owner in transitive_exports:
268272
can_be_linked_dynamically[owner] = True
269273

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(
271277
graph_structure_aspect_nodes,
272278
can_be_linked_dynamically,
273279
preloaded_deps_direct_labels,
274280
)
275281

282+
# We keep track of precompiled_only_dynamic_libraries, so that we can add
283+
# them to runfiles.
276284
precompiled_only_dynamic_libraries = []
277-
unaccounted_for_libs = []
278285
exports = {}
279286
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.
280293
dynamic_only_roots = {}
281294
linked_statically_but_not_exported = {}
282295
for linker_input in dependency_linker_inputs:
@@ -285,11 +298,21 @@ def _filter_inputs(
285298
continue
286299
linker_inputs_seen[stringified_linker_input] = True
287300
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:
292307
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
293316
linked_statically_but_not_exported.setdefault(link_once_static_libs_map[owner], []).append(owner)
294317

295318
is_direct_export = owner in direct_exports
@@ -311,41 +334,26 @@ def _filter_inputs(
311334
if len(static_libraries) and owner in dynamic_only_roots:
312335
dynamic_only_roots.pop(owner)
313336

337+
linker_input_to_be_linked_statically = linker_input
314338
if is_direct_export:
315-
wrapped_library = _wrap_static_library_with_alwayslink(
339+
linker_input_to_be_linked_statically = _wrap_static_library_with_alwayslink(
316340
ctx,
317341
feature_configuration,
318342
cc_toolchain,
319343
linker_input,
320344
)
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
321352

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
349357

350358
if dynamic_only_roots:
351359
message = ("Do not place libraries which only contain a " +
@@ -356,8 +364,7 @@ def _filter_inputs(
356364
fail(message)
357365

358366
_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)
361368

362369
def _throw_linked_but_not_exported_errors(error_libs_dict):
363370
if not error_libs_dict:
@@ -376,28 +383,6 @@ def _throw_linked_but_not_exported_errors(error_libs_dict):
376383

377384
fail("".join(error_builder))
378385

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) + "\nTo ignore which libraries get linked" +
398-
" statically for now, add the following to 'static_deps':\n" +
399-
"\n".join(static_deps_message))
400-
401386
def _same_package_or_above(label_a, label_b):
402387
if label_a.workspace_name != label_b.workspace_name:
403388
return False
@@ -421,6 +406,14 @@ def _get_permissions(ctx):
421406
def _cc_shared_library_impl(ctx):
422407
semantics.check_experimental_cc_shared_library(ctx)
423408

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+
424417
cc_toolchain = cc_helper.find_cpp_toolchain(ctx)
425418
feature_configuration = cc_common.configure_features(
426419
ctx = ctx,
@@ -460,7 +453,7 @@ def _cc_shared_library_impl(ctx):
460453

461454
link_once_static_libs_map = _build_link_once_static_libs_map(merged_cc_shared_library_info)
462455

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(
464457
ctx,
465458
feature_configuration,
466459
cc_toolchain,
@@ -544,8 +537,8 @@ def _cc_shared_library_impl(ctx):
544537
for export in ctx.attr.roots:
545538
export_label = str(export.label)
546539
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)
549542
continue
550543
exports[export_label] = True
551544

@@ -554,13 +547,13 @@ def _cc_shared_library_impl(ctx):
554547
ctx.actions.write(content = "\n".join(["Owner:" + str(ctx.label)] + exports.keys()), output = exports_debug_file)
555548

556549
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)
558551

559552
debug_files.append(exports_debug_file)
560553
debug_files.append(link_once_static_libs_debug_file)
561554

562555
if not ctx.fragments.cpp.experimental_link_static_libraries_once():
563-
link_once_static_libs = []
556+
curr_link_once_static_libs_set = {}
564557

565558
library = []
566559
if linking_outputs.library_to_link.resolved_symlink_dynamic_library != None:
@@ -589,7 +582,7 @@ def _cc_shared_library_impl(ctx):
589582
CcSharedLibraryInfo(
590583
dynamic_deps = merged_cc_shared_library_info,
591584
exports = exports.keys(),
592-
link_once_static_libs = link_once_static_libs,
585+
link_once_static_libs = curr_link_once_static_libs_set,
593586
linker_input = cc_common.create_linker_input(
594587
owner = ctx.label,
595588
libraries = depset([linking_outputs.library_to_link] + precompiled_only_dynamic_libraries),

src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library/BUILD.builtin_test

-24
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ cc_shared_library(
106106
"foo",
107107
"a_suffix",
108108
],
109-
static_deps = [
110-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:qux",
111-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:qux2",
112-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:prebuilt",
113-
],
114109
user_link_flags = select({
115110
"//src/conditions:linux": [
116111
"-Wl,-rpath,kittens",
@@ -207,11 +202,6 @@ cc_shared_library(
207202
":is_bazel": ["@test_repo//:bar"],
208203
"//conditions:default": [],
209204
}),
210-
static_deps = [
211-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:barX",
212-
"@test_repo//:bar",
213-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:qux2",
214-
],
215205
user_link_flags = select({
216206
"//src/conditions:linux": [
217207
"-Wl,--version-script=$(location :bar.lds)",
@@ -488,20 +478,6 @@ runfiles_test(
488478
target_under_test = ":python_test",
489479
)
490480

491-
build_failure_test(
492-
name = "static_deps_error_test",
493-
messages = select({
494-
":is_bazel": [
495-
"@//:__subpackages__",
496-
"@test_repo//:__subpackages__",
497-
],
498-
"//conditions:default": [
499-
"@//:__subpackages__",
500-
],
501-
}),
502-
target_under_test = "//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library/failing_targets:unaccounted_for_libs_so",
503-
)
504-
505481
no_exporting_static_lib_test(
506482
name = "no_exporting_static_lib_test",
507483
target_under_test = ":lib_with_no_exporting_roots",

src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library/failing_targets/BUILD.builtin_test

-33
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ cc_shared_library(
2222
roots = [
2323
":intermediate",
2424
],
25-
static_deps = [
26-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:barX",
27-
],
2825
tags = TAGS,
2926
)
3027

@@ -103,33 +100,3 @@ cc_shared_library(
103100
],
104101
tags = TAGS,
105102
)
106-
107-
cc_shared_library(
108-
name = "unaccounted_for_libs_so",
109-
roots = [
110-
":d1",
111-
],
112-
tags = TAGS,
113-
)
114-
115-
cc_library(
116-
name = "d1",
117-
srcs = ["empty.cc"],
118-
deps = ["d2"],
119-
)
120-
121-
cc_library(
122-
name = "d2",
123-
srcs = ["empty.cc"],
124-
deps = [
125-
"d3",
126-
] + select({
127-
"//src/main/starlark/tests/builtins_bzl/cc/cc_shared_library/test_cc_shared_library:is_bazel": ["@test_repo//:bar"],
128-
"//conditions:default": [],
129-
}),
130-
)
131-
132-
cc_library(
133-
name = "d3",
134-
srcs = ["empty.cc"],
135-
)

0 commit comments

Comments
 (0)