Skip to content

Commit eed9e54

Browse files
committed
Add swift.global_module_cache_uses_tmpdir feature
This adds a new feature, that can be enabled by passing `--features=swift.use_global_module_cache` and `--features=swift.global_module_cache_uses_tmpdir` to the build command. This feature, when enabled, will makes the Swift compilation actions use the shared Clang module cache path written to `/private/tmp/__build_bazel_rules_swift/swift_module_cache/REPOSITORY_NAME`. This makes the embedded Clang module breadcrumbs deterministic between Bazel instances, because they are always embedded as absolute paths. Note that the use of this cache is non-hermetic--the cached modules are not wiped between builds, and won't be cleaned when invoking bazel clean; the user is responsible for manually cleaning them. Additionally, this can be used as a workaround for a bug in the Swift compiler that causes the module breadcrumbs to be embedded even though the `-no-clang-module-breadcrumbs` flag is passed (https://bugs.swift.org/browse/SR-13275). Since the source path of modulemaps might be different for the same module, (i.e. multiple checkouts of the same repository, or remote execution), multiple modules with different hashes can end up in the cache. This can result in build failures. Don't use this feature with sandboxing (or probably remote execution as well).
1 parent 2a20daa commit eed9e54

9 files changed

+167
-0
lines changed

swift/internal/compiling.bzl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ load(
4545
"SWIFT_FEATURE_ENABLE_TESTING",
4646
"SWIFT_FEATURE_FASTBUILD",
4747
"SWIFT_FEATURE_FULL_DEBUG_INFO",
48+
"SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR",
4849
"SWIFT_FEATURE_INDEX_WHILE_BUILDING",
4950
"SWIFT_FEATURE_MINIMAL_DEPS",
5051
"SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD",
@@ -484,6 +485,21 @@ def compile_action_configs(
484485
],
485486
configurators = [_global_module_cache_configurator],
486487
features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE],
488+
not_features = [
489+
[SWIFT_FEATURE_USE_C_MODULES],
490+
[SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR],
491+
],
492+
),
493+
swift_toolchain_config.action_config(
494+
actions = [
495+
swift_action_names.COMPILE,
496+
swift_action_names.DERIVE_FILES,
497+
],
498+
configurators = [_tmpdir_module_cache_configurator],
499+
features = [
500+
SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE,
501+
SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR
502+
],
487503
not_features = [SWIFT_FEATURE_USE_C_MODULES],
488504
),
489505
swift_toolchain_config.action_config(
@@ -942,6 +958,18 @@ def _global_module_cache_configurator(prerequisites, args):
942958
paths.join(prerequisites.bin_dir.path, "_swift_module_cache"),
943959
)
944960

