Skip to content

Commit 406899e

Browse files
authored
Enable code coverage in Xcode for swift-built targets (#1623)
This is the second in a stack of PRs across three repositories. - bazelbuild/apple_support#491 - #1623 <-- you are here - MobileNativeFoundation/rules_xcodeproj#3250 It takes the approach suggested in MobileNativeFoundation/rules_xcodeproj#1119 and applies it to our swift toolchain. By breaking sandboxing rules and remapping a derivable path to the source root, we can to allow Xcode, which bookkeeps all code coverage representations in the IDE as absolute paths, to present code coverage information in the gutters and test results.
1 parent 921b53e commit 406899e

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

swift/internal/feature_names.bzl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ SWIFT_FEATURE_DEBUG_PREFIX_MAP = "swift.debug_prefix_map"
6969
# of remote builds.
7070
SWIFT_FEATURE_COVERAGE_PREFIX_MAP = "swift.coverage_prefix_map"
7171

72+
# A private feature that is used to embed absolute source paths in coverage builds.
73+
#
74+
# If enabled, coverage builds will use a `-coverage-prefix-map` that remaps
75+
# the current working directory to a canonical location, which permits
76+
# coverage representation in non-sandboxed builds with tools that expect
77+
# absolute paths such as Xcode.
78+
#
79+
# This feature should only be used with non-sandboxed builds inside tools such as
80+
# Xcode, and enabling it effectively breaks Bazel's ability to rely on the
81+
# remote cache those builds. It should not be enabled by users of the toolchain.
82+
SWIFT_FEATURE__COVERAGE_PREFIX_MAP_ABSOLUTE_SOURCES_NON_HERMETIC = "swift._coverage_prefix_map_absolute_sources_non_hermetic"
83+
7284
# If enabled, C and Objective-C libraries that are direct or transitive
7385
# dependencies of a Swift library will emit explicit precompiled modules that
7486
# are compatible with Swift's ClangImporter and propagate them up the build

swift/toolchains/config/compile_config.bzl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ load(
9090
"SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE",
9191
"SWIFT_FEATURE_USE_PCH_OUTPUT_DIR",
9292
"SWIFT_FEATURE_VFSOVERLAY",
93+
"SWIFT_FEATURE__COVERAGE_PREFIX_MAP_ABSOLUTE_SOURCES_NON_HERMETIC",
9394
"SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS",
9495
"SWIFT_FEATURE__SUPPORTS_UPCOMING_FEATURES",
9596
"SWIFT_FEATURE__SUPPORTS_V6",
@@ -558,6 +559,17 @@ def compile_action_configs(
558559
features = [
559560
[SWIFT_FEATURE_COVERAGE_PREFIX_MAP, SWIFT_FEATURE_COVERAGE],
560561
],
562+
not_features = [SWIFT_FEATURE__COVERAGE_PREFIX_MAP_ABSOLUTE_SOURCES_NON_HERMETIC],
563+
),
564+
ActionConfigInfo(
565+
actions = all_compile_action_names(),
566+
configurators = [
567+
add_arg("-Xwrapped-swift=-coverage-prefix-pwd-is-canonical"),
568+
],
569+
features = [
570+
[SWIFT_FEATURE__COVERAGE_PREFIX_MAP_ABSOLUTE_SOURCES_NON_HERMETIC, SWIFT_FEATURE_COVERAGE],
571+
],
572+
not_features = [SWIFT_FEATURE_COVERAGE_PREFIX_MAP, SWIFT_FEATURE_FILE_PREFIX_MAP],
561573
),
562574

563575
# Ensure that .swiftsourceinfo files are tracked and not deleted by the worker

tools/worker/swift_runner.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,12 @@ bool SwiftRunner::ProcessArgument(
288288

289289
// Helper function for adding path remapping flags that depend on information
290290
// only known at execution time.
291-
auto add_prefix_map_flags = [&](const std::string &flag) {
291+
auto add_prefix_map_flags = [&](const std::string &flag,
292+
const std::string &new_path = ".") {
292293
// Get the actual current working directory (the execution root), which
293294
// we didn't know at analysis time.
294295
consumer(flag);
295-
consumer(std::filesystem::current_path().string() + "=.");
296+
consumer(std::filesystem::current_path().string() + "=" + new_path);
296297

297298
#if __APPLE__
298299
std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__";
@@ -316,7 +317,18 @@ bool SwiftRunner::ProcessArgument(
316317
} else if (new_arg == "-coverage-prefix-pwd-is-dot") {
317318
// Replace the $PWD with . to make the paths relative to the workspace
318319
// without breaking hermiticity.
319-
add_prefix_map_flags("-file-prefix-map");
320+
add_prefix_map_flags("-coverage-prefix-map");
321+
changed = true;
322+
} else if (new_arg == "-coverage-prefix-pwd-is-canonical") {
323+
// Replace the $PWD with . to make the paths relative to the workspace
324+
// without breaking hermiticity.
325+
auto cwd = std::filesystem::current_path();
326+
// The bazel execroot is a normal directory, but inside of it there are
327+
// symlinks to our source tree. This fetches the true path of a known
328+
// directory in order to get the actual source root of the project. This
329+
// should only work with sandboxing disabled.
330+
auto target_path = std::filesystem::canonical(cwd / "BUILD.bazel").parent_path();
331+
add_prefix_map_flags("-coverage-prefix-map", target_path.string());
320332
changed = true;
321333
} else if (new_arg == "-file-prefix-pwd-is-dot") {
322334
// Replace the $PWD with . to make the paths relative to the workspace

0 commit comments

Comments
 (0)