Skip to content

Commit 00a5576

Browse files
CognitiveDissonluispadronbrentleyjones
authored
Use devicectl to install and launch *_application targets on a physical device (#2527)
In Xcode 15, Apple introduced a new command-line tool that allows management of physical devices. This makes it possible to install and launch *_application targets on a physical device without third-party solutions. With these changes, you can now use `bazel run //:iOSApp --ios_multi_cpus=arm64`. Previously, this command would attempt to launch the application on a simulator and fail due to an invalid architecture. Bazel currently lacks a specific flag for specifying device identifiers suitable for this purpose. I created a [PR to Bazel](bazelbuild/bazel#23599) introducing an `--ios_device` flag. However, it's unlikely to be accepted since it's a platform-specific flag. If it is accepted, we can utilize it in the future. For the current implementation, I added astring_flagthat allows passing a device identifier. It can be used like this:--@build_bazel_rules_apple//apple/build_settings:ios_device=<uuid|ecid|serial_number|udid|name|dns_name&gt; . --------- Signed-off-by: Vadim Smal <vadims@spotify.com> Co-authored-by: Luis Padron <heyluispadron@gmail.com> Co-authored-by: Brentley Jones <github@brentleyjones.com>
1 parent bed4231 commit 00a5576

9 files changed

Lines changed: 700 additions & 55 deletions

File tree

apple/build_settings/build_settings.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ Enables Bazel's tree artifacts for Apple bundle rules (instead of archives).
3838
""",
3939
default = False,
4040
),
41+
"ios_device": struct(
42+
doc = """
43+
The identifier, ECID, serial number, UDID, user-provided name, or DNS name
44+
of the device for running an iOS application.
45+
You can get a list of devices by running 'xcrun devicectl list devices`.
46+
""",
47+
default = "",
48+
),
4149
}
4250

4351
_BUILD_SETTING_LABELS = {

apple/internal/ios_rules.bzl

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -468,20 +468,33 @@ def _ios_application_impl(ctx):
468468
label_name = label.name,
469469
)
470470

471-
# TODO(b/254511920): Consider creating a custom build config for iOS simulator device/version.
472-
run_support.register_simulator_executable(
473-
actions = actions,
474-
bundle_extension = bundle_extension,
475-
bundle_name = bundle_name,
476-
label_name = label.name,
477-
output = executable,
478-
platform_prerequisites = platform_prerequisites,
479-
predeclared_outputs = predeclared_outputs,
480-
rule_descriptor = rule_descriptor,
481-
runner_template = ctx.file._runner_template,
482-
simulator_device = ctx.fragments.objc.ios_simulator_device,
483-
simulator_version = ctx.fragments.objc.ios_simulator_version,
484-
)
471+
if platform_prerequisites.platform.is_device:
472+
run_support.register_device_executable(
473+
actions = actions,
474+
bundle_extension = bundle_extension,
475+
bundle_name = bundle_name,
476+
label_name = label.name,
477+
output = executable,
478+
platform_prerequisites = platform_prerequisites,
479+
predeclared_outputs = predeclared_outputs,
480+
rule_descriptor = rule_descriptor,
481+
runner_template = ctx.file._device_runner_template,
482+
device = apple_xplat_toolchain_info.build_settings.ios_device,
483+
)
484+
else:
485+
run_support.register_simulator_executable(
486+
actions = actions,
487+
bundle_extension = bundle_extension,
488+
bundle_name = bundle_name,
489+
label_name = label.name,
490+
output = executable,
491+
platform_prerequisites = platform_prerequisites,
492+
predeclared_outputs = predeclared_outputs,
493+
rule_descriptor = rule_descriptor,
494+
runner_template = ctx.file._simulator_runner_template,
495+
simulator_device = ctx.fragments.objc.ios_simulator_device,
496+
simulator_version = ctx.fragments.objc.ios_simulator_version,
497+
)
485498

486499
archive = outputs.archive(
487500
actions = actions,
@@ -773,20 +786,33 @@ def _ios_app_clip_impl(ctx):
773786
label_name = label.name,
774787
)
775788

776-
# TODO(b/254511920): Consider creating a custom build config for iOS simulator device/version.
777-
run_support.register_simulator_executable(
778-
actions = actions,
779-
bundle_extension = bundle_extension,
780-
bundle_name = bundle_name,
781-
label_name = label.name,
782-
output = executable,
783-
platform_prerequisites = platform_prerequisites,
784-
predeclared_outputs = predeclared_outputs,
785-
rule_descriptor = rule_descriptor,
786-
runner_template = ctx.file._runner_template,
787-
simulator_device = ctx.fragments.objc.ios_simulator_device,
788-
simulator_version = ctx.fragments.objc.ios_simulator_version,
789-
)
789+
if platform_prerequisites.platform.is_device:
790+
run_support.register_device_executable(
791+
actions = actions,
792+
bundle_extension = bundle_extension,
793+
bundle_name = bundle_name,
794+
label_name = label.name,
795+
output = executable,
796+
platform_prerequisites = platform_prerequisites,
797+
predeclared_outputs = predeclared_outputs,
798+
rule_descriptor = rule_descriptor,
799+
runner_template = ctx.file._device_runner_template,
800+
device = apple_xplat_toolchain_info.build_settings.ios_device,
801+
)
802+
else:
803+
run_support.register_simulator_executable(
804+
actions = actions,
805+
bundle_extension = bundle_extension,
806+
bundle_name = bundle_name,
807+
label_name = label.name,
808+
output = executable,
809+
platform_prerequisites = platform_prerequisites,
810+
predeclared_outputs = predeclared_outputs,
811+
rule_descriptor = rule_descriptor,
812+
runner_template = ctx.file._simulator_runner_template,
813+
simulator_device = ctx.fragments.objc.ios_simulator_device,
814+
simulator_version = ctx.fragments.objc.ios_simulator_version,
815+
)
790816

791817
archive = outputs.archive(
792818
actions = actions,
@@ -2544,6 +2570,7 @@ ios_application = rule_factory.create_apple_rule(
25442570
allowed_families = rule_attrs.defaults.allowed_families.ios,
25452571
is_mandatory = True,
25462572
),
2573+
rule_attrs.device_runner_template_attr(),
25472574
rule_attrs.infoplist_attrs(),
25482575
rule_attrs.ipa_post_processor_attrs(),
25492576
rule_attrs.launch_images_attrs(),
@@ -2656,6 +2683,7 @@ ios_app_clip = rule_factory.create_apple_rule(
26562683
allowed_families = rule_attrs.defaults.allowed_families.ios,
26572684
is_mandatory = True,
26582685
),
2686+
rule_attrs.device_runner_template_attr(),
26592687
rule_attrs.infoplist_attrs(),
26602688
rule_attrs.ipa_post_processor_attrs(),
26612689
rule_attrs.locales_to_include_attrs(),

apple/internal/rule_attrs.bzl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ bundle in a directory named `Settings.bundle`.
719719
def _simulator_runner_template_attr():
720720
"""Returns the attribute required to `bazel run` a *_application target with an Apple sim."""
721721
return {
722-
"_runner_template": attr.label(
722+
"_simulator_runner_template": attr.label(
723723
cfg = "exec",
724724
allow_single_file = True,
725725
default = Label(
@@ -728,6 +728,18 @@ def _simulator_runner_template_attr():
728728
),
729729
}
730730

731+
def _device_runner_template_attr():
732+
"""Returns the attribute required to `bazel run` a *_application target on a physical device."""
733+
return {
734+
"_device_runner_template": attr.label(
735+
cfg = "exec",
736+
allow_single_file = True,
737+
default = Label(
738+
"@build_bazel_rules_apple//apple/internal/templates:apple_device_template",
739+
),
740+
),
741+
}
742+
731743
def _locales_to_include_attr():
732744
"""Returns the attribute required to support configuring the explicit set of locales supported for the bundle."""
733745
return {
@@ -757,6 +769,7 @@ rule_attrs = struct(
757769
common_tool_attrs = _common_tool_attrs,
758770
custom_transition_allowlist_attr = _custom_transition_allowlist_attr,
759771
device_family_attrs = _device_family_attrs,
772+
device_runner_template_attr = _device_runner_template_attr,
760773
extensionkit_attrs = _extensionkit_attrs,
761774
infoplist_attrs = _infoplist_attrs,
762775
ipa_post_processor_attrs = _ipa_post_processor_attrs,

apple/internal/run_support.bzl

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,59 @@ def _register_simulator_executable(
7676
},
7777
)
7878

79+
def _register_device_executable(
80+
*,
81+
actions,
82+
bundle_extension,
83+
bundle_name,
84+
label_name,
85+
output,
86+
platform_prerequisites,
87+
predeclared_outputs,
88+
rule_descriptor,
89+
runner_template,
90+
device = None):
91+
"""Registers an action that runs the bundled app on a physical device.
92+
93+
Args:
94+
actions: The actions provider from ctx.actions.
95+
bundle_extension: Extension for the Apple bundle inside the archive.
96+
bundle_name: The name of the output bundle.
97+
label_name: The name of the target.
98+
output: The `File` representing where the executable should be generated.
99+
platform_prerequisites: Struct containing information on the platform being targeted.
100+
predeclared_outputs: Outputs declared by the owning context. Typically from `ctx.outputs`
101+
rule_descriptor: The rule descriptor for the given rule.
102+
runner_template: The simulator runner template as a `File`.
103+
device: The identifier of the device ( <uuid|ecid|serial_number|udid|name|dns_name> ).
104+
"""
105+
106+
device = str(device or "")
107+
minimum_os = str(platform_prerequisites.minimum_os)
108+
platform_type = str(platform_prerequisites.platform_type)
109+
archive = outputs.archive(
110+
actions = actions,
111+
bundle_name = bundle_name,
112+
bundle_extension = bundle_extension,
113+
label_name = label_name,
114+
platform_prerequisites = platform_prerequisites,
115+
predeclared_outputs = predeclared_outputs,
116+
rule_descriptor = rule_descriptor,
117+
)
118+
119+
actions.expand_template(
120+
output = output,
121+
is_executable = True,
122+
template = runner_template,
123+
substitutions = {
124+
"%app_name%": bundle_name,
125+
"%ipa_file%": archive.short_path,
126+
"%minimum_os%": minimum_os,
127+
"%platform_type%": platform_type,
128+
"%device%": device,
129+
},
130+
)
131+
79132
def _register_macos_executable(
80133
*,
81134
actions,
@@ -105,6 +158,7 @@ def _register_macos_executable(
105158

106159
# Define the loadable module that lists the exported symbols in this file.
107160
run_support = struct(
108-
register_simulator_executable = _register_simulator_executable,
161+
register_device_executable = _register_device_executable,
109162
register_macos_executable = _register_macos_executable,
163+
register_simulator_executable = _register_simulator_executable,
110164
)

apple/internal/templates/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ filegroup(
1818
visibility = ["//visibility:public"],
1919
)
2020

21+
filegroup(
22+
name = "apple_device_template",
23+
srcs = ["apple_device.template.py"],
24+
# Used by the rule implementations, so it needs to be public; but
25+
# should be considered an implementation detail of the rules and
26+
# not used by other things.
27+
visibility = ["//visibility:public"],
28+
)
29+
2130
filegroup(
2231
name = "macos_template",
2332
srcs = ["macos.template.sh"],

0 commit comments

Comments
 (0)