Skip to content

Commit d613b0d

Browse files
Improve compile_only_aspect (#3222)
* Collect `CppCompile` * Add a new `resources` output group, which will cause the resources that will be bundled to be processed (e.g. asset catalog compiles, `Info.plist` processing, entitlement processing, etc.) --------- Signed-off-by: Brentley Jones <github@brentleyjones.com>
1 parent 43ac4f3 commit d613b0d

File tree

2 files changed

+148
-61
lines changed

2 files changed

+148
-61
lines changed

docs/usage.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ bazel run //label/to:xcodeproj \
5858
'build --config=compile_only --remote_download_minimal $_GENERATOR_LABEL_'
5959
```
6060

61+
If you want to also cache resource processing (e.g. asset catalog compiles,
62+
`Info.plist` processing, entitlement processing, etc.), then you can also
63+
include the `resources` output group:
64+
65+
```
66+
common:compile_only --output_groups=compiles,resources
67+
```
68+
6169
# Bazel configs
6270

6371
The way your project is generated, and the way Bazel builds it inside of Xcode,

xcodeproj/compile_only_aspect.bzl

Lines changed: 140 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,106 @@
11
"""
2-
Aspect that collects the outputs of all compile actions of a given build.
3-
Useful to be able to build and cache compile actions on CI, without having to
4-
link, bundle, or codesign as well (which we don't cache anyway).
2+
Aspect that collects the outputs of all actions that we want to cache for
3+
developers in a given build.
4+
5+
Useful to be able to build and cache actions on CI, without having to link,
6+
bundle, or codesign as well (which we don't cache anyway).
57
"""
68

7-
_DOWNSTREAM_VALID_RULE_KINDS = {
8-
"apple_dynamic_framework_import": None,
9-
"apple_dynamic_xcframework_import": None,
10-
"apple_static_framework_import": None,
11-
"apple_static_xcframework_import": None,
12-
"cc_binary": None,
13-
"ios_app_clip": None,
14-
"ios_application": None,
15-
"ios_extension": None,
16-
"ios_framework": None,
17-
"ios_ui_test": None,
18-
"ios_unit_test": None,
19-
"swift_binary": None,
20-
"swift_test": None,
21-
"_ios_internal_ui_test_bundle": None,
22-
"_ios_internal_unit_test_bundle": None,
23-
"_precompiled_apple_resource_bundle": None,
24-
}
25-
26-
_SWIFT_LIBRARY_KINDS = [
27-
"swift_library",
28-
"swift_test",
29-
]
30-
31-
def _compile_only_aspect_impl(target, ctx):
32-
outs = []
33-
deps = []
34-
if ctx.rule.kind in _DOWNSTREAM_VALID_RULE_KINDS or CcInfo in target:
35-
if ctx.rule.kind in _SWIFT_LIBRARY_KINDS:
36-
for action in target.actions:
37-
if action.mnemonic == "SwiftCompile":
38-
outs = [action.outputs]
39-
break
40-
elif ctx.rule.kind == "objc_library":
41-
outs = [
42-
action.outputs
43-
for action in target.actions
44-
if action.mnemonic == "ObjcCompile"
45-
]
9+
load("@build_bazel_rules_apple//apple:providers.bzl", "AppleResourceInfo")
10+
load("@build_bazel_rules_swift//swift:providers.bzl", "SwiftInfo")
11+
12+
_BUNDLING_RULE_KINDS = set([
13+
"ios_app_clip",
14+
"ios_application",
15+
"ios_build_test",
16+
"ios_extension",
17+
"macos_application",
18+
"macos_build_test",
19+
"macos_extension",
20+
"tvos_application",
21+
"tvos_build_test",
22+
"tvos_extension",
23+
"visionos_application",
24+
"visionos_build_test",
25+
"visionos_extension",
26+
"watchos_application",
27+
"watchos_build_test",
28+
"watchos_extension",
29+
"_ios_internal_ui_test_bundle",
30+
"_ios_internal_unit_test_bundle",
31+
"_macos_internal_ui_test_bundle",
32+
"_macos_internal_unit_test_bundle",
33+
"_tvos_internal_ui_test_bundle",
34+
"_tvos_internal_unit_test_bundle",
35+
"_visionos_internal_ui_test_bundle",
36+
"_visionos_internal_unit_test_bundle",
37+
"_watchos_internal_ui_test_bundle",
38+
"_watchos_internal_unit_test_bundle",
39+
])
40+
41+
_COMPILE_MNEMONICS = set([
42+
"CppCompile",
43+
"ObjcCompile",
44+
"SwiftCompile",
45+
])
46+
47+
_RESOURCE_MNEMONICS = set([
48+
"AlternateIconsInsert",
49+
"AppIntentsMetadataProcessor",
50+
"AssetCatalogCompile",
51+
"CompileInfoPlist",
52+
"CompilePlist",
53+
"CompileRootInfoPlist",
54+
"CompileStrings",
55+
"CompileTextureAtlas",
56+
"CompileXCStrings",
57+
"CopyPng",
58+
"MappingModelCompile",
59+
"MetalCompile",
60+
"MlmodelCompile",
61+
"MomCompile",
62+
"ProcessEntitlementsFiles",
63+
"ProcessDEREntitlements",
64+
"ProcessSimulatorEntitlementsFile",
65+
"StoryboardCompile",
66+
"StoryboardLink",
67+
"XibCompile",
68+
])
69+
70+
def _xcodeproj_cache_warm_aspect_impl(target, ctx):
71+
compile_outs = []
72+
resource_outs = []
73+
74+
if ctx.rule.kind in _BUNDLING_RULE_KINDS:
4675
deps = (
47-
getattr(ctx.rule.attr, "deps", []) +
48-
getattr(ctx.rule.attr, "implementation_deps", []) +
49-
getattr(ctx.rule.attr, "private_deps", [])
76+
ctx.rule.attr.deps +
77+
getattr(ctx.rule.attr, "extensions", []) +
78+
getattr(ctx.rule.attr, "frameworks", [])
5079
)
51-
swift_target = getattr(ctx.rule.attr, "swift_target", None)
52-
if swift_target:
53-
deps.append(swift_target)
54-
clang_target = getattr(ctx.rule.attr, "clang_target", None)
55-
if clang_target:
56-
deps.append(clang_target)
80+
81+
# Collect already processed resources from dependencies
82+
resource_info = target[AppleResourceInfo]
83+
dep_resources = [
84+
resources
85+
for (_, _, resources) in (
86+
resource_info.processed +
87+
resource_info.unprocessed
88+
)
89+
]
90+
91+
# Collect resources from this target
92+
self_resources = [
93+
action.outputs
94+
for action in target.actions
95+
if action.mnemonic in _RESOURCE_MNEMONICS
96+
]
97+
98+
resource_outs = self_resources + dep_resources
99+
elif ctx.rule.kind == "mixed_language_library":
100+
deps = [
101+
ctx.rule.attr.swift_target,
102+
ctx.rule.attr.clang_target,
103+
]
57104
elif ctx.rule.kind == "test_suite":
58105
deps = ctx.rule.attr.tests
59106
elif ctx.rule.kind == "ios_build_test":
@@ -63,35 +110,67 @@ def _compile_only_aspect_impl(target, ctx):
63110
getattr(ctx.rule.attr, "top_level_device_targets", []) +
64111
getattr(ctx.rule.attr, "top_level_simulator_targets", [])
65112
)
113+
elif CcInfo in target or SwiftInfo in target:
114+
compile_outs = [
115+
action.outputs
116+
for action in target.actions
117+
if action.mnemonic in _COMPILE_MNEMONICS
118+
]
119+
deps = (
120+
getattr(ctx.rule.attr, "deps", []) +
121+
getattr(ctx.rule.attr, "implementation_deps", []) +
122+
getattr(ctx.rule.attr, "private_deps", [])
123+
)
66124
else:
67-
return []
125+
deps = getattr(ctx.rule.attr, "deps", [])
68126

69127
return [
70128
OutputGroupInfo(
71129
compiles = depset(
72-
transitive = outs + [
130+
transitive = compile_outs + [
73131
dep[OutputGroupInfo].compiles
74132
for dep in deps
75-
if OutputGroupInfo in dep and hasattr(dep[OutputGroupInfo], "compiles")
133+
if (
134+
OutputGroupInfo in dep and
135+
hasattr(dep[OutputGroupInfo], "compiles")
136+
)
137+
],
138+
),
139+
resources = depset(
140+
transitive = resource_outs + [
141+
dep[OutputGroupInfo].resources
142+
for dep in deps
143+
if (
144+
OutputGroupInfo in dep and
145+
hasattr(dep[OutputGroupInfo], "resources")
146+
)
76147
],
77148
),
78149
),
79150
]
80151

81-
compile_only_aspect = aspect(
82-
implementation = _compile_only_aspect_impl,
152+
xcodeproj_cache_warm_aspect = aspect(
153+
implementation = _xcodeproj_cache_warm_aspect_impl,
83154
attr_aspects = [
84155
"deps",
85156
"implementation_deps",
86157
"private_deps",
87-
# from `mixed_language_library`
158+
159+
# `*_application`
160+
"extensions",
161+
"frameworks",
162+
163+
# `mixed_language_library`
88164
"clang_target",
89165
"swift_target",
90-
# from `test_suite`
91-
"targets",
92-
# from `*_build_test`
166+
167+
# `test_suite`
93168
"tests",
94-
# from `xcodeproj`
169+
170+
# `*_build_test`
171+
"targets",
172+
173+
# `xcodeproj`
95174
"top_level_device_targets",
96175
"top_level_simulator_targets",
97176
],

0 commit comments

Comments
 (0)