Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update rules for ObjcProvider deprecations #850

Merged
merged 5 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 106 additions & 18 deletions rules/force_load_direct_deps.bzl
Original file line number Diff line number Diff line change
@@ -1,36 +1,116 @@
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
load("//rules:providers.bzl", "AvoidDepsInfo")
load("//rules:transition_support.bzl", "transition_support")

def _impl(ctx):
if not ctx.attr.should_force_load:
return apple_common.new_objc_provider()
def _objc_provider_static_libraries(dep):
"""Returns the ObjcProvider static libraries (.a) that should be force loaded.
"""
if not apple_common.Objc in dep:
return []

return dep[apple_common.Objc].library.to_list()

def _cc_info_static_libraries(dep):
"""Returns the CcInfo static libraries (.a) that should be force loaded.
NOTE: CcInfo, unlike ObjcProvider, does not encode where the static library came from.
In the existing `_objc_provider_static_libraries` we only collect `.library` from ObjcProvider.
ObjcProvider `.library` list static library dependencies of the current target,
it does not include imported static libraries (such as those from `.framework` files).
CcInfo only provides `.static_library` and does not make this distinction.
To match this behavior, we only collect `.static_library` from CcInfo that are not from `.framework`s.
"""
if not CcInfo in dep:
return []

static_cc_libraries = []
for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list():
for library_to_link in linker_input.libraries:
if not library_to_link.static_library:
continue
containing_path = paths.dirname(library_to_link.static_library.path)
if containing_path.endswith(".framework"):
continue
jszumski marked this conversation as resolved.
Show resolved Hide resolved
static_cc_libraries.append(library_to_link.static_library)

force_load = []
return static_cc_libraries

# TODO: We should deprecate this rule for Bazel 7+ as `--incompatible_objc_alwayslink_by_default` effectively
jszumski marked this conversation as resolved.
Show resolved Hide resolved
# does the same thing.
def _force_load_direct_deps_impl(ctx):
"""This rule will traverse the direct deps of the target and force load the static libraries of the objc deps.
"""

if not ctx.attr.should_force_load:
return [
apple_common.new_objc_provider(),
CcInfo(),
]

force_load_libraries = []
force_load_cc_libraries = []
avoid_deps = []
avoid_libraries = {}
avoid_cc_libraries = {}
cc_toolchain = find_cpp_toolchain(ctx)
cc_features = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
language = "objc",
)

# Set the deps that should be avoided and not linked.
for dep in ctx.attr.deps:
if AvoidDepsInfo in dep:
avoid_deps.extend(dep[AvoidDepsInfo].libraries)

avoid_libraries = {}
# Collect the libraries that should be avoided.
for dep in avoid_deps:
if apple_common.Objc in dep:
for lib in dep[apple_common.Objc].library.to_list():
avoid_libraries[lib] = True
for lib in _objc_provider_static_libraries(dep):
avoid_libraries[lib] = True
for lib in _cc_info_static_libraries(dep):
avoid_cc_libraries[lib] = True

force_load = []
# Collect the libraries that should be force loaded.
for dep in ctx.attr.deps:
if apple_common.Objc in dep:
for lib in dep[apple_common.Objc].library.to_list():
if not lib in avoid_libraries:
force_load.append(lib)
return apple_common.new_objc_provider(
force_load_library = depset(force_load),
link_inputs = depset(force_load),
)
for lib in _objc_provider_static_libraries(dep):
if not lib in avoid_libraries:
force_load_libraries.append(lib)
for lib in _cc_info_static_libraries(dep):
if not lib in avoid_cc_libraries:
force_load_cc_libraries.append(lib)

return [
apple_common.new_objc_provider(
force_load_library = depset(force_load_libraries),
link_inputs = depset(force_load_libraries),
),
CcInfo(
linking_context = cc_common.create_linking_context(
linker_inputs = depset([
cc_common.create_linker_input(
owner = ctx.label,
libraries = depset([
cc_common.create_library_to_link(
actions = ctx.actions,
cc_toolchain = cc_toolchain,
feature_configuration = cc_features,
static_library = library,
alwayslink = True,
)
for library in force_load_cc_libraries
]),
),
]),
),
),
]

