Skip to content

Commit 714f607

Browse files
authored
Remove need to have --watchos_cpus defined when building iOS applications with watchOS apps (#2838)
1 parent 510c9de commit 714f607

File tree

4 files changed

+241
-27
lines changed

4 files changed

+241
-27
lines changed

apple/internal/transition_support.bzl

Lines changed: 100 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ _CPU_TO_DEFAULT_PLATFORM_FLAG = {
6060
for cpu, platform_name in CPU_TO_DEFAULT_PLATFORM_NAME.items()
6161
}
6262

63+
_IOS_ARCH_TO_EARLIEST_WATCHOS = {
64+
"x86_64": "x86_64",
65+
"sim_arm64": "arm64",
66+
"arm64": "armv7k",
67+
}
68+
69+
_IOS_ARCH_TO_64_BIT_WATCHOS = {
70+
"x86_64": "x86_64",
71+
"sim_arm64": "arm64",
72+
"arm64": "arm64_32",
73+
}
74+
6375
def _platform_specific_cpu_setting_name(platform_type):
6476
"""Returns the name of a platform-specific CPU setting.
6577
@@ -77,12 +89,63 @@ def _platform_specific_cpu_setting_name(platform_type):
7789
fail("ERROR: Unknown platform type: {}".format(platform_type))
7890
return flag
7991

80-
def _environment_archs(platform_type, settings):
92+
def _environment_arch_from_cpu(*, cpu_value, platform_prefix):
93+
"""Returns a specific platform's environment arch if found from the `--cpu` command line option.
94+
95+
Args:
96+
cpu_value: String found from an incoming `--cpu` value.
97+
platform_prefix: The platform prefix to search for within the incoming `--cpu` string.
98+
99+
Returns:
100+
The value following the platform_prefix if it was found in the incoming `--cpu` value, which
101+
is expected to be a valid environment arch, or `None`.
102+
"""
103+
if cpu_value.startswith(platform_prefix):
104+
return cpu_value[len(platform_prefix):]
105+
return None
106+
107+
def _watchos_environment_archs_from_ios(*, cpu_value, minimum_os_version, settings):
108+
"""Returns a set of watchOS environment archs based on incoming iOS archs.
109+
110+
Args:
111+
cpu_value: String found from an incoming `--cpu` value.
112+
minimum_os_version: A string coming directly from a rule's `minimum_os_version` attribute.
113+
settings: A dictionary whose set of keys is defined by the inputs parameter, typically from
114+
the settings argument found on the implementation function of the current Starlark
115+
transition.
116+
117+
Returns:
118+
A list of watchOS environment archs if any were found from the iOS environment archs, or an
119+
empty list if none were found.
120+
"""
121+
environment_archs = []
122+
ios_archs = settings[_platform_specific_cpu_setting_name("ios")]
123+
if not ios_archs:
124+
ios_arch = _environment_arch_from_cpu(
125+
cpu_value = cpu_value,
126+
platform_prefix = "ios_",
127+
)
128+
if ios_arch:
129+
ios_archs = [ios_arch]
130+
if ios_archs:
131+
# Make sure to return a fallback compatible with the rule's assigned minimum OS.
132+
ios_to_watchos_arch_dict = _IOS_ARCH_TO_64_BIT_WATCHOS
133+
if apple_common.dotted_version(minimum_os_version) < apple_common.dotted_version("9.0"):
134+
ios_to_watchos_arch_dict = _IOS_ARCH_TO_EARLIEST_WATCHOS
135+
environment_archs = [
136+
ios_to_watchos_arch_dict[arch]
137+
for arch in ios_archs
138+
if ios_to_watchos_arch_dict.get(arch)
139+
]
140+
return environment_archs
141+
142+
def _environment_archs(platform_type, minimum_os_version, settings):
81143
"""Returns a full set of environment archs from the incoming command line options.
82144
83145
Args:
84146
platform_type: A string denoting the platform type; `"ios"`, `"macos"`,
85147
`"tvos"`, `"visionos"`, or `"watchos"`.
148+
minimum_os_version: A string coming directly from a rule's `minimum_os_version` attribute.
86149
settings: A dictionary whose set of keys is defined by the inputs parameter, typically from
87150
the settings argument found on the implementation function of the current Starlark
88151
transition.
@@ -93,11 +156,30 @@ def _environment_archs(platform_type, settings):
93156
"""
94157
environment_archs = settings[_platform_specific_cpu_setting_name(platform_type)]
95158
if not environment_archs:
159+
cpu_value = settings["//command_line_option:cpu"]
96160
if platform_type == "ios":
97-
# Legacy exception to interpret the --cpu as an iOS arch.
98-
cpu_value = settings["//command_line_option:cpu"]
99-
if cpu_value.startswith("ios_"):
100-
environment_archs = [cpu_value[4:]]
161+
# Legacy handling to interpret the --cpu as an iOS environment arch.
162+
ios_arch = _environment_arch_from_cpu(
163+
cpu_value = cpu_value,
164+
platform_prefix = "ios_",
165+
)
166+
if ios_arch:
167+
environment_archs = [ios_arch]
168+
if platform_type == "watchos":
169+
# Interpret the --cpu as a watchOS environment arch; often will be set by a transition.
170+
watchos_arch = _environment_arch_from_cpu(
171+
cpu_value = cpu_value,
172+
platform_prefix = "watchos_",
173+
)
174+
if watchos_arch:
175+
environment_archs = [watchos_arch]
176+
else:
177+
# If not found, generate watchOS archs via incoming iOS environment arch(s).
178+
environment_archs = _watchos_environment_archs_from_ios(
179+
cpu_value = cpu_value,
180+
minimum_os_version = minimum_os_version,
181+
settings = settings,
182+
)
101183
if not environment_archs:
102184
environment_archs = [
103185
_cpu_string(
@@ -366,10 +448,11 @@ def _command_line_options_for_xcframework_platform(
366448

367449
def _apple_rule_base_transition_impl(settings, attr):
368450
"""Rule transition for Apple rules using Bazel CPUs and a valid Apple split transition."""
451+
minimum_os_version = attr.minimum_os_version
369452
platform_type = attr.platform_type
370453
return _command_line_options(
371-
environment_arch = _environment_archs(platform_type, settings)[0],
372-
minimum_os_version = attr.minimum_os_version,
454+
environment_arch = _environment_archs(platform_type, minimum_os_version, settings)[0],
455+
minimum_os_version = minimum_os_version,
373456
platform_type = platform_type,
374457
settings = settings,
375458
)
@@ -425,13 +508,13 @@ _apple_rule_base_transition = transition(
425508
)
426509

427510
def _apple_platforms_rule_base_transition_impl(settings, attr):
428-
"""Rule transition for Apple rules using Bazel platforms."""
511+
"""Rule transition for Apple rules using Bazel platforms and the Starlark split transition."""
429512
minimum_os_version = attr.minimum_os_version
430513
platform_type = attr.platform_type
431514
environment_arch = None
432515
if not settings["//command_line_option:incompatible_enable_apple_toolchain_resolution"]:
433516
# Add fallback to match an anticipated split of Apple cpu-based resolution
434-
environment_arch = _environment_archs(platform_type, settings)[0]
517+
environment_arch = _environment_archs(platform_type, minimum_os_version, settings)[0]
435518
return _command_line_options(
436519
apple_platforms = settings["//command_line_option:apple_platforms"],
437520
environment_arch = environment_arch,
@@ -453,10 +536,14 @@ def _apple_platforms_rule_bundle_output_base_transition_impl(settings, attr):
453536
environment_arch = None
454537
if not settings["//command_line_option:incompatible_enable_apple_toolchain_resolution"]:
455538
# Add fallback to match an anticipated split of Apple cpu-based resolution
456-
environment_arch = _environment_archs(platform_type, settings)[0]
539+
environment_arch = _environment_archs(
540+
platform_type = platform_type,
541+
settings = settings,
542+
minimum_os_version = minimum_os_version,
543+
)
457544
return _command_line_options(
458545
apple_platforms = settings["//command_line_option:apple_platforms"],
459-
environment_arch = environment_arch,
546+
environment_arch = environment_arch[0],
460547
force_bundle_outputs = True,
461548
minimum_os_version = minimum_os_version,
462549
platform_type = platform_type,
@@ -558,8 +645,9 @@ def _apple_platform_split_transition_impl(settings, attr):
558645
)
559646

560647
else:
648+
minimum_os_version = attr.minimum_os_version
561649
platform_type = attr.platform_type
562-
for environment_arch in _environment_archs(platform_type, settings):
650+
for environment_arch in _environment_archs(platform_type, minimum_os_version, settings):
563651
found_cpu = _cpu_string(
564652
environment_arch = environment_arch,
565653
platform_type = platform_type,
@@ -568,7 +656,6 @@ def _apple_platform_split_transition_impl(settings, attr):
568656
if found_cpu in output_dictionary:
569657
continue
570658

571-
minimum_os_version = attr.minimum_os_version
572659
environment_arch_is_supported = _is_arch_supported_for_target_tuple(
573660
environment_arch = environment_arch,
574661
minimum_os_version = minimum_os_version,

test/starlark_tests/targets_under_test/watchos/BUILD

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,15 @@ watchos_application(
227227
name = "app_arm64_support",
228228
app_icons = ["//test/starlark_tests/resources:WatchAppIcon.xcassets"],
229229
bundle_id = "com.google.example",
230-
extension = ":ext_arm64_support",
231230
infoplists = [
232231
"//test/starlark_tests/resources:WatchosAppInfo.plist",
233232
],
234233
minimum_os_version = common.min_os_watchos.arm64_support,
235234
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
236235
tags = common.fixture_tags,
236+
deps = [
237+
"//test/starlark_tests/resources:watchkit_single_target_app_main_lib",
238+
],
237239
)
238240

239241
watchos_extension(
@@ -257,6 +259,21 @@ watchos_extension(
257259
],
258260
)
259261

262+
watchos_extension(
263+
name = "ext_arm64_support",
264+
bundle_id = "com.google.example.ext",
265+
entitlements = "//test/starlark_tests/resources:entitlements.plist",
266+
infoplists = [
267+
"//test/starlark_tests/resources:WatchosExtensionInfo.plist",
268+
],
269+
minimum_os_version = common.min_os_watchos.arm64_support,
270+
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
271+
tags = common.fixture_tags,
272+
deps = [
273+
"//test/starlark_tests/resources:watchkit_ext_main_lib",
274+
],
275+
)
276+
260277
watchos_extension(
261278
name = "ext_with_fmwk",
262279
bundle_id = "com.google.example.ext",
@@ -369,27 +386,28 @@ watchos_extension(
369386
tags = common.fixture_tags,
370387
)
371388

372-
watchos_extension(
373-
name = "ext_arm64_support",
374-
bundle_id = "com.google.example.ext",
389+
ios_application(
390+
name = "app_companion",
391+
bundle_id = "com.google",
392+
families = ["iphone"],
375393
infoplists = [
376-
"//test/starlark_tests/resources:WatchosExtensionInfo.plist",
394+
"//test/starlark_tests/resources:Info.plist",
377395
],
378-
minimum_os_version = common.min_os_watchos.arm64_support,
396+
minimum_os_version = common.min_os_ios.baseline,
379397
provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision",
380-
resources = [
381-
"//test/starlark_tests/resources:example_filegroup",
382-
"//test/starlark_tests/resources:localization",
383-
"//test/starlark_tests/resources:resource_bundle",
384-
],
385398
tags = common.fixture_tags,
399+
visibility = [
400+
"//test/starlark_tests:__subpackages__",
401+
"//tools/dossier_codesigningtool:__pkg__",
402+
],
403+
watch_application = ":app",
386404
deps = [
387-
"//test/starlark_tests/resources:watchkit_ext_main_lib",
405+
"//test/starlark_tests/resources:objc_main_lib",
388406
],
389407
)
390408

391409
ios_application(
392-
name = "app_companion",
410+
name = "app_companion_arm64_support",
393411
bundle_id = "com.google",
394412
families = ["iphone"],
395413
infoplists = [
@@ -402,7 +420,7 @@ ios_application(
402420
"//test/starlark_tests:__subpackages__",
403421
"//tools/dossier_codesigningtool:__pkg__",
404422
],
405-
watch_application = ":app",
423+
watch_application = ":app_arm64_support",
406424
deps = [
407425
"//test/starlark_tests/resources:objc_main_lib",
408426
],

test/starlark_tests/watchos_application_tests.bzl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,60 @@ def watchos_application_test_suite(name):
115115
tags = [name],
116116
)
117117

118+
# Test that the output stub binary is identified as watchOS simulator via the Mach-O load
119+
# command LC_VERSION_MIN_WATCHOS for the arm64 binary slice when only iOS cpus are defined, and
120+
# that 32-bit archs are eliminated.
121+
binary_contents_test(
122+
name = "{}_simulator_ios_cpus_intel_platform_test".format(name),
123+
build_type = "simulator",
124+
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_companion",
125+
cpus = {
126+
"ios_multi_cpus": ["x86_64", "sim_arm64"],
127+
"watchos_cpus": [""],
128+
},
129+
binary_test_file = "$BUNDLE_ROOT/Watch/app.app/_WatchKitStub/WK",
130+
binary_test_architecture = "x86_64",
131+
binary_not_contains_architectures = ["i386", "arm64e"],
132+
macho_load_commands_contain = ["cmd LC_VERSION_MIN_WATCHOS"],
133+
tags = [name],
134+
)
135+
136+
# Test that the output application binary is identified as watchOS simulator via the Mach-O
137+
# load command LC_BUILD_VERSION for the arm64 binary slice when only iOS cpus are defined, and
138+
# that 32-bit archs are eliminated.
139+
binary_contents_test(
140+
name = "{}_simulator_ios_cpus_arm_platform_test".format(name),
141+
build_type = "simulator",
142+
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_companion",
143+
cpus = {
144+
"ios_multi_cpus": ["x86_64", "sim_arm64"],
145+
"watchos_cpus": [""],
146+
},
147+
binary_test_file = "$BUNDLE_ROOT/Watch/app.app/_WatchKitStub/WK",
148+
binary_test_architecture = "arm64",
149+
binary_not_contains_architectures = ["i386", "arm64e"],
150+
macho_load_commands_contain = ["cmd LC_BUILD_VERSION", "platform WATCHOSSIMULATOR"],
151+
tags = [name],
152+
)
153+
154+
# Test that the output stub binary is identified as watchOS simulator via the Mach-O load
155+
# command LC_VERSION_MIN_WATCHOS for the arm64 binary slice when only iOS cpus are defined, and
156+
# that it defaults to armv7k.
157+
binary_contents_test(
158+
name = "{}_device_ios_cpus_platform_test".format(name),
159+
build_type = "device",
160+
target_under_test = "//test/starlark_tests/targets_under_test/watchos:app_companion",
161+
cpus = {
162+
"ios_multi_cpus": ["arm64"],
163+
"watchos_cpus": [""],
164+
},
165+
binary_test_file = "$BUNDLE_ROOT/Watch/app.app/app",
166+
binary_test_architecture = "armv7k",
167+
binary_not_contains_architectures = ["arm64_32", "arm64", "arm64e"],
168+
macho_load_commands_contain = ["cmd LC_VERSION_MIN_WATCHOS"],
169+
tags = [name],
170+
)
171+
118172
# Test that the output multi-arch stub binary is identified as watchOS simulator via the Mach-O
119173
# load command LC_BUILD_VERSION for the arm64 binary slice, and that 32-bit archs are
120174
# eliminated.

0 commit comments

Comments
 (0)