Skip to content

Commit 795191e

Browse files
authored
Update rules for ObjcProvider deprecations (#850)
In Bazel 7+ `ObjcProvider` no longer supports/provides the required linking attributes. The migrations is detailed here: bazelbuild/bazel#16939. In summary, as part of the migration, the `ObjcProvider` fields which previously provided linking related information are now now longer providing that info. In addition to this, a new flag: `--incompatible_objc_linking_info_migration` was added to further delete these link attrs from the `ObjcProvider` making it an error if the attr is used or set. The goal of this PR is to address support for `ObjcProvider` migration and to instead use the correct linking information from `CcInfo`. This will support both Bazel 6/7+. It does not try to support `--incompatible_objc_linking_info_migration` as that requires more changes and should be a separate PR Depends on: - #848 - #847
1 parent 76c35f8 commit 795191e

File tree

9 files changed

+203
-49
lines changed

9 files changed

+203
-49
lines changed

rules/force_load_direct_deps.bzl

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,116 @@
1+
load("@bazel_skylib//lib:paths.bzl", "paths")
2+
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
13
load("//rules:providers.bzl", "AvoidDepsInfo")
24
load("//rules:transition_support.bzl", "transition_support")
35

4-
def _impl(ctx):
5-
if not ctx.attr.should_force_load:
6-
return apple_common.new_objc_provider()
6+
def _objc_provider_static_libraries(dep):
7+
"""Returns the ObjcProvider static libraries (.a) that should be force loaded.
8+
"""
9+
if not apple_common.Objc in dep:
10+
return []
11+
12+
return dep[apple_common.Objc].library.to_list()
13+
14+
def _cc_info_static_libraries(dep):
15+
"""Returns the CcInfo static libraries (.a) that should be force loaded.
16+
17+
NOTE: CcInfo, unlike ObjcProvider, does not encode where the static library came from.
18+
In the existing `_objc_provider_static_libraries` we only collect `.library` from ObjcProvider.
19+
ObjcProvider `.library` list static library dependencies of the current target,
20+
it does not include imported static libraries (such as those from `.framework` files).
21+
CcInfo only provides `.static_library` and does not make this distinction.
22+
To match this behavior, we only collect `.static_library` from CcInfo that are not from `.framework`s.
23+
"""
24+
if not CcInfo in dep:
25+
return []
26+
27+
static_cc_libraries = []
28+
for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list():
29+
for library_to_link in linker_input.libraries:
30+
if not library_to_link.static_library:
31+
continue
32+
containing_path = paths.dirname(library_to_link.static_library.path)
33+
if containing_path.endswith(".framework"):
34+
continue
35+
static_cc_libraries.append(library_to_link.static_library)
736

8-
force_load = []
37+
return static_cc_libraries
938

39+
# TODO: We should deprecate this rule for Bazel 7+ as `--incompatible_objc_alwayslink_by_default` effectively
40+
# does the same thing.
41+
def _force_load_direct_deps_impl(ctx):
42+
"""This rule will traverse the direct deps of the target and force load the static libraries of the objc deps.
43+
"""
44+
45+
if not ctx.attr.should_force_load:
46+
return [
47+
apple_common.new_objc_provider(),
48+
CcInfo(),
49+
]
50+
51+
force_load_libraries = []
52+
force_load_cc_libraries = []
1053
avoid_deps = []
54+
avoid_libraries = {}
55+
avoid_cc_libraries = {}
56+
cc_toolchain = find_cpp_toolchain(ctx)
57+
cc_features = cc_common.configure_features(
58+
ctx = ctx,
59+
cc_toolchain = cc_toolchain,
60+
language = "objc",
61+
)
62+
63+
# Set the deps that should be avoided and not linked.
1164
for dep in ctx.attr.deps:
1265
if AvoidDepsInfo in dep:
1366
avoid_deps.extend(dep[AvoidDepsInfo].libraries)
1467

15-
avoid_libraries = {}
68+
# Collect the libraries that should be avoided.
1669
for dep in avoid_deps:
17-
if apple_common.Objc in dep:
18-
for lib in dep[apple_common.Objc].library.to_list():
19-
avoid_libraries[lib] = True
70+
for lib in _objc_provider_static_libraries(dep):
71+
avoid_libraries[lib] = True
72+
for lib in _cc_info_static_libraries(dep):
73+
avoid_cc_libraries[lib] = True
2074

21-
force_load = []
75+
# Collect the libraries that should be force loaded.
2276
for dep in ctx.attr.deps:
23-
if apple_common.Objc in dep:
24-
for lib in dep[apple_common.Objc].library.to_list():
25-
if not lib in avoid_libraries:
26-
force_load.append(lib)
27-
return apple_common.new_objc_provider(
28-
force_load_library = depset(force_load),
29-
link_inputs = depset(force_load),
30-
)
77+
for lib in _objc_provider_static_libraries(dep):
78+
if not lib in avoid_libraries:
79+
force_load_libraries.append(lib)
80+
for lib in _cc_info_static_libraries(dep):
81+
if not lib in avoid_cc_libraries:
82+
force_load_cc_libraries.append(lib)
83+
84+
return [
85+
apple_common.new_objc_provider(
86+
force_load_library = depset(force_load_libraries),
87+
link_inputs = depset(force_load_libraries),
88+
),
89+
CcInfo(
90+
linking_context = cc_common.create_linking_context(
91+
linker_inputs = depset([
92+
cc_common.create_linker_input(
93+
owner = ctx.label,
94+
libraries = depset([
95+
cc_common.create_library_to_link(
96+
actions = ctx.actions,
97+
cc_toolchain = cc_toolchain,
98+
feature_configuration = cc_features,
99+
static_library = library,
100+
alwayslink = True,
101+
)
102+
for library in force_load_cc_libraries
103+
]),
104+
),
105+
]),
106+
),
107+
),
108+
]
31109

32110
force_load_direct_deps = rule(
33-
implementation = _impl,
111+
implementation = _force_load_direct_deps_impl,
112+
toolchains = use_cpp_toolchain(),
113+
fragments = ["apple", "cpp", "objc"],
34114
attrs = {
35115
"deps": attr.label_list(
36116
cfg = transition_support.apple_platform_split_transition,
@@ -58,6 +138,14 @@ force_load_direct_deps = rule(
58138
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
59139
doc = "Needed to allow this rule to have an incoming edge configuration transition.",
60140
),
141+
"_cc_toolchain": attr.label(
142+
providers = [cc_common.CcToolchainInfo],
143+
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
144+
doc = """\
145+
The C++ toolchain from which linking flags and other tools needed by the Swift
146+
toolchain (such as `clang`) will be retrieved.
147+
""",
148+
),
61149
},
62150
doc = """
63151
A rule to link with `-force_load` for direct`deps`

rules/framework.bzl

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ load("//rules:library.bzl", "PrivateHeadersInfo", "apple_library")
66
load("//rules:plists.bzl", "process_infoplists")
77
load("//rules:providers.bzl", "AvoidDepsInfo", "FrameworkInfo")
88
load("//rules:transition_support.bzl", "transition_support")
9+
load("//rules:utils.bzl", "is_bazel_7")
910
load("//rules/internal:objc_provider_utils.bzl", "objc_provider_utils")
1011
load("@bazel_skylib//lib:partial.bzl", "partial")
1112
load("@bazel_skylib//lib:paths.bzl", "paths")
@@ -534,6 +535,18 @@ def _get_symlinked_framework_clean_action(ctx, framework_files, compilation_cont
534535
else:
535536
ctx.actions.write(framework_manifest, "# Empty framework\n")
536537

538+
def _get_cc_info_linker_inputs(*, deps):
539+
linker_inputs = []
540+
541+
for dep in deps:
542+
if not CcInfo in dep:
543+
continue
544+
545+
for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list():
546+
linker_inputs.append(linker_input)
547+
548+
return depset(linker_inputs)
549+
537550
def _create_swiftmodule(attrs):
538551
kwargs = {}
539552

@@ -986,7 +999,9 @@ def _apple_framework_packaging_impl(ctx):
986999

9871000
split_slice_key = "{}_{}{}".format(platform, split_slice_varint, arch)
9881001
deps = _attrs_for_split_slice(ctx.split_attr.deps, split_slice_key)
1002+
dep_cc_infos = [dep[CcInfo] for dep in deps if CcInfo in dep]
9891003
transitive_deps = _attrs_for_split_slice(ctx.split_attr.transitive_deps, split_slice_key)
1004+
transitive_dep_cc_infos = [dep[CcInfo] for dep in transitive_deps if CcInfo in dep]
9901005
vfs = _attrs_for_split_slice(ctx.split_attr.vfs, split_slice_key)
9911006

9921007
current_apple_platform = transition_support.current_apple_platform(apple_fragment = ctx.fragments.apple, xcode_config = ctx.attr._xcode_config)
@@ -1004,15 +1019,15 @@ def _apple_framework_packaging_impl(ctx):
10041019
))
10051020
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "defines", depset(
10061021
direct = [],
1007-
transitive = [getattr(dep[CcInfo].compilation_context, "defines") for dep in deps if CcInfo in dep],
1022+
transitive = [getattr(cc_info.compilation_context, "defines") for cc_info in dep_cc_infos],
10081023
))
10091024
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "includes", depset(
10101025
direct = [],
1011-
transitive = [getattr(dep[CcInfo].compilation_context, "includes") for dep in deps if CcInfo in dep],
1026+
transitive = [getattr(cc_info.compilation_context, "includes") for cc_info in dep_cc_infos],
10121027
))
10131028
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "framework_includes", depset(
10141029
direct = [],
1015-
transitive = [getattr(dep[CcInfo].compilation_context, "framework_includes") for dep in deps if CcInfo in dep],
1030+
transitive = [getattr(cc_info.compilation_context, "framework_includes") for cc_info in dep_cc_infos],
10161031
))
10171032

10181033
# Compute cc_info and swift_info
@@ -1031,17 +1046,23 @@ def _apple_framework_packaging_impl(ctx):
10311046
# If not virtualizing the framework - then it runs a "clean"
10321047
_get_symlinked_framework_clean_action(ctx, framework_files, compilation_context_fields)
10331048

1049+
# Construct the `CcInfo` provider, the linking context here used instead of ObjcProvider in Bazel 7+.
10341050
cc_info_provider = CcInfo(
10351051
compilation_context = cc_common.create_compilation_context(
10361052
**compilation_context_fields
10371053
),
1054+
linking_context = cc_common.create_linking_context(
1055+
linker_inputs = _get_cc_info_linker_inputs(deps = deps) if is_bazel_7 else depset([]),
1056+
),
10381057
)
10391058

10401059
if virtualize_frameworks:
10411060
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [cc_info_provider])
10421061
else:
1043-
dep_cc_infos = [dep[CcInfo] for dep in transitive_deps if CcInfo in dep]
1044-
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [cc_info_provider], cc_infos = dep_cc_infos)
1062+
cc_info = cc_common.merge_cc_infos(
1063+
direct_cc_infos = [cc_info_provider],
1064+
cc_infos = transitive_dep_cc_infos,
1065+
)
10451066

10461067
# Propagate the avoid deps information upwards
10471068
avoid_deps = []
@@ -1072,6 +1093,7 @@ def _apple_framework_packaging_impl(ctx):
10721093
providers = [dep[apple_common.Objc] for dep in deps if apple_common.Objc in dep],
10731094
transitive = [dep[apple_common.Objc] for dep in transitive_deps if apple_common.Objc in dep],
10741095
)
1096+
10751097
return [
10761098
avoid_deps_info,
10771099
framework_info,

rules/import_middleman.bzl

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
load("@build_bazel_rules_apple//apple/internal:providers.bzl", "AppleFrameworkImportInfo", "new_appleframeworkimportinfo")
2-
load("//rules:features.bzl", "feature_names")
32
load("//rules/internal:objc_provider_utils.bzl", "objc_provider_utils")
43
load("@build_bazel_rules_apple//apple/internal:bundling_support.bzl", "bundling_support")
54

@@ -174,7 +173,6 @@ def _file_collector_rule_impl(ctx):
174173
# This should be correctly configured upstream: see setup in rules_ios
175174
fail("using import_middleman ({}) on wrong transition ({},{},is_device={})".format(ctx.attr.name, platform, arch, ctx.fragments.apple.single_arch_platform.is_device))
176175

177-
virtualize_frameworks = feature_names.virtualize_frameworks in ctx.features
178176
merge_keys = [
179177
"sdk_dylib",
180178
"sdk_framework",
@@ -184,17 +182,13 @@ def _file_collector_rule_impl(ctx):
184182
"link_inputs",
185183
"linkopt",
186184
"library",
187-
] + ([] if is_sim_arm64 else [
188-
# Merge in the objc provider fields
189-
"imported_library",
190-
"dynamic_framework_file",
191-
"static_framework_file",
192-
])
185+
]
193186

194187
objc_provider_fields = objc_provider_utils.merge_objc_providers_dict(
195188
providers = [dep[apple_common.Objc] for dep in ctx.attr.deps],
196189
merge_keys = merge_keys,
197190
)
191+
198192
exisiting_imported_libraries = objc_provider_fields.get("imported_library", depset([]))
199193
replaced_imported_libraries = _replace_inputs(ctx, exisiting_imported_libraries, input_imported_libraries, _update_lib).inputs
200194
objc_provider_fields["imported_library"] = depset(_deduplicate_test_deps(test_linker_deps[1], replaced_imported_libraries))
@@ -260,15 +254,15 @@ def _file_collector_rule_impl(ctx):
260254
**objc_provider_fields
261255
)
262256

263-
additional_providers = []
257+
# Create the CcInfo provider, linking information from this is used in Bazel 7+.
264258
dep_cc_infos = [dep[CcInfo] for dep in ctx.attr.deps if CcInfo in dep]
265-
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [], cc_infos = dep_cc_infos)
266-
additional_providers.append(cc_info)
259+
cc_info = cc_common.merge_cc_infos(cc_infos = dep_cc_infos)
267260

268261
return [
269262
DefaultInfo(files = depset(dynamic_framework_dirs + replaced_frameworks)),
270263
objc,
271-
] + _make_imports(dynamic_framework_dirs) + additional_providers
264+
cc_info,
265+
] + _make_imports(dynamic_framework_dirs)
272266

273267
import_middleman = rule(
274268
implementation = _file_collector_rule_impl,

0 commit comments

Comments
 (0)