Skip to content

Commit

Permalink
Fix library identifier matching for XCFrameworks import rules
Browse files Browse the repository at this point in the history
Current logic for figuring out an XCFramework library identifier
from file paths fails to match correctly for arm64 device builds,
choosing a simulator library due to how an XCFramework library
identifier for a device build is a substring for a simulator build:

  - Device build: `ios-arm64`
  - Simulator build: `ios-arm64-simulator`

This change updates current logic to match a library identifier from
file paths using the effective target triplet, as well as matching
XCFramework files using that library identifier from file paths.

Additionally, it adds extra handling logic to avoid selecting an
`arm64e` or `arm64_32` library when targeting `arm64` due to
substring matching.

Based on PR #1579 by keith

PiperOrigin-RevId: 471303360
  • Loading branch information
stravinskii authored and swiple-rules-gardener committed Aug 31, 2022
1 parent 28e98d1 commit 717d4b4
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 8 deletions.
24 changes: 18 additions & 6 deletions apple/internal/apple_xcframework_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def _get_xcframework_library_from_paths(*, target_triplet, xcframework):
return None

def filter_by_library_identifier(files):
return [f for f in files if library_identifier in f.short_path]
return [f for f in files if "/{}/".format(library_identifier) in f.short_path]

files_by_category = xcframework.files_by_category
binaries = filter_by_library_identifier(files_by_category.binary_imports)
Expand Down Expand Up @@ -403,17 +403,29 @@ def _get_library_identifier(
fail("Unrecognized XCFramework bundle type: %s" % bundle_type)

for library_identifier in library_identifiers:
platform, _, architectures_environment = library_identifier.partition("-")
platform, _, suffix = library_identifier.partition("-")
architectures, _, environment = suffix.partition("-")

if platform != target_platform:
continue

if target_architecture not in architectures_environment:
if target_architecture not in architectures:
continue

if target_environment == "simulator" and not library_identifier.endswith("-simulator"):
continue
# Extra handling of path matching for arm64* architectures.
if target_architecture == "arm64":
arm64_index = architectures.find(target_architecture)
arm64e_index = architectures.find("arm64e")
arm64_32_index = architectures.find("arm64_32")

if arm64_index == arm64e_index or arm64_index == arm64_32_index:
continue

if target_environment == "device" and not environment:
return library_identifier

return library_identifier
if target_environment != "device" and target_environment == environment:
return library_identifier

return None

Expand Down
62 changes: 62 additions & 0 deletions test/starlark_tests/apple_dynamic_xcframework_import_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ def apple_dynamic_xcframework_import_test_suite(name):
binary_contains_file_info = ["Mach-O 64-bit dynamically linked shared library arm64"],
tags = [name],
)
binary_contents_test(
name = "{}_xcframework_binary_file_info_test_arm64_device".format(name),
build_type = "device",
cpus = {"ios_multi_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/Frameworks/generated_dynamic_xcframework_with_headers.framework/generated_dynamic_xcframework_with_headers",
binary_contains_file_info = ["Mach-O 64-bit dynamically linked shared library arm64"],
tags = [name],
)
binary_contents_test(
name = "{}_xcframework_binary_file_info_test_fat".format(name),
build_type = "simulator",
Expand Down Expand Up @@ -217,6 +226,59 @@ def apple_dynamic_xcframework_import_test_suite(name):
tags = [name],
)

# Verify ios_application links correct XCFramework library for arm64* architectures.
archive_contents_test(
name = "{}_links_ios_arm64_macho_load_cmd_for_simulator_test".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/Frameworks/generated_dynamic_xcframework_with_headers.framework/generated_dynamic_xcframework_with_headers",
binary_test_architecture = "arm64",
cpus = {"ios_multi_cpus": ["sim_arm64"]},
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOSSIMULATOR"],
tags = [name],
)
archive_contents_test(
name = "{}_links_ios_arm64_macho_load_cmd_for_device_test".format(name),
build_type = "device",
cpus = {"ios_multi_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/Frameworks/generated_dynamic_xcframework_with_headers.framework/generated_dynamic_xcframework_with_headers",
binary_test_architecture = "arm64",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOS"],
tags = [name],
)
archive_contents_test(
name = "{}_links_ios_arm64e_macho_load_cmd_for_device_test".format(name),
build_type = "device",
cpus = {"ios_multi_cpus": ["arm64e"]},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/Frameworks/generated_dynamic_xcframework_with_headers.framework/generated_dynamic_xcframework_with_headers",
binary_test_architecture = "arm64e",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOS"],
tags = [name],
)

# Verify watchos_application links correct XCFramework library for arm64* architectures.
archive_contents_test(
name = "{}_links_watchos_arm64_macho_load_cmd_for_simulator_test".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/PlugIns/ext_with_imported_xcframework.appex/Frameworks/generated_dynamic_watchos_xcframework.framework/generated_dynamic_watchos_xcframework",
binary_test_architecture = "arm64",
cpus = {"watchos_cpus": ["arm64"]},
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform WATCHOSSIMULATOR"],
tags = [name],
)
archive_contents_test(
name = "{}_links_watchos_arm64_32_macho_load_cmd_for_device_test".format(name),
build_type = "device",
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_with_imported_xcframework",
binary_test_file = "$BUNDLE_ROOT/PlugIns/ext_with_imported_xcframework.appex/Frameworks/generated_dynamic_watchos_xcframework.framework/generated_dynamic_watchos_xcframework",
binary_test_architecture = "arm64_32",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform WATCHOS"],
tags = [name],
)

# Verify importing XCFramework with dynamic libraries (i.e. not Apple frameworks) fails.
analysis_failure_message_test(
name = "{}_fails_importing_xcframework_with_libraries_test".format(name),
Expand Down
63 changes: 63 additions & 0 deletions test/starlark_tests/apple_static_xcframework_import_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,69 @@ def apple_static_xcframework_import_test_suite(name):
tags = [name],
)

# Verify ios_application links correct XCFramework library between simulator and device builds.
archive_contents_test(
name = "{}_links_ios_arm64_macho_load_cmd_for_simulator_test".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework_with_static_library",
binary_test_file = "$BINARY",
binary_test_architecture = "arm64",
cpus = {"ios_multi_cpus": ["sim_arm64"]},
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOSSIMULATOR"],
tags = [name],
)
archive_contents_test(
name = "{}_links_ios_arm64_macho_load_cmd_for_device_test".format(name),
build_type = "device",
cpus = {"ios_multi_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework_with_static_library",
binary_test_architecture = "arm64",
binary_test_file = "$BINARY",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOS"],
tags = [name],
)
archive_contents_test(
name = "{}_links_ios_arm64e_macho_load_cmd_for_device_test".format(name),
build_type = "device",
cpus = {"ios_multi_cpus": ["arm64e"]},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework_with_static_library",
binary_test_architecture = "arm64e",
binary_test_file = "$BINARY",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform IOS"],
tags = [name],
)

# Verify watchos_application links correct XCFramework library for arm64* architectures.
archive_contents_test(
name = "{}_links_watchos_arm64_macho_load_cmd_for_simulator_test".format(name),
build_type = "simulator",
cpus = {"watchos_cpus": ["arm64"]},
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_with_imported_static_xcframework",
not_contains = ["$BUNDLE_ROOT/PlugIns/ext_with_imported_static_xcframework.appex/Frameworks"],
binary_test_file = "$BUNDLE_ROOT/PlugIns/ext_with_imported_static_xcframework.appex/ext_with_imported_static_xcframework",
binary_test_architecture = "arm64",
binary_contains_symbols = [
"-[SharedClass doSomethingShared]",
"_OBJC_CLASS_$_SharedClass",
],
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform WATCHOSSIMULATOR"],
tags = [name],
)
archive_contents_test(
name = "{}_links_watchos_arm64_32_macho_load_cmd_for_device_test".format(name),
build_type = "device",
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_with_imported_static_xcframework",
not_contains = ["$BUNDLE_ROOT/PlugIns/ext_with_imported_static_xcframework.appex/Frameworks"],
binary_test_file = "$BUNDLE_ROOT/PlugIns/ext_with_imported_static_xcframework.appex/ext_with_imported_static_xcframework",
binary_test_architecture = "arm64_32",
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform WATCHOS"],
binary_contains_symbols = [
"-[SharedClass doSomethingShared]",
"_OBJC_CLASS_$_SharedClass",
],
tags = [name],
)

# Verify ios_application bundles Framework files when using xcframework_processor_tool.
archive_contents_test(
name = "{}_ios_application_with_imported_static_xcframework_includes_symbols_with_xcframework_import_tool".format(name),
Expand Down
2 changes: 2 additions & 0 deletions test/starlark_tests/targets_under_test/ios/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,7 @@ ios_application(
"//test/starlark_tests/resources:Info.plist",
],
minimum_os_version = common.min_os_ios.baseline,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
deps = [
":dynamic_xcframework_depending_lib",
Expand Down Expand Up @@ -1823,6 +1824,7 @@ ios_application(
"//test/starlark_tests/resources:Info.plist",
],
minimum_os_version = common.min_os_ios.baseline,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
deps = [
":static_xcframework_depending_objc_lib",
Expand Down
141 changes: 141 additions & 0 deletions test/starlark_tests/targets_under_test/watchos/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ load(
load(
"//apple:apple.bzl",
"apple_dynamic_framework_import",
"apple_dynamic_xcframework_import",
"apple_static_xcframework_import",
)
load(
"//test/starlark_tests:common.bzl",
Expand All @@ -21,6 +23,11 @@ load(
"//test/testdata/fmwk:generate_framework.bzl",
"generate_import_framework",
)
load(
"//test/testdata/xcframeworks:generate_xcframework.bzl",
"generate_dynamic_xcframework",
"generate_static_xcframework",
)
load(
"@build_bazel_rules_swift//swift:swift_library.bzl",
"swift_library",
Expand Down Expand Up @@ -432,3 +439,137 @@ watchos_unit_test(
"//test/starlark_tests/resources:objc_test_lib",
],
)

# -----------------------------------------------------------------------------------------
# Targets for Apple dynamic XCFramework import tests.

watchos_application(
name = "app_with_imported_xcframework",
app_icons = ["//test/starlark_tests/resources:WatchAppIcon.xcassets"],
bundle_id = "com.google.example",
extension = ":ext_with_imported_xcframework",
infoplists = [
"//test/starlark_tests/resources:WatchosAppInfo.plist",
],
minimum_os_version = common.min_os_watchos.arm64_support,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
)

watchos_extension(
name = "ext_with_imported_xcframework",
bundle_id = "com.google.example.ext",
entitlements = "//test/starlark_tests/resources:entitlements.plist",
infoplists = [
"//test/starlark_tests/resources:WatchosExtensionInfo.plist",
],
ipa_post_processor = "//test/starlark_tests/targets_under_test/apple:ipa_post_processor_verify_codesigning",
minimum_os_version = common.min_os_watchos.arm64_support,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
deps = [
":dynamic_xcframework_depending_lib",
"//test/starlark_tests/resources:watchkit_ext_main_lib",
],
)

objc_library(
name = "dynamic_xcframework_depending_lib",
tags = common.fixture_tags,
deps = [
":watchos_imported_dynamic_xcframework",
],
)

apple_dynamic_xcframework_import(
name = "watchos_imported_dynamic_xcframework",
visibility = ["//visibility:public"],
xcframework_imports = [":generated_dynamic_watchos_xcframework"],
)

generate_dynamic_xcframework(
name = "generated_dynamic_watchos_xcframework",
srcs = ["//test/testdata/fmwk:objc_source"],
hdrs = ["//test/testdata/fmwk:objc_headers"],
minimum_os_versions = {
"watchos": common.min_os_watchos.arm64_support,
"watchos_simulator": common.min_os_watchos.arm_sim_support,
},
platforms = {
"watchos": [
"armv7k",
"arm64_32",
],
"watchos_simulator": [
"x86_64",
"arm64",
"i386",
],
},
)

# -----------------------------------------------------------------------------------------
# Targets for Apple static XCFramework import tests.

watchos_application(
name = "app_with_imported_static_xcframework",
app_icons = ["//test/starlark_tests/resources:WatchAppIcon.xcassets"],
bundle_id = "com.google.example",
extension = ":ext_with_imported_static_xcframework",
infoplists = [
"//test/starlark_tests/resources:WatchosAppInfo.plist",
],
minimum_os_version = common.min_os_watchos.arm64_support,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
)

watchos_extension(
name = "ext_with_imported_static_xcframework",
bundle_id = "com.google.example.ext",
entitlements = "//test/starlark_tests/resources:entitlements.plist",
infoplists = [
"//test/starlark_tests/resources:WatchosExtensionInfo.plist",
],
minimum_os_version = common.min_os_watchos.arm64_support,
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
tags = common.fixture_tags,
deps = [
":static_xcframework_depending_lib",
"//test/starlark_tests/resources:watchkit_ext_main_lib",
],
)

objc_library(
name = "static_xcframework_depending_lib",
tags = common.fixture_tags,
deps = [":watchos_imported_static_xcframework"],
)

apple_static_xcframework_import(
name = "watchos_imported_static_xcframework",
features = ["-swift.layering_check"],
visibility = ["//visibility:public"],
xcframework_imports = [":generated_static_watchos_xcframework"],
)

generate_static_xcframework(
name = "generated_static_watchos_xcframework",
srcs = ["//test/testdata/fmwk:objc_source"],
hdrs = ["//test/testdata/fmwk:objc_headers"],
minimum_os_versions = {
"watchos": common.min_os_watchos.arm64_support,
"watchos_simulator": common.min_os_watchos.arm_sim_support,
},
platforms = {
"watchos": [
"armv7k",
"arm64_32",
],
"watchos_simulator": [
"x86_64",
"arm64",
"i386",
],
},
)
10 changes: 8 additions & 2 deletions test/testdata/xcframeworks/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ generate_dynamic_xcframework(
"x86_64",
"arm64",
],
"ios": ["arm64"],
"ios": [
"arm64",
"arm64e",
],
},
)

Expand Down Expand Up @@ -77,7 +80,10 @@ generate_static_xcframework(
"x86_64",
"arm64",
],
"ios": ["arm64"],
"ios": [
"arm64",
"arm64e",
],
},
)

Expand Down

1 comment on commit 717d4b4

@keith
Copy link
Member

@keith keith commented on 717d4b4 Aug 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.