From 16cb877951203acf5fbbb1c5f93bd0779d0d4a31 Mon Sep 17 00:00:00 2001 From: Nicholas Levin Date: Fri, 8 Dec 2023 09:17:39 -0800 Subject: [PATCH 1/7] Have Xcode 15+ builds support the newer App Intents metadata processor logic. PiperOrigin-RevId: 589151949 (cherry picked from commit 41d5bb71ed2aade26dfa6e894e05b2b681ea523e) --- apple/internal/aspects/BUILD | 1 + apple/internal/aspects/app_intents_aspect.bzl | 14 +++++++++++++- .../partials/app_intents_metadata_bundle.bzl | 19 +++++++++++++++---- apple/internal/providers/app_intents_info.bzl | 9 +++++++-- .../internal/resource_actions/app_intents.bzl | 14 ++++++++++---- test/starlark_tests/ios_application_tests.bzl | 15 +++++++++++++++ 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/apple/internal/aspects/BUILD b/apple/internal/aspects/BUILD index dcda2b61e7..f96220545f 100644 --- a/apple/internal/aspects/BUILD +++ b/apple/internal/aspects/BUILD @@ -16,6 +16,7 @@ bzl_library( deps = [ "//apple/internal:cc_info_support", "//apple/internal/providers:app_intents_info", + "@build_bazel_apple_support//lib:apple_support", ], ) diff --git a/apple/internal/aspects/app_intents_aspect.bzl b/apple/internal/aspects/app_intents_aspect.bzl index 8b7f13fc9d..0b2ee381e9 100644 --- a/apple/internal/aspects/app_intents_aspect.bzl +++ b/apple/internal/aspects/app_intents_aspect.bzl @@ -14,11 +14,15 @@ """Implementation of the aspect that propagates AppIntentsInfo providers.""" +load( + "@build_bazel_apple_support//lib:apple_support.bzl", + "apple_support", +) +load("@build_bazel_rules_apple//apple/internal:cc_info_support.bzl", "cc_info_support") load( "@build_bazel_rules_apple//apple/internal/providers:app_intents_info.bzl", "AppIntentsInfo", ) -load("@build_bazel_rules_apple//apple/internal:cc_info_support.bzl", "cc_info_support") def _app_intents_aspect_impl(target, ctx): """Implementation of the swift source files propation aspect.""" @@ -32,13 +36,21 @@ def _app_intents_aspect_impl(target, ctx): "Found the following SDK frameworks: %s" % sdk_frameworks.to_list(), ) + swiftconstvalues_files = [] + xcode_version_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] + if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.0"): + swiftconstvalues_files = target[OutputGroupInfo]["const_values"].to_list() + return [ AppIntentsInfo( swift_source_files = ctx.rule.files.srcs, + swiftconstvalues_files = swiftconstvalues_files, ), ] app_intents_aspect = aspect( implementation = _app_intents_aspect_impl, + # The only attrs required for this aspect are for the `xcode_version` >= 15.0 check above. + attrs = apple_support.action_required_attrs(), doc = "Collects Swift source files from swift_library targets required by AppIntents tooling.", ) diff --git a/apple/internal/partials/app_intents_metadata_bundle.bzl b/apple/internal/partials/app_intents_metadata_bundle.bzl index 008709210f..e0b26dd546 100644 --- a/apple/internal/partials/app_intents_metadata_bundle.bzl +++ b/apple/internal/partials/app_intents_metadata_bundle.bzl @@ -88,15 +88,25 @@ def _app_intents_metadata_bundle_partial_impl( label.name + "_app_intents_stub_binary", ) + # Mirroring Xcode 15+ behavior, the metadata tool only looks at the first split for a given arch + # rather than every possible set of source files and inputs. Oddly, this only applies to the + # swift source files and the swiftconstvalues files; the triples and other files do cover all + # available archs. + first_cc_toolchain_key = cc_toolchains.keys()[0] + metadata_bundle = generate_app_intents_metadata_bundle( actions = actions, apple_fragment = platform_prerequisites.apple_fragment, bundle_binary = fat_stub_binary, + constvalues_files = [ + swiftconstvalues_file + for dep in deps[first_cc_toolchain_key] + for swiftconstvalues_file in dep[AppIntentsInfo].swiftconstvalues_files + ], label = label, source_files = [ swift_source_file - for split_deps in deps.values() - for dep in split_deps + for dep in deps[first_cc_toolchain_key] for swift_source_file in dep[AppIntentsInfo].swift_source_files ], target_triples = [ @@ -134,9 +144,10 @@ def app_intents_metadata_bundle_partial( Args: actions: The actions provider from ctx.actions. - cc_toolchains: Dictionary of CcToolchainInfo providers for current target splits. + cc_toolchains: Dictionary of CcToolchainInfo and ApplePlatformInfo providers under a split + transition to relay target platform information. ctx: The Starlark context for a rule target being built. - deps: List of dependencies implementing the AppIntents protocol. + deps: Dictionary of targets under a split transition implementing the AppIntents protocol. disabled_features: List of features to be disabled for C++ link actions. features: List of features to be enabled for C++ link actions. label: Label of the target being built. diff --git a/apple/internal/providers/app_intents_info.bzl b/apple/internal/providers/app_intents_info.bzl index a6758ba8c8..20adcb463d 100644 --- a/apple/internal/providers/app_intents_info.bzl +++ b/apple/internal/providers/app_intents_info.bzl @@ -15,6 +15,11 @@ """AppIntentsInfo provider implementation for AppIntents support for Apple rules.""" AppIntentsInfo = provider( - doc = "Private provider to propagate `.swift` source files required by AppIntents processing.", - fields = ["swift_source_files"], + doc = "Private provider to propagate source files required by AppIntents processing.", + fields = { + "swift_source_files": """ +A List with the swift source Files to handle via app intents processing.""", + "swiftconstvalues_files": """ +A List with the swiftconstvalues Files to handle via app intents processing for Xcode 15+.""", + }, ) diff --git a/apple/internal/resource_actions/app_intents.bzl b/apple/internal/resource_actions/app_intents.bzl index cfe1dca2c5..42a2bfe02b 100644 --- a/apple/internal/resource_actions/app_intents.bzl +++ b/apple/internal/resource_actions/app_intents.bzl @@ -22,6 +22,7 @@ def generate_app_intents_metadata_bundle( actions, apple_fragment, bundle_binary, + constvalues_files, source_files, label, target_triples, @@ -32,6 +33,8 @@ def generate_app_intents_metadata_bundle( actions: The actions provider from `ctx.actions`. apple_fragment: An Apple fragment (ctx.fragments.apple). bundle_binary: File referencing an application/extension/framework binary. + constvalues_files: List of swiftconstvalues files generated from Swift source files + implementing the AppIntents protocol. source_files: List of Swift source files implementing the AppIntents protocol. label: Label for the current target (`ctx.label`). target_triples: List of Apple target triples from `CcToolchainInfo` providers. @@ -55,11 +58,13 @@ def generate_app_intents_metadata_bundle( args.add("--module-name", label.name) args.add("--output", output.dirname) args.add_all("--source-files", source_files) + transitive_inputs = [depset(source_files)] + args.add("--sdk-root", apple_support.path_placeholders.sdkroot()) args.add_all(target_triples, before_each = "--target-triple") if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.0"): - # TODO(b/295227222): Generate app intents metadata with --compile-time-extraction using - # .swiftconstvals instead of --legacy-extraction at the earliest convenience. - args.add("--legacy-extraction") + args.add_all("--swift-const-vals", constvalues_files) + transitive_inputs.append(depset(constvalues_files)) + args.add("--compile-time-extraction") apple_support.run_shell( actions = actions, @@ -82,7 +87,8 @@ elif [[ "$output" == *"skipping writing output"* ]]; then exit 1 fi ''', - inputs = depset([bundle_binary], transitive = [depset(source_files)]), + executable = "/usr/bin/xcrun", + inputs = depset([bundle_binary], transitive = transitive_inputs), outputs = [output], mnemonic = "AppIntentsMetadataProcessor", xcode_config = xcode_version_config, diff --git a/test/starlark_tests/ios_application_tests.bzl b/test/starlark_tests/ios_application_tests.bzl index e53c7df0a0..9fd69ec477 100644 --- a/test/starlark_tests/ios_application_tests.bzl +++ b/test/starlark_tests/ios_application_tests.bzl @@ -779,6 +779,21 @@ def ios_application_test_suite(name): tags = [name], ) + # Test app with App Intents generates and bundles Metadata.appintents bundle for fat binaries. + archive_contents_test( + name = "{}_fat_build_contains_app_intents_metadata_bundle_test".format(name), + build_type = "simulator", + cpus = { + "ios_multi_cpus": ["x86_64", "sim_arm64"], + }, + target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_app_intents", + contains = [ + "$BUNDLE_ROOT/Metadata.appintents/extract.actionsdata", + "$BUNDLE_ROOT/Metadata.appintents/version.json", + ], + tags = [name], + ) + # Test Metadata.appintents bundle contents for simulator and device. archive_contents_test( name = "{}_metadata_appintents_bundle_contents_for_simulator_test".format(name), From d9451cd0012568c1891bf1a0fccf0607710b3ec8 Mon Sep 17 00:00:00 2001 From: Nicholas Levin Date: Mon, 11 Dec 2023 13:52:35 -0800 Subject: [PATCH 2/7] Fix to resolve error when compiling app intents indicating that it expects all values to be statically allocated and resolved at compile time. This pulls all of the module names found from SwiftInfo when gathering the swiftconstfiles. This appears to work in the test targets set up, which do lean on the multiple module strategy. PiperOrigin-RevId: 589938532 (cherry picked from commit 5668eb4e9e2efdc428fe47ec1bb4e9b0ea156b2f) --- apple/internal/aspects/BUILD | 1 + apple/internal/aspects/app_intents_aspect.bzl | 9 +++ .../partials/app_intents_metadata_bundle.bzl | 5 ++ apple/internal/providers/app_intents_info.bzl | 2 + .../internal/resource_actions/app_intents.bzl | 27 +++++++-- test/starlark_tests/common.bzl | 1 + test/starlark_tests/ios_application_tests.bzl | 28 +++++++++ test/starlark_tests/resources/BUILD | 8 +++ .../widget_configuration_intent.swift | 59 +++++++++++++++++++ .../targets_under_test/ios/BUILD | 40 +++++++++++++ 10 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 test/starlark_tests/resources/widget_configuration_intent.swift diff --git a/apple/internal/aspects/BUILD b/apple/internal/aspects/BUILD index f96220545f..c045d40148 100644 --- a/apple/internal/aspects/BUILD +++ b/apple/internal/aspects/BUILD @@ -17,6 +17,7 @@ bzl_library( "//apple/internal:cc_info_support", "//apple/internal/providers:app_intents_info", "@build_bazel_apple_support//lib:apple_support", + "@build_bazel_rules_swift//swift:providers", ], ) diff --git a/apple/internal/aspects/app_intents_aspect.bzl b/apple/internal/aspects/app_intents_aspect.bzl index 0b2ee381e9..a1306e259c 100644 --- a/apple/internal/aspects/app_intents_aspect.bzl +++ b/apple/internal/aspects/app_intents_aspect.bzl @@ -23,6 +23,10 @@ load( "@build_bazel_rules_apple//apple/internal/providers:app_intents_info.bzl", "AppIntentsInfo", ) +load( + "@build_bazel_rules_swift//swift:providers.bzl", + "SwiftInfo", +) def _app_intents_aspect_impl(target, ctx): """Implementation of the swift source files propation aspect.""" @@ -37,12 +41,17 @@ def _app_intents_aspect_impl(target, ctx): ) swiftconstvalues_files = [] + module_names = [] xcode_version_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.0"): + # TODO(b/315847370): See if these names need to be deduplicated, if duplicate entries are at + # all possible. + module_names = [x.name for x in target[SwiftInfo].direct_modules if x.swift] swiftconstvalues_files = target[OutputGroupInfo]["const_values"].to_list() return [ AppIntentsInfo( + intent_module_names = module_names, swift_source_files = ctx.rule.files.srcs, swiftconstvalues_files = swiftconstvalues_files, ), diff --git a/apple/internal/partials/app_intents_metadata_bundle.bzl b/apple/internal/partials/app_intents_metadata_bundle.bzl index e0b26dd546..34f34deab0 100644 --- a/apple/internal/partials/app_intents_metadata_bundle.bzl +++ b/apple/internal/partials/app_intents_metadata_bundle.bzl @@ -103,6 +103,11 @@ def _app_intents_metadata_bundle_partial_impl( for dep in deps[first_cc_toolchain_key] for swiftconstvalues_file in dep[AppIntentsInfo].swiftconstvalues_files ], + intents_module_names = [ + intent_module_name + for dep in deps[first_cc_toolchain_key] + for intent_module_name in dep[AppIntentsInfo].intent_module_names + ], label = label, source_files = [ swift_source_file diff --git a/apple/internal/providers/app_intents_info.bzl b/apple/internal/providers/app_intents_info.bzl index 20adcb463d..b72f0a8a2b 100644 --- a/apple/internal/providers/app_intents_info.bzl +++ b/apple/internal/providers/app_intents_info.bzl @@ -17,6 +17,8 @@ AppIntentsInfo = provider( doc = "Private provider to propagate source files required by AppIntents processing.", fields = { + "intent_module_names": """ +A List with the module names where App Intents are expected to be found.""", "swift_source_files": """ A List with the swift source Files to handle via app intents processing.""", "swiftconstvalues_files": """ diff --git a/apple/internal/resource_actions/app_intents.bzl b/apple/internal/resource_actions/app_intents.bzl index 42a2bfe02b..fec2c37775 100644 --- a/apple/internal/resource_actions/app_intents.bzl +++ b/apple/internal/resource_actions/app_intents.bzl @@ -23,8 +23,9 @@ def generate_app_intents_metadata_bundle( apple_fragment, bundle_binary, constvalues_files, - source_files, + intents_module_names, label, + source_files, target_triples, xcode_version_config): """Process and generate AppIntents metadata bundle (Metadata.appintents). @@ -35,8 +36,10 @@ def generate_app_intents_metadata_bundle( bundle_binary: File referencing an application/extension/framework binary. constvalues_files: List of swiftconstvalues files generated from Swift source files implementing the AppIntents protocol. - source_files: List of Swift source files implementing the AppIntents protocol. + intents_module_names: List of Strings with the module names corresponding to the modules + found which have intents compiled. label: Label for the current target (`ctx.label`). + source_files: List of Swift source files implementing the AppIntents protocol. target_triples: List of Apple target triples from `CcToolchainInfo` providers. xcode_version_config: The `apple_common.XcodeVersionConfig` provider from the current ctx. Returns: @@ -55,14 +58,28 @@ def generate_app_intents_metadata_bundle( args.add("appintentsmetadataprocessor") args.add("--binary-file", bundle_binary) - args.add("--module-name", label.name) + if len(intents_module_names) == 0: + # TODO(b/315847370): See why this works for Xcode 14.x, and if it should be an actual module + # name instead. + args.add("--module-name", label.name) + else: + args.add_all( + intents_module_names, + before_each = "--module-name", + ) args.add("--output", output.dirname) - args.add_all("--source-files", source_files) + args.add_all( + source_files, + before_each = "--source-files", + ) transitive_inputs = [depset(source_files)] args.add("--sdk-root", apple_support.path_placeholders.sdkroot()) args.add_all(target_triples, before_each = "--target-triple") if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.0"): - args.add_all("--swift-const-vals", constvalues_files) + args.add_all( + constvalues_files, + before_each = "--swift-const-vals", + ) transitive_inputs.append(depset(constvalues_files)) args.add("--compile-time-extraction") diff --git a/test/starlark_tests/common.bzl b/test/starlark_tests/common.bzl index 7746b53e87..061eef7eb4 100644 --- a/test/starlark_tests/common.bzl +++ b/test/starlark_tests/common.bzl @@ -37,6 +37,7 @@ _min_os_ios = struct( oldest_supported = "11.0", nplus1 = "13.0", stable_swift_abi = "12.2", + widget_configuration_intents_support = "16.0", ) _min_os_macos = struct( diff --git a/test/starlark_tests/ios_application_tests.bzl b/test/starlark_tests/ios_application_tests.bzl index 9fd69ec477..e62b5215f5 100644 --- a/test/starlark_tests/ios_application_tests.bzl +++ b/test/starlark_tests/ios_application_tests.bzl @@ -779,6 +779,34 @@ def ios_application_test_suite(name): tags = [name], ) + # Test app with a Widget Configuration Intent with a computed property generates and bundles Metadata.appintents bundle. + archive_contents_test( + name = "{}_with_widget_configuration_intent_contains_app_intents_metadata_bundle_test".format(name), + build_type = "simulator", + target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_widget_configuration_intent", + contains = [ + "$BUNDLE_ROOT/Metadata.appintents/extract.actionsdata", + "$BUNDLE_ROOT/Metadata.appintents/version.json", + ], + tags = [ + name, + ], + ) + + # Test app with a Widget Configuration Intent with a computed property generates and bundles Metadata.appintents bundle. + archive_contents_test( + name = "{}_with_app_intent_and_widget_configuration_intent_contains_app_intents_metadata_bundle_test".format(name), + build_type = "simulator", + target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_app_intent_and_widget_configuration_intent", + contains = [ + "$BUNDLE_ROOT/Metadata.appintents/extract.actionsdata", + "$BUNDLE_ROOT/Metadata.appintents/version.json", + ], + tags = [ + name, + ], + ) + # Test app with App Intents generates and bundles Metadata.appintents bundle for fat binaries. archive_contents_test( name = "{}_fat_build_contains_app_intents_metadata_bundle_test".format(name), diff --git a/test/starlark_tests/resources/BUILD b/test/starlark_tests/resources/BUILD index 23a6263819..16e5f9fae7 100644 --- a/test/starlark_tests/resources/BUILD +++ b/test/starlark_tests/resources/BUILD @@ -1118,6 +1118,14 @@ swift_library( tags = common.fixture_tags, ) +swift_library( + name = "widget_configuration_intent", + srcs = ["widget_configuration_intent.swift"], + linkopts = ["-Wl,-framework,AppIntents"], + module_name = "WidgetConfigurationIntent", + tags = common.fixture_tags, +) + # -------------------------------------------------------------------------------- # C/C++ rules with data diff --git a/test/starlark_tests/resources/widget_configuration_intent.swift b/test/starlark_tests/resources/widget_configuration_intent.swift new file mode 100644 index 0000000000..e8ed01be95 --- /dev/null +++ b/test/starlark_tests/resources/widget_configuration_intent.swift @@ -0,0 +1,59 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import AppIntents + +enum RefreshInterval: String, AppEnum { + case hourly, daily, weekly + + static var typeDisplayRepresentation: TypeDisplayRepresentation = "Refresh Interval" + static var caseDisplayRepresentations: [RefreshInterval: DisplayRepresentation] = [ + .hourly: "Every Hour", + .daily: "Every Day", + .weekly: "Every Week", + ] +} + +struct FavoriteSoup: WidgetConfigurationIntent { + static var title: LocalizedStringResource = "Favorite Soup" + static var description = IntentDescription("Shows a picture of your favorite soup!") + + @Parameter(title: "Soup") + var name: String? + + @Parameter(title: "Shuffle", default: true) + var shuffle: Bool + + @Parameter(title: "Refresh", default: .daily) + var interval: RefreshInterval + + static var parameterSummary: some ParameterSummary { + When(\.$shuffle, .equalTo, true) { + Summary { + \.$name + \.$shuffle + \.$interval + } + } otherwise: { + Summary { + \.$name + \.$shuffle + } + } + } + + func perform() async throws -> some IntentResult & ProvidesDialog { + return .result(dialog: "This is an intent with a computed property!") + } +} diff --git a/test/starlark_tests/targets_under_test/ios/BUILD b/test/starlark_tests/targets_under_test/ios/BUILD index f397b2615b..1bc2399e35 100644 --- a/test/starlark_tests/targets_under_test/ios/BUILD +++ b/test/starlark_tests/targets_under_test/ios/BUILD @@ -4478,6 +4478,46 @@ ios_application( ], ) +ios_application( + name = "app_with_widget_configuration_intent", + app_intents = [ + "//test/starlark_tests/resources:widget_configuration_intent", + ], + bundle_id = "com.google.example", + families = ["iphone"], + infoplists = [ + "//test/starlark_tests/resources:Info.plist", + ], + minimum_os_version = common.min_os_ios.widget_configuration_intents_support, + provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision", + tags = common.fixture_tags, + deps = [ + "//test/starlark_tests/resources:swift_uikit_appdelegate", + "//test/starlark_tests/resources:widget_configuration_intent", + ], +) + +ios_application( + name = "app_with_app_intent_and_widget_configuration_intent", + app_intents = [ + "//test/starlark_tests/resources:app_intent", + "//test/starlark_tests/resources:widget_configuration_intent", + ], + bundle_id = "com.google.example", + families = ["iphone"], + infoplists = [ + "//test/starlark_tests/resources:Info.plist", + ], + minimum_os_version = common.min_os_ios.widget_configuration_intents_support, + provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision", + tags = common.fixture_tags, + deps = [ + "//test/starlark_tests/resources:app_intent", + "//test/starlark_tests/resources:swift_uikit_appdelegate", + "//test/starlark_tests/resources:widget_configuration_intent", + ], +) + # --------------------------------------------------------------------------------------- # Targets for base_bundle_id and bundle_id flows with and without shared capabilities. From 6301a192bab4d061e4df89fa6320007f62c8d9b4 Mon Sep 17 00:00:00 2001 From: Nicholas Levin Date: Tue, 12 Dec 2023 13:43:27 -0800 Subject: [PATCH 3/7] Only allow one module to define App Intents, as that is all that Apple's app intents metadata processor tool allows for. PiperOrigin-RevId: 590322476 (cherry picked from commit 21b435b59999513d43e27facbbd767144c4dc77c) --- apple/internal/aspects/BUILD | 2 ++ apple/internal/aspects/app_intents_aspect.bzl | 15 ++++++++--- .../internal/resource_actions/app_intents.bzl | 25 ++++++++++++------- test/starlark_tests/ios_application_tests.bzl | 16 ++++++------ 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/apple/internal/aspects/BUILD b/apple/internal/aspects/BUILD index c045d40148..59347fa2bb 100644 --- a/apple/internal/aspects/BUILD +++ b/apple/internal/aspects/BUILD @@ -16,7 +16,9 @@ bzl_library( deps = [ "//apple/internal:cc_info_support", "//apple/internal/providers:app_intents_info", + "@bazel_skylib//lib:collections", "@build_bazel_apple_support//lib:apple_support", + "@build_bazel_rules_swift//swift:module_name", "@build_bazel_rules_swift//swift:providers", ], ) diff --git a/apple/internal/aspects/app_intents_aspect.bzl b/apple/internal/aspects/app_intents_aspect.bzl index a1306e259c..ec2d0fce0b 100644 --- a/apple/internal/aspects/app_intents_aspect.bzl +++ b/apple/internal/aspects/app_intents_aspect.bzl @@ -14,6 +14,10 @@ """Implementation of the aspect that propagates AppIntentsInfo providers.""" +load( + "@bazel_skylib//lib:collections.bzl", + "collections", +) load( "@build_bazel_apple_support//lib:apple_support.bzl", "apple_support", @@ -23,6 +27,10 @@ load( "@build_bazel_rules_apple//apple/internal/providers:app_intents_info.bzl", "AppIntentsInfo", ) +load( + "@build_bazel_rules_swift//swift:module_name.bzl", + "derive_swift_module_name", +) load( "@build_bazel_rules_swift//swift:providers.bzl", "SwiftInfo", @@ -41,12 +49,11 @@ def _app_intents_aspect_impl(target, ctx): ) swiftconstvalues_files = [] - module_names = [] + module_names = collections.uniq([x.name for x in target[SwiftInfo].direct_modules if x.swift]) + if not module_names: + module_names = [derive_swift_module_name(ctx.label)] xcode_version_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.0"): - # TODO(b/315847370): See if these names need to be deduplicated, if duplicate entries are at - # all possible. - module_names = [x.name for x in target[SwiftInfo].direct_modules if x.swift] swiftconstvalues_files = target[OutputGroupInfo]["const_values"].to_list() return [ diff --git a/apple/internal/resource_actions/app_intents.bzl b/apple/internal/resource_actions/app_intents.bzl index fec2c37775..f03c9c3fd8 100644 --- a/apple/internal/resource_actions/app_intents.bzl +++ b/apple/internal/resource_actions/app_intents.bzl @@ -58,15 +58,22 @@ def generate_app_intents_metadata_bundle( args.add("appintentsmetadataprocessor") args.add("--binary-file", bundle_binary) - if len(intents_module_names) == 0: - # TODO(b/315847370): See why this works for Xcode 14.x, and if it should be an actual module - # name instead. - args.add("--module-name", label.name) - else: - args.add_all( - intents_module_names, - before_each = "--module-name", - ) + + if len(intents_module_names) > 1: + fail(""" +Found the following module names in the top level target {label} for app_intents: {intents_module_names} + +App Intents must have only one module name for metadata generation to work correctly. +""".format( + intents_module_names = ", ".join(intents_module_names), + label = str(label), + )) + elif len(intents_module_names) == 0: + fail(""" +Could not find a module name for app_intents. One is required for App Intents metadata generation. +""") + + args.add("--module-name", intents_module_names[0]) args.add("--output", output.dirname) args.add_all( source_files, diff --git a/test/starlark_tests/ios_application_tests.bzl b/test/starlark_tests/ios_application_tests.bzl index e62b5215f5..0ef7ee3d8f 100644 --- a/test/starlark_tests/ios_application_tests.bzl +++ b/test/starlark_tests/ios_application_tests.bzl @@ -793,15 +793,15 @@ def ios_application_test_suite(name): ], ) - # Test app with a Widget Configuration Intent with a computed property generates and bundles Metadata.appintents bundle. - archive_contents_test( - name = "{}_with_app_intent_and_widget_configuration_intent_contains_app_intents_metadata_bundle_test".format(name), - build_type = "simulator", + # Test app that has two Intents defined as top level modules generates an error message. + analysis_failure_message_test( + name = "{}_with_two_app_intents_and_two_modules_fails".format(name), target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_app_intent_and_widget_configuration_intent", - contains = [ - "$BUNDLE_ROOT/Metadata.appintents/extract.actionsdata", - "$BUNDLE_ROOT/Metadata.appintents/version.json", - ], + expected_error = ( + "App Intents must have only one module name for metadata generation to work correctly." + ).format( + package = "//test/starlark_tests/targets_under_test/ios", + ), tags = [ name, ], From c51f19cb0dbfb396fd13a65fcb534b4ec35a844c Mon Sep 17 00:00:00 2001 From: Nicholas Levin Date: Fri, 26 Jan 2024 09:26:12 -0800 Subject: [PATCH 4/7] Append the Xcode build version to the appintentsmetadataprocessor for Xcode 15.3 builds, based on the version string reported from the XcodeVersionConfig provider. PiperOrigin-RevId: 601786735 (cherry picked from commit ea240b84d659ec39e42b769c058f657dfce7091f) --- apple/internal/resource_actions/app_intents.bzl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apple/internal/resource_actions/app_intents.bzl b/apple/internal/resource_actions/app_intents.bzl index f03c9c3fd8..847f0a31eb 100644 --- a/apple/internal/resource_actions/app_intents.bzl +++ b/apple/internal/resource_actions/app_intents.bzl @@ -89,6 +89,18 @@ Could not find a module name for app_intents. One is required for App Intents me ) transitive_inputs.append(depset(constvalues_files)) args.add("--compile-time-extraction") + if xcode_version_config.xcode_version() >= apple_common.dotted_version("15.3"): + # Read the build version from the fourth component of the Xcode version. + xcode_version_split = str(xcode_version_config.xcode_version()).split(".") + if len(xcode_version_split) < 4: + fail("""\ +Internal Error: Expected xcode_config to report the Xcode version with the build version as the \ +fourth component of the full version string, but instead found {xcode_version_string}. Please file \ +an issue with the Apple BUILD rules with repro steps. +""".format( + xcode_version_string = str(xcode_version_config.xcode_version()), + )) + args.add("--xcode-version", xcode_version_split[3]) apple_support.run_shell( actions = actions, From e84f076ccc68bf5c8579fb0929bd109999f0ec13 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 28 Feb 2024 16:23:50 -0800 Subject: [PATCH 5/7] Compat --- apple/internal/aspects/BUILD | 2 +- apple/internal/aspects/app_intents_aspect.bzl | 2 +- apple/internal/resource_actions/app_intents.bzl | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apple/internal/aspects/BUILD b/apple/internal/aspects/BUILD index 59347fa2bb..ca4555cc99 100644 --- a/apple/internal/aspects/BUILD +++ b/apple/internal/aspects/BUILD @@ -18,8 +18,8 @@ bzl_library( "//apple/internal/providers:app_intents_info", "@bazel_skylib//lib:collections", "@build_bazel_apple_support//lib:apple_support", + "@build_bazel_rules_swift//swift", "@build_bazel_rules_swift//swift:module_name", - "@build_bazel_rules_swift//swift:providers", ], ) diff --git a/apple/internal/aspects/app_intents_aspect.bzl b/apple/internal/aspects/app_intents_aspect.bzl index ec2d0fce0b..0f5e66477f 100644 --- a/apple/internal/aspects/app_intents_aspect.bzl +++ b/apple/internal/aspects/app_intents_aspect.bzl @@ -32,7 +32,7 @@ load( "derive_swift_module_name", ) load( - "@build_bazel_rules_swift//swift:providers.bzl", + "@build_bazel_rules_swift//swift:swift.bzl", "SwiftInfo", ) diff --git a/apple/internal/resource_actions/app_intents.bzl b/apple/internal/resource_actions/app_intents.bzl index 847f0a31eb..eba3acdd8e 100644 --- a/apple/internal/resource_actions/app_intents.bzl +++ b/apple/internal/resource_actions/app_intents.bzl @@ -123,7 +123,6 @@ elif [[ "$output" == *"skipping writing output"* ]]; then exit 1 fi ''', - executable = "/usr/bin/xcrun", inputs = depset([bundle_binary], transitive = transitive_inputs), outputs = [output], mnemonic = "AppIntentsMetadataProcessor", From 2221ba34a4038881619ff3965e72680cafb76cda Mon Sep 17 00:00:00 2001 From: Patrick Balestra Date: Fri, 28 Jun 2024 11:18:33 +0200 Subject: [PATCH 6/7] Possible fix for breaking change --- apple/internal/framework_import_support.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/apple/internal/framework_import_support.bzl b/apple/internal/framework_import_support.bzl index aa8724f0df..9973a812bb 100644 --- a/apple/internal/framework_import_support.bzl +++ b/apple/internal/framework_import_support.bzl @@ -515,6 +515,7 @@ def _swift_info_from_module_interface( requested_features = features, unsupported_features = disabled_features, ), + target_name = module_name, module_name = module_name, swiftinterface_file = swiftinterface_file, swift_infos = swift_infos, From ea520cd3610e65f40907629586962fae255a2ca4 Mon Sep 17 00:00:00 2001 From: Luis Padron Date: Tue, 9 Jul 2024 10:47:32 -0400 Subject: [PATCH 7/7] Update for rules_swift 2.0.0 --- apple/internal/framework_import_support.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/apple/internal/framework_import_support.bzl b/apple/internal/framework_import_support.bzl index 9973a812bb..aa8724f0df 100644 --- a/apple/internal/framework_import_support.bzl +++ b/apple/internal/framework_import_support.bzl @@ -515,7 +515,6 @@ def _swift_info_from_module_interface( requested_features = features, unsupported_features = disabled_features, ), - target_name = module_name, module_name = module_name, swiftinterface_file = swiftinterface_file, swift_infos = swift_infos,