force_load_direct_deps = rule(
implementation = _impl,
implementation = _force_load_direct_deps_impl,
toolchains = use_cpp_toolchain(),
fragments = ["apple", "cpp", "objc"],
attrs = {
"deps": attr.label_list(
cfg = transition_support.apple_platform_split_transition,
Expand Down Expand Up @@ -58,6 +138,14 @@ force_load_direct_deps = rule(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
doc = "Needed to allow this rule to have an incoming edge configuration transition.",
),
"_cc_toolchain": attr.label(
providers = [cc_common.CcToolchainInfo],
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
doc = """\
The C++ toolchain from which linking flags and other tools needed by the Swift
toolchain (such as `clang`) will be retrieved.
""",
),
},
doc = """
A rule to link with `-force_load` for direct`deps`
Expand Down
32 changes: 27 additions & 5 deletions rules/framework.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ load("//rules:library.bzl", "PrivateHeadersInfo", "apple_library")
load("//rules:plists.bzl", "process_infoplists")
load("//rules:providers.bzl", "AvoidDepsInfo", "FrameworkInfo")
load("//rules:transition_support.bzl", "transition_support")
load("//rules:utils.bzl", "is_bazel_7")
load("//rules/internal:objc_provider_utils.bzl", "objc_provider_utils")
load("@bazel_skylib//lib:partial.bzl", "partial")
load("@bazel_skylib//lib:paths.bzl", "paths")
Expand Down Expand Up @@ -534,6 +535,18 @@ def _get_symlinked_framework_clean_action(ctx, framework_files, compilation_cont
else:
ctx.actions.write(framework_manifest, "# Empty framework\n")

def _get_cc_info_linker_inputs(*, deps):
linker_inputs = []

for dep in deps:
if not CcInfo in dep:
continue

for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list():
linker_inputs.append(linker_input)

return depset(linker_inputs)

def _create_swiftmodule(attrs):
kwargs = {}

Expand Down Expand Up @@ -986,7 +999,9 @@ def _apple_framework_packaging_impl(ctx):

split_slice_key = "{}_{}{}".format(platform, split_slice_varint, arch)
deps = _attrs_for_split_slice(ctx.split_attr.deps, split_slice_key)
dep_cc_infos = [dep[CcInfo] for dep in deps if CcInfo in dep]
transitive_deps = _attrs_for_split_slice(ctx.split_attr.transitive_deps, split_slice_key)
transitive_dep_cc_infos = [dep[CcInfo] for dep in transitive_deps if CcInfo in dep]
vfs = _attrs_for_split_slice(ctx.split_attr.vfs, split_slice_key)

current_apple_platform = transition_support.current_apple_platform(apple_fragment = ctx.fragments.apple, xcode_config = ctx.attr._xcode_config)
Expand All @@ -1004,15 +1019,15 @@ def _apple_framework_packaging_impl(ctx):
))
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "defines", depset(
direct = [],
transitive = [getattr(dep[CcInfo].compilation_context, "defines") for dep in deps if CcInfo in dep],
transitive = [getattr(cc_info.compilation_context, "defines") for cc_info in dep_cc_infos],
))
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "includes", depset(
direct = [],
transitive = [getattr(dep[CcInfo].compilation_context, "includes") for dep in deps if CcInfo in dep],
transitive = [getattr(cc_info.compilation_context, "includes") for cc_info in dep_cc_infos],
))
objc_provider_utils.add_to_dict_if_present(compilation_context_fields, "framework_includes", depset(
direct = [],
transitive = [getattr(dep[CcInfo].compilation_context, "framework_includes") for dep in deps if CcInfo in dep],
transitive = [getattr(cc_info.compilation_context, "framework_includes") for cc_info in dep_cc_infos],
))

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

# Construct the `CcInfo` provider, the linking context here used instead of ObjcProvider in Bazel 7+.
cc_info_provider = CcInfo(
compilation_context = cc_common.create_compilation_context(
**compilation_context_fields
),
linking_context = cc_common.create_linking_context(
linker_inputs = _get_cc_info_linker_inputs(deps = deps) if is_bazel_7 else depset([]),
),
)

if virtualize_frameworks:
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [cc_info_provider])
else:
dep_cc_infos = [dep[CcInfo] for dep in transitive_deps if CcInfo in dep]
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [cc_info_provider], cc_infos = dep_cc_infos)
cc_info = cc_common.merge_cc_infos(
direct_cc_infos = [cc_info_provider],
cc_infos = transitive_dep_cc_infos,
)

# Propagate the avoid deps information upwards
avoid_deps = []
Expand Down Expand Up @@ -1072,6 +1093,7 @@ def _apple_framework_packaging_impl(ctx):
providers = [dep[apple_common.Objc] for dep in deps if apple_common.Objc in dep],
transitive = [dep[apple_common.Objc] for dep in transitive_deps if apple_common.Objc in dep],
)

return [
avoid_deps_info,
framework_info,
Expand Down
18 changes: 6 additions & 12 deletions rules/import_middleman.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
load("@build_bazel_rules_apple//apple/internal:providers.bzl", "AppleFrameworkImportInfo", "new_appleframeworkimportinfo")
load("//rules:features.bzl", "feature_names")
load("//rules/internal:objc_provider_utils.bzl", "objc_provider_utils")
load("@build_bazel_rules_apple//apple/internal:bundling_support.bzl", "bundling_support")

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

virtualize_frameworks = feature_names.virtualize_frameworks in ctx.features
merge_keys = [
"sdk_dylib",
"sdk_framework",
Expand All @@ -184,17 +182,13 @@ def _file_collector_rule_impl(ctx):
"link_inputs",
"linkopt",
"library",
] + ([] if is_sim_arm64 else [
# Merge in the objc provider fields
"imported_library",
"dynamic_framework_file",
"static_framework_file",
])
]

objc_provider_fields = objc_provider_utils.merge_objc_providers_dict(
providers = [dep[apple_common.Objc] for dep in ctx.attr.deps],
merge_keys = merge_keys,
)

exisiting_imported_libraries = objc_provider_fields.get("imported_library", depset([]))
replaced_imported_libraries = _replace_inputs(ctx, exisiting_imported_libraries, input_imported_libraries, _update_lib).inputs
objc_provider_fields["imported_library"] = depset(_deduplicate_test_deps(test_linker_deps[1], replaced_imported_libraries))
Expand Down Expand Up @@ -260,15 +254,15 @@ def _file_collector_rule_impl(ctx):
**objc_provider_fields
)

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

return [
DefaultInfo(files = depset(dynamic_framework_dirs + replaced_frameworks)),
objc,
] + _make_imports(dynamic_framework_dirs) + additional_providers
cc_info,
] + _make_imports(dynamic_framework_dirs)

import_middleman = rule(
implementation = _file_collector_rule_impl,
Expand Down
Loading