961+
def _tmpdir_module_cache_configurator(prerequisites, args):
962+
"""Adds flags to enable a stable tmp directory module cache."""
963+
964+
args.add(
965+
"-module-cache-path",
966+
paths.join(
967+
"/private/tmp/__build_bazel_rules_swift",
968+
"swift_module_cache",
969+
prerequisites.workspace_name,
970+
),
971+
)
972+
945973
def _batch_mode_configurator(prerequisites, args):
946974
"""Adds flags to enable batch compilation mode."""
947975
if not _is_wmo_manually_requested(prerequisites.user_compile_flags):
@@ -1449,6 +1477,7 @@ def compile(
14491477
srcs,
14501478
swift_toolchain,
14511479
target_name,
1480+
workspace_name,
14521481
additional_inputs = [],
14531482
bin_dir = None,
14541483
copts = [],
@@ -1471,6 +1500,9 @@ def compile(
14711500
target_name: The name of the target for which the code is being
14721501
compiled, which is used to determine unique file paths for the
14731502
outputs.
1503+
workspace_name: The name of the workspace for which the code is being
1504+
compiled, which is used to determine unique file paths for some
1505+
outputs.
14741506
additional_inputs: A list of `File`s representing additional input files
14751507
that need to be passed to the Swift compile action because they are
14761508
referenced by compiler flags.
@@ -1662,6 +1694,7 @@ def compile(
16621694
user_compile_flags = copts,
16631695
vfsoverlay_file = vfsoverlay_file,
16641696
vfsoverlay_search_path = _SWIFTMODULES_VFS_ROOT,
1697+
workspace_name = workspace_name,
16651698
# Merge the compile outputs into the prerequisites.
16661699
**struct_fields(compile_outputs)
16671700
)

swift/internal/feature_names.bzl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,29 @@ SWIFT_FEATURE_USE_C_MODULES = "swift.use_c_modules"
158158
# crashes.
159159
SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE = "swift.use_global_module_cache"
160160

161+
# If enabled, and Swift compilation actions will use the shared Clang module
162+
# cache path written to
163+
# `/private/tmp/__build_bazel_rules_swift/swift_module_cache/REPOSITORY_NAME`.
164+
# This makes the embedded Clang module breadcrumbs deterministic between Bazel
165+
# instances, because they are always embedded as absolute paths. Note that the
166+
# use of this cache is non-hermetic--the cached modules are not wiped between
167+
# builds, and won't be cleaned when invoking `bazel clean`; the user is
168+
# responsible for manually cleaning them.
169+
#
170+
# Additionally, this can be used as a workaround for a bug in the Swift
171+
# compiler that causes the module breadcrumbs to be embedded even though the
172+
# `-no-clang-module-breadcrumbs` flag is passed
173+
# (https://bugs.swift.org/browse/SR-13275).
174+
#
175+
# Since the source path of modulemaps might be different for the same module,
176+
# (i.e. multiple checkouts of the same repository, or remote execution),
177+
# multiple modules with different hashes can end up in the cache. This can
178+
# result in build failures. Don't use this feature with sandboxing (or
179+
# probably remote execution as well).
180+
#
181+
# This feature requires `swift.use_global_module_cache` to be enabled.
182+
SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR = "swift.global_module_cache_uses_tmpdir"
183+
161184
# If enabled, actions invoking the Swift driver or frontend may write argument
162185
# lists into response files (i.e., "@args.txt") to avoid passing command lines
163186
# that exceed the system limit. Toolchains typically set this automatically if

swift/internal/swift_binary_test.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def _swift_linking_rule_impl(
198198
srcs = srcs,
199199
swift_toolchain = swift_toolchain,
200200
target_name = ctx.label.name,
201+
workspace_name = ctx.workspace_name,
201202
)
202203
user_link_flags.extend(compilation_outputs.linker_flags)
203204
objects_to_link.extend(compilation_outputs.object_files)

swift/internal/swift_grpc_library.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ def _swift_grpc_library_impl(ctx):
291291
srcs = generated_files,
292292
swift_toolchain = swift_toolchain,
293293
target_name = ctx.label.name,
294+
workspace_name = ctx.workspace_name,
294295
)
295296

296297
linker_input, library_to_link = create_linker_input(

swift/internal/swift_library.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def _swift_library_impl(ctx):
165165
srcs = srcs,
166166
swift_toolchain = swift_toolchain,
167167
target_name = ctx.label.name,
168+
workspace_name = ctx.workspace_name,
168169
)
169170

170171
# If a module was created for the generated header, propagate it as well so

swift/internal/swift_module_alias.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def _swift_module_alias_impl(ctx):
7070
srcs = [reexport_src],
7171
swift_toolchain = swift_toolchain,
7272
target_name = ctx.label.name,
73+
workspace_name = ctx.workspace_name,
7374
)
7475

7576
linker_input, library_to_link = create_linker_input(

swift/internal/swift_protoc_gen_aspect.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx):
426426
srcs = pbswift_files,
427427
swift_toolchain = swift_toolchain,
428428
target_name = target.label.name,
429+
workspace_name = aspect_ctx.workspace_name,
429430
)
430431

