blob: 7fc23db9be2b1fd3076ec5e9b136ce1fefef2665 [file] [log] [blame]
From 01a53a95a8fa20f2bf5ec6357baa457e7b2bc9f2 Mon Sep 17 00:00:00 2001
From: Tim Windelschmidt <tim@monogon.tech>
Date: Fri, 12 Jan 2024 15:44:41 +0100
Subject: [PATCH] Improve reproducibility
Fixes a few issues with rules_rust/rustc reproducibility when the same code is
being built in slightly different BuildConfigurations.
Even if BuildConfigurations differ only by insignificant (to rules_rust)
configuration flags, the resulting output directory will be different (keyed by
an 'ST-hash' which is generated from the configuration).
Unfortunately, rust/rules_rust really likes to embed bazel-out/<dir>/bin paths
into the binaries by default, thus embedding the ST-hash, thus leading to
different bit-for-bit binaries when built across two slightly different
configs.
We fix this by doing two changes:
1. We override the codegen metadata hash suffix to not depend on the ST-hash
directory name. Otherwise, built rlibs will have a numeric .XXX suffix that
changes depending on the ST-hash. We have to do this separately for prost
codegen, too.
2. We add a remap path option to rustc that replaces bazel-out/<dir>/bin/ with
bin/.
---
proto/prost/private/prost.bzl | 4 +++-
proto/protobuf/proto.bzl | 2 +-
rust/private/clippy.bzl | 2 +-
rust/private/rust.bzl | 6 +++---
rust/private/rustc.bzl | 4 ++++
rust/private/utils.bzl | 7 +++++--
6 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/proto/prost/private/prost.bzl b/proto/prost/private/prost.bzl
index 38bd7b4f..645a520f 100644
--- a/proto/prost/private/prost.bzl
+++ b/proto/prost/private/prost.bzl
@@ -131,7 +131,8 @@ def _compile_rust(ctx, attr, crate_name, src, deps, edition):
A DepVariantInfo provider.
"""
toolchain = ctx.toolchains["@rules_rust//rust:toolchain_type"]
- output_hash = repr(hash(src.path + ".prost"))
+ src_path = src.path.replace(ctx.bin_dir.path, 'bin')
+ output_hash = repr(hash(src_path + ".prost"))
lib_name = "{prefix}{name}-{lib_hash}{extension}".format(
prefix = "lib",
diff --git a/proto/protobuf/proto.bzl b/proto/protobuf/proto.bzl
index 959d0c1c..00dff5d0 100644
--- a/proto/protobuf/proto.bzl
+++ b/proto/protobuf/proto.bzl
@@ -187,7 +187,7 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr
srcs.append(lib_rs)
# And simulate rust_library behavior
- output_hash = determine_output_hash(lib_rs, ctx.label)
+ output_hash = determine_output_hash(ctx.bin_dir, lib_rs, ctx.label)
rust_lib = ctx.actions.declare_file("%s/lib%s-%s.rlib" % (
output_dir,
crate_name,
diff --git a/rust/private/clippy.bzl b/rust/private/clippy.bzl
index ef3ec2f8..cab2e6bf 100644
--- a/rust/private/clippy.bzl
+++ b/rust/private/clippy.bzl
@@ -132,7 +132,7 @@ def _clippy_aspect_impl(target, ctx):
dep_info = dep_info,
linkstamp_outs = linkstamp_outs,
ambiguous_libs = ambiguous_libs,
- output_hash = determine_output_hash(crate_info.root, ctx.label),
+ output_hash = determine_output_hash(ctx.bin_dir, crate_info.root, ctx.label),
rust_flags = [],
out_dir = out_dir,
build_env_files = build_env_files,
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index afe1f129..ee73ee44 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -159,7 +159,7 @@ def _rust_library_common(ctx, crate_type):
if crate_type in ["cdylib", "staticlib"]:
output_hash = None
else:
- output_hash = determine_output_hash(crate_root, ctx.label)
+ output_hash = determine_output_hash(ctx.bin_dir, crate_root, ctx.label)
rust_lib_name = determine_lib_name(
crate_name,
@@ -309,7 +309,7 @@ def _rust_test_impl(ctx):
# Target is building the crate in `test` config
crate = ctx.attr.crate[rust_common.crate_info] if rust_common.crate_info in ctx.attr.crate else ctx.attr.crate[rust_common.test_crate_info].crate
- output_hash = determine_output_hash(crate.root, ctx.label)
+ output_hash = determine_output_hash(ctx.bin_dir, crate.root, ctx.label)
output = ctx.actions.declare_file(
"test-%s/%s%s" % (
output_hash,
@@ -368,7 +368,7 @@ def _rust_test_impl(ctx):
crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, crate_root_type)
srcs, crate_root = transform_sources(ctx, ctx.files.srcs, crate_root)
- output_hash = determine_output_hash(crate_root, ctx.label)
+ output_hash = determine_output_hash(ctx.bin_dir, crate_root, ctx.label)
output = ctx.actions.declare_file(
"test-%s/%s%s" % (
output_hash,
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 6dbb258b..bb5e0b05 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -965,6 +965,10 @@ def construct_arguments(
if remap_path_prefix != None:
rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix))
+ # Replace unstable bindir path (based on ST-hash which is in turn based on
+ # build configuration) with a stable bin/ path.
+ rustc_flags.add("--remap-path-prefix={}=bin".format(ctx.bin_dir.path))
+
emit_without_paths = []
for kind in emit:
if kind == "link" and crate_info.type == "bin" and crate_info.output != None:
diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl
index 57a3fe7a..315f45b6 100644
--- a/rust/private/utils.bzl
+++ b/rust/private/utils.bzl
@@ -186,7 +186,7 @@ def abs(value):
return -value
return value
-def determine_output_hash(crate_root, label):
+def determine_output_hash(bin_dir, crate_root, label):
"""Generates a hash of the crate root file's path.
Args:
@@ -197,8 +197,11 @@ def determine_output_hash(crate_root, label):
str: A string representation of the hash.
"""
+ # Remove any unstable BuildConfiguration derived dir fragments to unify
+ # hashes between different configs.
+ crate_root_path = crate_root.path.replace(bin_dir.path, 'bin')
# Take the absolute value of hash() since it could be negative.
- h = abs(hash(crate_root.path) + hash(repr(label)))
+ h = abs(hash(crate_root_path) + hash(repr(label)))
return repr(h)
def get_preferred_artifact(library_to_link, use_pic):
--
2.44.1