Skip to content

Commit

Permalink
Add -ffile-prefix-map for deterministic C++ compilation
Browse files Browse the repository at this point in the history
Summary:
Previously, with some toolchains, the debuginfo in object files produced by `cxx_compile` actions contained absolute paths for headers in the toolchain's standard library. This affected xplat's `minimal_xcode` toolchain.

Different macOS RE runners do not necessarily all put the current directory in the same location when running actions, which introduced nondeterminism and wrecks cache utilization.

Reviewed By: rmaz

Differential Revision: D60678938

fbshipit-source-id: a8bfab64d39571a3bd5e7b3fb4ae16a977a7c3cf
  • Loading branch information
David Tolnay authored and facebook-github-bot committed Aug 3, 2024
1 parent b70b171 commit e27ef6c
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 6 deletions.
11 changes: 6 additions & 5 deletions cxx/compile.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -608,14 +608,15 @@ def _get_category(ext: CxxExtension) -> str:
# This should be unreachable as long as we handle all enum values
fail("Unknown extension: " + ext.value)

def _get_compile_base(compiler_info: typing.Any) -> cmd_args:
def _get_compile_base(toolchain: CxxToolchainInfo, compiler_info: typing.Any) -> cmd_args:
"""
Given a compiler info returned by _get_compiler_info, form the base compile args.
"""

cmd = cmd_args(compiler_info.compiler)

return cmd
if toolchain.remap_cwd and compiler_info.compiler_type in ["clang", "clang_windows", "clang_cl"]:
return cmd_args(toolchain.remap_cwd, compiler_info.compiler)
else:
return cmd_args(compiler_info.compiler)

def _dep_file_type(ext: CxxExtension) -> [DepFileType, None]:
# Raw assembly doesn't make sense to capture dep files for.
Expand Down Expand Up @@ -761,7 +762,7 @@ def _generate_base_compile_command(
"""
toolchain = get_cxx_toolchain_info(ctx)
compiler_info = _get_compiler_info(toolchain, ext)
base_compile_cmd = _get_compile_base(compiler_info)
base_compile_cmd = _get_compile_base(toolchain, compiler_info)
category = _get_category(ext)

headers_dep_files = None
Expand Down
3 changes: 3 additions & 0 deletions cxx/cxx_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ def cxx_toolchain_impl(ctx):
dumpbin_toolchain_path = ctx.attrs._dumpbin_toolchain_path[DefaultInfo].default_outputs[0] if ctx.attrs._dumpbin_toolchain_path else None,
target_sdk_version = get_toolchain_target_sdk_version(ctx),
dist_lto_tools_info = ctx.attrs.dist_lto_tools[DistLtoToolsInfo],
remap_cwd = ctx.attrs._remap_cwd_tool[RunInfo] if ctx.attrs.remap_cwd else None,
)

def cxx_toolchain_extra_attributes(is_toolchain_rule):
Expand Down Expand Up @@ -225,6 +226,7 @@ def cxx_toolchain_extra_attributes(is_toolchain_rule):
"public_headers_symlinks_enabled": attrs.bool(default = True),
"ranlib": attrs.option(dep_type(providers = [RunInfo]), default = None),
"rc_compiler": attrs.option(dep_type(providers = [RunInfo]), default = None),
"remap_cwd": attrs.bool(default = False),
"requires_objects": attrs.bool(default = False),
"sanitizer_runtime_enabled": attrs.bool(default = False),
"sanitizer_runtime_files": attrs.set(attrs.dep(), sorted = True, default = []), # Use `attrs.dep()` as it's not a tool, always propagate target platform
Expand Down Expand Up @@ -255,6 +257,7 @@ def cxx_toolchain_extra_attributes(is_toolchain_rule):
# FIXME: prelude// should be standalone (not refer to fbsource//)
"_mk_hmap": attrs.default_only(dep_type(providers = [RunInfo], default = "prelude//cxx/tools:hmap_wrapper")),
"_msvc_hermetic_exec": attrs.default_only(dep_type(providers = [RunInfo], default = "prelude//windows/tools:msvc_hermetic_exec")),
"_remap_cwd_tool": attrs.default_only(dep_type(providers = [RunInfo], default = "prelude//cxx/tools:remap_cwd")),
} | cxx_toolchain_allow_cache_upload_args()

def _cxx_toolchain_inheriting_target_platform_attrs():
Expand Down
5 changes: 4 additions & 1 deletion cxx/cxx_toolchain_types.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ CxxToolchainInfo = provider(
"pic_behavior": provider_field(typing.Any, default = None),
"dumpbin_toolchain_path": provider_field(typing.Any, default = None),
"target_sdk_version": provider_field([str, None], default = None),
"remap_cwd": provider_field(RunInfo | None, default = None),
},
)

Expand Down Expand Up @@ -257,7 +258,8 @@ def cxx_toolchain_infos(
platform_deps_aliases = [],
pic_behavior = PicBehavior("supported"),
dumpbin_toolchain_path = None,
target_sdk_version = None):
target_sdk_version = None,
remap_cwd = None):
"""
Creates the collection of cxx-toolchain Infos for a cxx toolchain.
Expand Down Expand Up @@ -301,6 +303,7 @@ def cxx_toolchain_infos(
pic_behavior = pic_behavior,
dumpbin_toolchain_path = dumpbin_toolchain_path,
target_sdk_version = target_sdk_version,
remap_cwd = remap_cwd,
)

# Provide placeholder mappings, used primarily by cxx_genrule.
Expand Down
6 changes: 6 additions & 0 deletions cxx/tools/BUCK.v2
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ prelude.python_bootstrap_binary(
visibility = ["PUBLIC"],
)

prelude.python_bootstrap_binary(
name = "remap_cwd",
main = "remap_cwd.py",
visibility = ["PUBLIC"],
)

# Required to support the $(cxx-header-tree) macro
cxx_hacks(
name = "cxx_hacks",
Expand Down
32 changes: 32 additions & 0 deletions cxx/tools/remap_cwd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.

"""
Usage: remap_cwd.py path/to/clang++ [args...]
Runs `path/to/clang++ -ffile-prefix-map=$PWD= [args...]`
"""

import os
import subprocess
import sys


if __name__ == "__main__":
cwd = os.getcwd()
# Add trailing slash
cwd = os.path.join(cwd, "")

ret = subprocess.call(
[
sys.argv[1],
f"-ffile-prefix-map={cwd}=",
*sys.argv[2:],
],
)
sys.exit(ret)

0 comments on commit e27ef6c

Please sign in to comment.