431432
linker_input, library_to_link = create_linker_input(

test/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
22
load(":debug_settings_tests.bzl", "debug_settings_test_suite")
33
load(":coverage_settings_tests.bzl", "coverage_settings_test_suite")
44
load(":generated_header_tests.bzl", "generated_header_test_suite")
5+
load(":module_cache_settings_tests.bzl", "module_cache_settings_test_suite")
56
load(":private_deps_tests.bzl", "private_deps_test_suite")
67
load(":swift_through_non_swift_tests.bzl", "swift_through_non_swift_test_suite")
78
load(":split_derived_files_tests.bzl", "split_derived_files_test_suite")
@@ -14,6 +15,8 @@ coverage_settings_test_suite()
1415

1516
generated_header_test_suite()
1617

18+
module_cache_settings_test_suite()
19+
1720
private_deps_test_suite()
1821

1922
swift_through_non_swift_test_suite()

test/module_cache_settings_tests.bzl

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Copyright 2021 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+
"""Tests for module cache related command line flags under various configs."""
16+
17+
load(
18+
"@build_bazel_rules_swift//test/rules:action_command_line_test.bzl",
19+
"make_action_command_line_test_rule",
20+
)
21+
22+
use_global_module_cache_action_command_line_test = make_action_command_line_test_rule(
23+
config_settings = {
24+
"//command_line_option:features": [
25+
"swift.use_global_module_cache",
26+
],
27+
},
28+
)
29+
30+
global_module_cache_uses_tmpdir_action_command_line_test = make_action_command_line_test_rule(
31+
config_settings = {
32+
"//command_line_option:features": [
33+
"swift.global_module_cache_uses_tmpdir",
34+
"swift.use_global_module_cache",
35+
],
36+
},
37+
)
38+
39+
incorrect_global_module_cache_uses_tmpdir_action_command_line_test = make_action_command_line_test_rule(
40+
config_settings = {
41+
"//command_line_option:features": [
42+
"swift.global_module_cache_uses_tmpdir",
43+
],
44+
},
45+
)
46+
47+
def module_cache_settings_test_suite(name = "module_cache_settings"):
48+
"""Test suite for module cache options.
49+
50+
Args:
51+
name: The name prefix for all the nested tests
52+
"""
53+
54+
# Verify that a global module cache path is passed to swiftc.
55+
use_global_module_cache_action_command_line_test(
56+
name = "{}_global_module_cache_build".format(name),
57+
expected_argv = [
58+
"-module-cache-path",
59+
# Starlark doesn't have support for regular expression yet, so we
60+
# can't verify the whole argument here.
61+
"/bin/_swift_module_cache",
62+
],
63+
not_expected_argv = [
64+
"-Xwrapped-swift=-ephemeral-module-cache",
65+
"/private/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift",
66+
],
67+
mnemonic = "SwiftCompile",
68+
tags = [name],
69+
target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple",
70+
)
71+
72+
# Verify that a pre-defined shared module cache path in `/private/tmp` is
73+
# passed to swiftc.
74+
global_module_cache_uses_tmpdir_action_command_line_test(
75+
name = "{}_tmpdir_module_cache_build".format(name),
76+
expected_argv = [
77+
"-module-cache-path",
78+
"/private/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift",
79+
],
80+
not_expected_argv = [
81+
"-Xwrapped-swift=-ephemeral-module-cache",
82+
],
83+
mnemonic = "SwiftCompile",
84+
tags = [name],
85+
target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple",
86+
)
87+
88+
# Verify that no module cache path is used when only
89+
# `swift.global_module_cache_uses_tmpdir` is passed.
90+
incorrect_global_module_cache_uses_tmpdir_action_command_line_test(
91+
name = "{}_incorrect_tmpdir_module_cache_build".format(name),
92+
not_expected_argv = [
93+
"/private/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift",
94+
],
95+
mnemonic = "SwiftCompile",
96+
tags = [name],
97+
target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple",
98+
)
99+
100+
native.test_suite(
101+
name = name,
102+
tags = [name],
103+
)

0 commit comments

Comments
 (0)