Skip to content

Commit

Permalink
Add support to import macOS versioned frameworks. (#2133)
Browse files Browse the repository at this point in the history
This change adds support to import macOS versioned frameworks
for both framework and XCFramework importing rules:

  - apple_dynamic_framework_import
  - apple_dynamic_xcframework_import

This change fixes an issue with imported macOS frameworks causing build
failures at the signing step for `macos_application` targets due to an
incorrect framework bundle format since Bazel will resolve symlinks for
versioned frameworks (standalone or bundled inside an XCFramework).

`codesign` will fail with the following error:

  "bundle format is ambiguous (could be app or framework)"

Since macOS frameworks include different framework versions under a
`Versions` directory and symlinks for the effective version this change
updates imported_dynamic_framework_processor to handle re-do symbolic
links from imported macOS frameworks, as well code signing each
framework version per Apple documentation.

Support to bundle macOS versioned frameworks with tree artifact outputs
is not supported because Bazel does not re-create symbolic links from
remote executed actions yet
(bazelbuild/bazel#16361).

PiperOrigin-RevId: 503486495
(cherry picked from commit a82a299)

Co-authored-by: Mauricio Garcia <[email protected]>
  • Loading branch information
keith and stravinskii authored Aug 18, 2023
1 parent 4389a5f commit 93d5b18
Show file tree
Hide file tree
Showing 14 changed files with 477 additions and 93 deletions.
23 changes: 20 additions & 3 deletions apple/internal/apple_framework_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ load(
"@build_bazel_rules_apple//apple/internal/providers:framework_import_bundle_info.bzl",
"AppleFrameworkImportBundleInfo",
)
load(
"@build_bazel_rules_apple//apple/internal:apple_toolchains.bzl",
"AppleXPlatToolsToolchainInfo",
)
load(
"@build_bazel_rules_apple//apple/internal:cc_toolchain_info_support.bzl",
"cc_toolchain_info_support",
Expand All @@ -46,6 +50,10 @@ load(
"@build_bazel_rules_apple//apple/internal/utils:bundle_paths.bzl",
"bundle_paths",
)
load(
"@build_bazel_rules_apple//apple/internal:experimental.bzl",
"is_experimental_tree_artifact_enabled",
)
load(
"@build_bazel_rules_apple//apple/internal/aspects:swift_usage_aspect.bzl",
"SwiftUsageInfo",
Expand Down Expand Up @@ -197,6 +205,7 @@ def _debug_info_binaries(
def _apple_dynamic_framework_import_impl(ctx):
"""Implementation for the apple_dynamic_framework_import rule."""
actions = ctx.actions
apple_xplat_toolchain_info = ctx.attr._xplat_toolchain[AppleXPlatToolsToolchainInfo]
cc_toolchain = find_cpp_toolchain(ctx)
deps = ctx.attr.deps
disabled_features = ctx.disabled_features
Expand All @@ -207,13 +216,21 @@ def _apple_dynamic_framework_import_impl(ctx):
# TODO(b/207475773): Remove grep-includes once it's no longer required for cc_common APIs.
grep_includes = ctx.file._grep_includes

# TODO(b/258492867): Add tree artifacts support when Bazel can handle remote actions with
# symlinks. See https://github.com/bazelbuild/bazel/issues/16361.
target_triplet = cc_toolchain_info_support.get_apple_clang_triplet(cc_toolchain)
has_versioned_framework_files = framework_import_support.has_versioned_framework_files(
framework_imports,
)
if target_triplet.os == "macos" and has_versioned_framework_files:
# TODO(b/158696451): Add support to import macOS versioned frameworks.
fail("apple_dynamic_framework_import rule does not yet support macOS versioned frameworks.")
tree_artifact_enabled = (
apple_xplat_toolchain_info.build_settings.use_tree_artifacts_outputs or
is_experimental_tree_artifact_enabled(config_vars = ctx.var)
)
if target_triplet.os == "macos" and has_versioned_framework_files and tree_artifact_enabled:
fail("The apple_dynamic_framework_import rule does not yet support versioned " +
"frameworks with the experimental tree artifact feature/build setting. " +
"Please ensure that the `apple.experimental.tree_artifact_outputs` variable is not " +
"set to 1 on the command line or in your active build configuration.")

providers = []
framework = framework_import_support.classify_framework_imports(
Expand Down
18 changes: 15 additions & 3 deletions apple/internal/apple_xcframework_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ load(
"@build_bazel_rules_apple//apple/internal:cc_toolchain_info_support.bzl",
"cc_toolchain_info_support",
)
load(
"@build_bazel_rules_apple//apple/internal:experimental.bzl",
"is_experimental_tree_artifact_enabled",
)
load(
"@build_bazel_rules_apple//apple/internal:framework_import_support.bzl",
"framework_import_support",
Expand Down Expand Up @@ -446,13 +450,21 @@ def _apple_dynamic_xcframework_import_impl(ctx):
xcframework_imports = ctx.files.xcframework_imports
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]

# TODO(b/258492867): Add tree artifacts support when Bazel can handle remote actions with
# symlinks. See https://github.com/bazelbuild/bazel/issues/16361.
target_triplet = cc_toolchain_info_support.get_apple_clang_triplet(cc_toolchain)
has_versioned_framework_files = framework_import_support.has_versioned_framework_files(
xcframework_imports,
)
if target_triplet.os == "macos" and has_versioned_framework_files:
# TODO(b/158696451): Add support to import XCFrameworks with macOS versioned frameworks.
fail("apple_dynamic_xcframework_import rule does not yet support macOS versioned frameworks.")
tree_artifact_enabled = (
apple_xplat_toolchain_info.build_settings.use_tree_artifacts_outputs or
is_experimental_tree_artifact_enabled(config_vars = ctx.var)
)
if target_triplet.os == "macos" and has_versioned_framework_files and tree_artifact_enabled:
fail("The apple_dynamic_xcframework_import rule does not yet support versioned " +
"frameworks with the experimental tree artifact feature/build setting. " +
"Please ensure that the `apple.experimental.tree_artifact_outputs` variable is not " +
"set to 1 on the command line or in your active build configuration.")

xcframework = _classify_xcframework_imports(ctx.var, xcframework_imports)
if xcframework.bundle_type == _BUNDLE_TYPE.libraries:
Expand Down
64 changes: 52 additions & 12 deletions test/starlark_tests/apple_dynamic_xcframework_import_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
load(
"//test/starlark_tests/rules:analysis_failure_message_test.bzl",
"analysis_failure_message_test",
"analysis_failure_message_with_tree_artifact_outputs_test",
)
load(
"//test/starlark_tests/rules:analysis_target_actions_test.bzl",
Expand Down Expand Up @@ -333,12 +334,12 @@ def apple_dynamic_xcframework_import_test_suite(name):
archive_contents_test(
name = "{}_bundles_imported_macos_xcframework_to_application_x86_64_build".format(name),
build_type = "device",
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_xcframework.framework/generated_dynamic_macos_xcframework",
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "x86_64",
contains = [
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_xcframework.framework/Resources/Info.plist",
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_xcframework.framework/generated_dynamic_macos_xcframework",
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/Resources/Info.plist",
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
],
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
Expand All @@ -347,8 +348,8 @@ def apple_dynamic_xcframework_import_test_suite(name):
name = "{}_bundles_imported_macos_xcframework_to_application_arm64_build".format(name),
build_type = "device",
cpus = {"macos_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_xcframework.framework/generated_dynamic_macos_xcframework",
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "arm64",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
Expand All @@ -357,8 +358,8 @@ def apple_dynamic_xcframework_import_test_suite(name):
name = "{}_bundles_imported_macos_xcframework_to_application_arm64e_build".format(name),
build_type = "simulator",
cpus = {"macos_cpus": ["arm64e"]},
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_xcframework.framework/generated_dynamic_macos_xcframework",
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "arm64e",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
Expand All @@ -372,11 +373,50 @@ def apple_dynamic_xcframework_import_test_suite(name):
tags = [name],
)

# Verify importing XCFramework with versioned frameworks fails.
analysis_failure_message_test(
name = "{}_fails_with_versioned_frameworks_test".format(name),
# Verify macos_application links XCFramework versioned framework for device and simulator
# architectures.
archive_contents_test(
name = "{}_bundles_imported_macos_versioned_xcframework_to_application_x86_64_build".format(name),
build_type = "device",
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "x86_64",
contains = [
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/Resources/Info.plist",
"$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
],
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
)
archive_contents_test(
name = "{}_bundles_imported_macos_versioned_xcframework_to_application_arm64_build".format(name),
build_type = "device",
cpus = {"macos_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "arm64",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
)
archive_contents_test(
name = "{}_bundles_imported_macos_versioned_xcframework_to_application_arm64e_build".format(name),
build_type = "simulator",
cpus = {"macos_cpus": ["arm64e"]},
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
binary_test_file = "$CONTENT_ROOT/Frameworks/generated_dynamic_macos_versioned_xcframework.framework/generated_dynamic_macos_versioned_xcframework",
binary_test_architecture = "arm64e",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform MACOS"],
tags = [name],
)

# Verify importing XCFramework with versioned frameworks and tree artifacts fails.
analysis_failure_message_with_tree_artifact_outputs_test(
name = "{}_fails_with_versioned_frameworks_and_tree_artifact_outputs_test".format(name),
target_under_test = "//test/starlark_tests/targets_under_test/macos:app_with_imported_dynamic_versioned_xcframework",
expected_error = "apple_dynamic_xcframework_import rule does not yet support macOS versioned frameworks.",
expected_error = (
"The apple_dynamic_xcframework_import rule does not yet support versioned " +
"frameworks with the experimental tree artifact feature/build setting."
),
tags = [name],
)

Expand Down
12 changes: 1 addition & 11 deletions test/starlark_tests/apple_xcframework_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@ load(
":common.bzl",
"common",
)
load(
"//apple/build_settings:build_settings.bzl",
"build_settings_labels",
)
load(
"//test/starlark_tests/rules:analysis_failure_message_test.bzl",
"analysis_failure_message_test",
"make_analysis_failure_message_test",
"analysis_failure_message_with_tree_artifact_outputs_test",
)
load(
"//test/starlark_tests/rules:common_verification_tests.bzl",
Expand All @@ -44,12 +40,6 @@ load(
"linkmap_test",
)

analysis_failure_message_with_tree_artifact_outputs_test = make_analysis_failure_message_test(
config_settings = {
build_settings_labels._use_tree_artifacts_outputs_skylib_workaround: True,
},
)

def apple_xcframework_test_suite(name):
"""Test suite for apple_xcframework.
Expand Down
Loading

0 comments on commit 93d5b18

Please sign in to comment.