Skip to content

Commit 5931f36

Browse files
nglevinswiple-rules-gardener
authored andcommitted
Establish a private provider to relay archive-relative artifacts when building apps via tree artifact bundling.
PiperOrigin-RevId: 610781162
1 parent c96d8fb commit 5931f36

File tree

7 files changed

+200
-7
lines changed

7 files changed

+200
-7
lines changed

apple/internal/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ bzl_library(
472472
":experimental",
473473
":intermediates",
474474
":outputs",
475+
":providers",
475476
"//apple/internal/utils:bundle_paths",
476477
"//apple/internal/utils:defines",
477478
"@bazel_skylib//lib:partial",

apple/internal/processor.bzl

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ load(
9191
"@build_bazel_rules_apple//apple/internal:outputs.bzl",
9292
"outputs",
9393
)
94+
load(
95+
"@build_bazel_rules_apple//apple/internal:providers.bzl",
96+
"new_applebundlearchivesupportinfo",
97+
)
9498
load(
9599
"@build_bazel_rules_apple//apple/internal/utils:bundle_paths.bzl",
96100
"bundle_paths",
@@ -315,7 +319,7 @@ def _bundle_partial_outputs_files(
315319
for partial_output in partial_outputs:
316320
for location, parent_dir, files in getattr(partial_output, "bundle_files", []):
317321
if tree_artifact_is_enabled and location == _LOCATION_ENUM.archive:
318-
# Skip bundling archive related files, as we're only building the bundle directory.
322+
# These files get relayed via AppleBundleArchiveSupportInfo instead.
319323
continue
320324

321325
if trim_locales:
@@ -352,7 +356,7 @@ def _bundle_partial_outputs_files(
352356

353357
for location, parent_dir, zip_files in getattr(partial_output, "bundle_zips", []):
354358
if tree_artifact_is_enabled and location == _LOCATION_ENUM.archive:
355-
# Skip bundling archive related files, as we're only building the bundle directory.
359+
# These zips get relayed via AppleBundleArchiveSupportInfo instead.
356360
continue
357361

358362
parent_dir_is_valid = _is_parent_dir_valid(
@@ -497,6 +501,9 @@ def _bundle_post_process_and_sign(
497501
rule_descriptor: A rule descriptor for platform and product types from the rule context.
498502
rule_label: The label of the target being analyzed.
499503
xplat_exec_group: A String. The exec_group for actions using the xplat toolchain.
504+
505+
Returns:
506+
A List of providers if any were created during bundling. Can be an empty List.
500507
"""
501508
tree_artifact_is_enabled = is_experimental_tree_artifact_enabled(
502509
platform_prerequisites = platform_prerequisites,
@@ -507,13 +514,33 @@ def _bundle_post_process_and_sign(
507514
rule_descriptor = rule_descriptor,
508515
tree_artifact_is_enabled = tree_artifact_is_enabled,
509516
)
517+
bundling_providers = []
510518
signed_frameworks_depsets = []
511519
for partial_output in partial_outputs:
512520
if hasattr(partial_output, "signed_frameworks"):
513521
signed_frameworks_depsets.append(partial_output.signed_frameworks)
514522
transitive_signed_frameworks = depset(transitive = signed_frameworks_depsets)
515523

516524
if tree_artifact_is_enabled:
525+
bundle_files_for_xcarchive = []
526+
bundle_zips_for_xcarchive = []
527+
528+
for partial_output in partial_outputs:
529+
for location, parent_dir, files in getattr(partial_output, "bundle_files", []):
530+
if location == _LOCATION_ENUM.archive:
531+
bundle_files_for_xcarchive.append((parent_dir, files))
532+
533+
for location, parent_dir, zip_files in getattr(partial_output, "bundle_zips", []):
534+
if location == _LOCATION_ENUM.archive:
535+
bundle_zips_for_xcarchive.append((parent_dir, zip_files))
536+
537+
bundling_providers.append(
538+
new_applebundlearchivesupportinfo(
539+
bundle_files = bundle_files_for_xcarchive,
540+
bundle_zips = bundle_zips_for_xcarchive,
541+
),
542+
)
543+
517544
extra_input_files = []
518545

519546
if entitlements:
@@ -683,6 +710,8 @@ def _bundle_post_process_and_sign(
683710
signed_frameworks = transitive_signed_frameworks,
684711
)
685712

713+
return bundling_providers
714+
686715
def _process(
687716
*,
688717
actions,
@@ -737,6 +766,7 @@ def _process(
737766
"""
738767

739768
partial_outputs = [partial.call(p) for p in partials]
769+
providers = []
740770

741771
if bundle_post_process_and_sign:
742772
output_archive = outputs.archive(
@@ -746,7 +776,7 @@ def _process(
746776
platform_prerequisites = platform_prerequisites,
747777
predeclared_outputs = predeclared_outputs,
748778
)
749-
_bundle_post_process_and_sign(
779+
bundling_providers = _bundle_post_process_and_sign(
750780
actions = actions,
751781
apple_mac_toolchain_info = apple_mac_toolchain_info,
752782
apple_xplat_toolchain_info = apple_xplat_toolchain_info,
@@ -767,11 +797,11 @@ def _process(
767797
rule_label = rule_label,
768798
xplat_exec_group = xplat_exec_group,
769799
)
800+
providers.extend(bundling_providers)
770801
transitive_output_files = [depset([output_archive])]
771802
else:
772803
transitive_output_files = []
773804

774-
providers = []
775805
output_group_dicts = []
776806
for partial_output in partial_outputs:
777807
if hasattr(partial_output, "providers"):

apple/internal/providers.bzl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ set to true for the extension but false for the application.
151151
init = make_banned_init(provider_name = "AppleBundleInfo"),
152152
)
153153

154+
AppleBundleArchiveSupportInfo, new_applebundlearchivesupportinfo = provider(
155+
doc = "Provides supporting files to be embedded within an xcarchive bundle.",
156+
fields = {
157+
"bundle_files": """
158+
Required. A List of tuples of the format (parent_dir, files) where `parent_dir` is a String
159+
indicating the parent directory structure from the root of the archive to the desired output
160+
directory and `files` is a `depset` of `File`s referencing the files to be placed there.
161+
""",
162+
"bundle_zips": """
163+
Required. A List of tuples of the format (parent_dir, files) where `parent_dir` is a String
164+
indicating the parent directory structure from the root of the archive to the desired output
165+
directory and `files` is a `depset` of `File`s referencing the ZIP files to be extracted there.
166+
""",
167+
},
168+
init = make_banned_init(provider_name = "AppleBundleArchiveSupportInfo"),
169+
)
170+
154171
AppleBundleVersionInfo, new_applebundleversioninfo = provider(
155172
doc = "Provides versioning information for an Apple bundle.",
156173
fields = {

test/starlark_tests/ios_extension_tests.bzl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ load(
1818
"//test/starlark_tests/rules:analysis_output_group_info_files_test.bzl",
1919
"analysis_output_group_info_files_test",
2020
)
21+
load(
22+
"//test/starlark_tests/rules:apple_bundle_archive_support_info_device_test.bzl",
23+
"apple_bundle_archive_support_info_device_test",
24+
)
2125
load(
2226
"//test/starlark_tests/rules:apple_dsym_bundle_info_test.bzl",
2327
"apple_dsym_bundle_info_test",
@@ -188,18 +192,24 @@ def ios_extension_test_suite(name):
188192
archive_contents_test(
189193
name = "{}_device_swift_dylibs_present".format(name),
190194
build_type = "device",
191-
target_under_test = "//test/starlark_tests/targets_under_test/tvos:app_with_swift_ext",
195+
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_swift_ext",
192196
not_contains = ["$BUNDLE_ROOT/PlugIns/ext.appex/Frameworks/libswiftCore.dylib"],
193197
contains = [
194198
"$BUNDLE_ROOT/Frameworks/libswiftCore.dylib",
195-
"$ARCHIVE_ROOT/SwiftSupport/appletvos/libswiftCore.dylib",
199+
"$ARCHIVE_ROOT/SwiftSupport/iphoneos/libswiftCore.dylib",
196200
],
197201
tags = [name],
198202
)
203+
apple_bundle_archive_support_info_device_test(
204+
name = "{}_bundle_archive_support_contains_stub_executable_device_test".format(name),
205+
expected_archive_bundle_files = ["SwiftSupport/iphoneos/swiftlibs"],
206+
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_swift_ext",
207+
tags = [name],
208+
)
199209
archive_contents_test(
200210
name = "{}_simulator_swift_dylibs_present".format(name),
201211
build_type = "simulator",
202-
target_under_test = "//test/starlark_tests/targets_under_test/tvos:app_with_swift_ext",
212+
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_swift_ext",
203213
contains = ["$BUNDLE_ROOT/Frameworks/libswiftCore.dylib"],
204214
not_contains = ["$BUNDLE_ROOT/PlugIns/ext.appex/Frameworks/libswiftCore.dylib"],
205215
tags = [name],

test/starlark_tests/ios_imessage_application_tests.bzl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
"""ios_imessage_application Starlark tests."""
1616

17+
load(
18+
"//test/starlark_tests/rules:apple_bundle_archive_support_info_device_test.bzl",
19+
"apple_bundle_archive_support_info_device_test",
20+
)
1721
load(
1822
"//test/starlark_tests/rules:apple_verification_test.bzl",
1923
"apple_verification_test",
@@ -91,6 +95,13 @@ def ios_imessage_application_test_suite(name):
9195
tags = [name],
9296
)
9397

98+
apple_bundle_archive_support_info_device_test(
99+
name = "{}_bundle_archive_support_contains_stub_executable_device_test".format(name),
100+
expected_archive_bundle_files = ["MessagesApplicationSupport/MessagesApplicationSupportStub"],
101+
target_under_test = "//test/starlark_tests/targets_under_test/ios:imessage_app",
102+
tags = [name],
103+
)
104+
94105
native.test_suite(
95106
name = name,
96107
tags = [name],
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Starlark test rule for files found in AppleBundleArchiveSupportInfo fields."""
16+
17+
load(
18+
"@bazel_skylib//lib:new_sets.bzl",
19+
"sets",
20+
)
21+
load(
22+
"@bazel_skylib//lib:paths.bzl",
23+
"paths",
24+
)
25+
load(
26+
"@bazel_skylib//lib:unittest.bzl",
27+
"asserts",
28+
)
29+
load(
30+
"@build_bazel_rules_apple//apple/build_settings:build_settings.bzl",
31+
"build_settings_labels",
32+
)
33+
load(
34+
"@build_bazel_rules_apple//apple/internal:providers.bzl",
35+
"AppleBundleArchiveSupportInfo",
36+
) # buildifier: disable=bzl-visibility
37+
load(
38+
"@build_bazel_rules_apple//test/starlark_tests/rules:analysis_provider_test.bzl",
39+
"make_provider_test_rule",
40+
)
41+
42+
visibility("//test/starlark_tests/...")
43+
44+
def _assert_outputs_in_set(*, actual_outputs, env, expected_outputs):
45+
"""Assert the expected set of outputs is within actual_outputs."""
46+
47+
actual_set = sets.make(actual_outputs)
48+
expected_set = sets.make(expected_outputs)
49+
50+
asserts.set_equals(
51+
env,
52+
expected_set,
53+
sets.intersection(actual_set, expected_set),
54+
"{expected_list} not contained in {actual_list}".format(
55+
actual_list = sets.to_list(actual_set),
56+
expected_list = sets.to_list(expected_set),
57+
),
58+
)
59+
60+
def _assert_contains_expected_bundle_files_and_zips(
61+
ctx,
62+
env,
63+
apple_bundle_archive_support_info):
64+
"""Assert AppleBundleArchiveSupportInfo contains expected bundle files and zips."""
65+
66+
_assert_outputs_in_set(
67+
env = env,
68+
expected_outputs = ctx.attr.expected_archive_bundle_files,
69+
actual_outputs = [
70+
paths.join(parent_dir, file.basename)
71+
for parent_dir, files in apple_bundle_archive_support_info.bundle_files
72+
for file in files.to_list()
73+
],
74+
)
75+
76+
_assert_outputs_in_set(
77+
env = env,
78+
expected_outputs = ctx.attr.expected_archive_bundle_zips,
79+
actual_outputs = [
80+
paths.join(parent_dir, file.basename)
81+
for parent_dir, files in apple_bundle_archive_support_info.bundle_zips
82+
for file in files.to_list()
83+
],
84+
)
85+
86+
apple_bundle_archive_support_info_device_test = make_provider_test_rule(
87+
provider = AppleBundleArchiveSupportInfo,
88+
assertion_fn = _assert_contains_expected_bundle_files_and_zips,
89+
attrs = {
90+
"expected_archive_bundle_files": attr.string_list(
91+
mandatory = False,
92+
doc = """
93+
List of archive-relative bundle file paths expected as outputs of AppleBundleArchiveSupportInfo.
94+
""",
95+
),
96+
"expected_archive_bundle_zips": attr.string_list(
97+
mandatory = False,
98+
doc = """
99+
List of archive-relative bundle zip paths expected as outputs of AppleBundleArchiveSupportInfo.
100+
""",
101+
),
102+
},
103+
config_settings = {
104+
build_settings_labels.use_tree_artifacts_outputs: True,
105+
"//command_line_option:macos_cpus": "arm64,x86_64",
106+
"//command_line_option:ios_multi_cpus": "arm64",
107+
"//command_line_option:tvos_cpus": "arm64",
108+
"//command_line_option:visionos_cpus": "arm64",
109+
"//command_line_option:watchos_cpus": "arm64_32",
110+
},
111+
)

test/starlark_tests/watchos_application_tests.bzl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ load(
2222
"//test/starlark_tests/rules:analysis_target_actions_test.bzl",
2323
"analysis_target_actions_test",
2424
)
25+
load(
26+
"//test/starlark_tests/rules:apple_bundle_archive_support_info_device_test.bzl",
27+
"apple_bundle_archive_support_info_device_test",
28+
)
2529
load(
2630
"//test/starlark_tests/rules:apple_verification_test.bzl",
2731
"apple_verification_test",
@@ -117,6 +121,15 @@ def watchos_application_test_suite(name):
117121
tags = [name],
118122
)
119123

124+
# Tests that the WatchKit stub executable is referenced via the provider if we're building the
125+
# iOS companion app as a tree artifact.
126+
apple_bundle_archive_support_info_device_test(
127+
name = "{}_bundle_archive_support_contains_stub_executable_device_test".format(name),
128+
expected_archive_bundle_files = ["WatchKitSupport2/WK"],
129+
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_companion",
130+
tags = [name],
131+
)
132+
120133
# Test that the output stub binary is identified as watchOS simulator via the Mach-O load
121134
# command LC_VERSION_MIN_WATCHOS for the x86_64 binary slice when only iOS cpus are defined, and
122135
# that 32-bit archs are eliminated.

0 commit comments

Comments
 (0)