diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 3242857a4..be1c6cd36 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -132,6 +132,11 @@ SWIFT_FEATURE_FULL_DEBUG_INFO = "swift.full_debug_info" # Use CodeView debug information, which enables generation of PDBs for debugging. SWIFT_FEATURE_CODEVIEW_DEBUG_INFO = "swift.codeview_debug_info" +# If enabled, paths embedded into precompiled Clang modules will be relative to +# the workspace, not to the modulemap file location. Paths in the module maps +# themselves will still be treated as modulemap-relative. +SWIFT_FEATURE_MODULE_HOME_IS_CWD = "swift.module_home_is_cwd" + # If enabled, compilation actions and module map generation will assume that the # header paths in module maps are relative to the current working directory # (i.e., the workspace root); if disabled, header paths in module maps are diff --git a/swift/toolchains/config/compile_config.bzl b/swift/toolchains/config/compile_config.bzl index 588b36ae7..63c237a3b 100644 --- a/swift/toolchains/config/compile_config.bzl +++ b/swift/toolchains/config/compile_config.bzl @@ -48,6 +48,7 @@ load( "SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX", "SWIFT_FEATURE_DISABLE_SYSTEM_INDEX", "SWIFT_FEATURE_EMIT_BC", + "SWIFT_FEATURE_EMIT_C_MODULE", "SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE", "SWIFT_FEATURE_EMIT_SWIFTDOC", "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", @@ -67,6 +68,7 @@ load( "SWIFT_FEATURE_INTERNALIZE_AT_LINK", "SWIFT_FEATURE_LAYERING_CHECK", "SWIFT_FEATURE_MODULAR_INDEXING", + "SWIFT_FEATURE_MODULE_HOME_IS_CWD", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_NO_ASAN_VERSION_CHECK", "SWIFT_FEATURE_OPT", @@ -658,6 +660,52 @@ def compile_action_configs( ], ), + # Explicitly set the working directory to ensure that the + # `FILE_SYSTEM_OPTIONS` block of PCM files is hermetic. + # + # IMPORTANT: When writing a PCM file, Clang *unconditionally* includes + # the working directory in the `FILE_SYSTEM_OPTIONS` block. Thus, the + # only way to ensure that these files are hermetic is to pass + # `-working-directory=.`. We cannot pass this to Swift, however, because + # the driver unfortunately resolves whatever path is given to it and + # then passes all of the source files as absolute paths to the + # frontend, which makes other outputs non-hermetic. Therefore, we *only* + # pass this flag to Clang. Having the two values not be literally + # identical should still be safe, because we're only passing a value + # here that is *effectively* the same as the default. + ActionConfigInfo( + actions = all_compile_action_names() + [ + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [ + add_arg("-Xcc", "-working-directory"), + add_arg("-Xcc", "."), + ], + features = [[ + SWIFT_FEATURE_EMIT_C_MODULE, + SWIFT_FEATURE_USE_C_MODULES, + SWIFT_FEATURE_MODULE_HOME_IS_CWD, + ]], + ), + # Treat paths embedded into .pcm files as workspace-relative, not + # modulemap-relative. + ActionConfigInfo( + actions = all_compile_action_names() + [ + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [ + add_arg("-Xcc", "-Xclang"), + add_arg("-Xcc", "-fmodule-file-home-is-cwd"), + ], + features = [[ + SWIFT_FEATURE_EMIT_C_MODULE, + SWIFT_FEATURE_USE_C_MODULES, + SWIFT_FEATURE_MODULE_HOME_IS_CWD, + ]], + ), + # Treat paths in .modulemap files as workspace-relative, not modulemap- # relative. ActionConfigInfo( @@ -1096,7 +1144,7 @@ def compile_action_configs( SWIFT_ACTION_PRECOMPILE_C_MODULE, ], configurators = [ - add_arg("-file-prefix-map", "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR"), + add_arg("-file-prefix-map", "__BAZEL_XCODE_DEVELOPER_DIR__=/PLACEHOLDER_DEVELOPER_DIR"), ], features = [SWIFT_FEATURE_FILE_PREFIX_MAP], ), diff --git a/swift/toolchains/xcode_swift_toolchain.bzl b/swift/toolchains/xcode_swift_toolchain.bzl index a7cdb456b..b6b8a1ed6 100644 --- a/swift/toolchains/xcode_swift_toolchain.bzl +++ b/swift/toolchains/xcode_swift_toolchain.bzl @@ -56,6 +56,7 @@ load( "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX", "SWIFT_FEATURE_FILE_PREFIX_MAP", + "SWIFT_FEATURE_MODULE_HOME_IS_CWD", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_REMAP_XCODE_PATH", "SWIFT_FEATURE__SUPPORTS_UPCOMING_FEATURES", @@ -708,7 +709,16 @@ def _xcode_swift_toolchain_impl(ctx): requested_features.append(SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX) if _is_xcode_at_least_version(xcode_config, "16.0"): - requested_features.append(SWIFT_FEATURE__SUPPORTS_V6) + requested_features.extend([ + SWIFT_FEATURE__SUPPORTS_V6, + # Ensure hermetic PCM files (no absolute workspace paths). This flag + # is actually supported on Xcode 15.x as well, but it's bugged; a + # `MODULE_DIRECTORY` field remains in the PCM file that has the + # absolute workspace path, so it's not hermetic, and worse, it + # causes other compilation errors in the unfortunately common case + # where two modules contain the same header. + SWIFT_FEATURE_MODULE_HOME_IS_CWD, + ]) unsupported_features = ctx.disabled_features + [ SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD, diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index 4788c331f..6610e589e 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -285,6 +285,24 @@ bool SwiftRunner::ProcessArgument( Iterator &itr, const std::string &arg, std::function consumer) { bool changed = false; + + // Helper function for adding path remapping flags that depend on information + // only known at execution time. + auto add_prefix_map_flags = [&](const std::string &flag) { + // Get the actual current working directory (the execution root), which + // we didn't know at analysis time. + consumer(flag); + consumer(std::filesystem::current_path().string() + "=."); + +#if __APPLE__ + std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"; + if (bazel_placeholder_substitutions_.Apply(developer_dir)) { + consumer(flag); + consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR"); + } +#endif + }; + if (arg[0] == '@') { changed = ProcessPossibleResponseFile(arg, consumer); } else { @@ -293,20 +311,17 @@ bool SwiftRunner::ProcessArgument( if (new_arg == "-debug-prefix-pwd-is-dot") { // Replace the $PWD with . to make the paths relative to the workspace // without breaking hermiticity. - consumer("-debug-prefix-map"); - consumer(std::filesystem::current_path().string() + "=."); + add_prefix_map_flags("-debug-prefix-map"); changed = true; } else if (new_arg == "-coverage-prefix-pwd-is-dot") { // Replace the $PWD with . to make the paths relative to the workspace // without breaking hermiticity. - consumer("-coverage-prefix-map"); - consumer(std::filesystem::current_path().string() + "=."); + add_prefix_map_flags("-file-prefix-map"); changed = true; } else if (new_arg == "-file-prefix-pwd-is-dot") { // Replace the $PWD with . to make the paths relative to the workspace // without breaking hermiticity. - consumer("-file-prefix-map"); - consumer(std::filesystem::current_path().string() + "=."); + add_prefix_map_flags("-file-prefix-map"); changed = true; } else if (StripPrefix("-macro-expansion-dir=", new_arg)) { changed = true;