feat: Strip debug info from opt builds (#2513)
Attempts to follow the cargo proposal linked below to remove debug info
for release builds. Furthermore this should uphold the expected behavior
of bazel for cc builds which automatically strips debug symbols for
optimized builds.
https://github.com/rust-lang/cargo/issues/4122#issuecomment-1868318860
diff --git a/docs/flatten.md b/docs/flatten.md
index 398e365..632ba74 100644
--- a/docs/flatten.md
+++ b/docs/flatten.md
@@ -1179,7 +1179,7 @@
<a href="#rust_toolchain-experimental_use_cc_common_link">experimental_use_cc_common_link</a>, <a href="#rust_toolchain-extra_exec_rustc_flags">extra_exec_rustc_flags</a>, <a href="#rust_toolchain-extra_rustc_flags">extra_rustc_flags</a>,
<a href="#rust_toolchain-extra_rustc_flags_for_crate_types">extra_rustc_flags_for_crate_types</a>, <a href="#rust_toolchain-global_allocator_library">global_allocator_library</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>,
<a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-per_crate_rustc_flags">per_crate_rustc_flags</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>,
- <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
+ <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-strip_level">strip_level</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
</pre>
Declares a Rust toolchain for use.
@@ -1259,6 +1259,7 @@
| <a id="rust_toolchain-rustfmt"></a>rustfmt | **Deprecated**: Instead see [rustfmt_toolchain](#rustfmt_toolchain) | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
| <a id="rust_toolchain-staticlib_ext"></a>staticlib_ext | The extension for static libraries created from rustc. | String | required | |
| <a id="rust_toolchain-stdlib_linkflags"></a>stdlib_linkflags | Additional linker flags to use when Rust standard library is linked by a C++ linker (rustc will deal with these automatically). Subject to location expansion with respect to the srcs of the <code>rust_std</code> attribute. | List of strings | required | |
+| <a id="rust_toolchain-strip_level"></a>strip_level | Rustc strip levels. For all potential options, see https://doc.rust-lang.org/rustc/codegen-options/index.html#strip | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{"dbg": "none", "fastbuild": "none", "opt": "debuginfo"}</code> |
| <a id="rust_toolchain-target_json"></a>target_json | Override the target_triple with a custom target specification. For more details see: https://doc.rust-lang.org/rustc/targets/custom.html | String | optional | <code>""</code> |
| <a id="rust_toolchain-target_triple"></a>target_triple | The platform triple for the toolchains target environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | optional | <code>""</code> |
diff --git a/docs/rust_repositories.md b/docs/rust_repositories.md
index f3129e2..7644c86 100644
--- a/docs/rust_repositories.md
+++ b/docs/rust_repositories.md
@@ -41,7 +41,7 @@
<a href="#rust_toolchain-experimental_use_cc_common_link">experimental_use_cc_common_link</a>, <a href="#rust_toolchain-extra_exec_rustc_flags">extra_exec_rustc_flags</a>, <a href="#rust_toolchain-extra_rustc_flags">extra_rustc_flags</a>,
<a href="#rust_toolchain-extra_rustc_flags_for_crate_types">extra_rustc_flags_for_crate_types</a>, <a href="#rust_toolchain-global_allocator_library">global_allocator_library</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>,
<a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-per_crate_rustc_flags">per_crate_rustc_flags</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>,
- <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
+ <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-strip_level">strip_level</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
</pre>
Declares a Rust toolchain for use.
@@ -121,6 +121,7 @@
| <a id="rust_toolchain-rustfmt"></a>rustfmt | **Deprecated**: Instead see [rustfmt_toolchain](#rustfmt_toolchain) | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
| <a id="rust_toolchain-staticlib_ext"></a>staticlib_ext | The extension for static libraries created from rustc. | String | required | |
| <a id="rust_toolchain-stdlib_linkflags"></a>stdlib_linkflags | Additional linker flags to use when Rust standard library is linked by a C++ linker (rustc will deal with these automatically). Subject to location expansion with respect to the srcs of the <code>rust_std</code> attribute. | List of strings | required | |
+| <a id="rust_toolchain-strip_level"></a>strip_level | Rustc strip levels. For all potential options, see https://doc.rust-lang.org/rustc/codegen-options/index.html#strip | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{"dbg": "none", "fastbuild": "none", "opt": "debuginfo"}</code> |
| <a id="rust_toolchain-target_json"></a>target_json | Override the target_triple with a custom target specification. For more details see: https://doc.rust-lang.org/rustc/targets/custom.html | String | optional | <code>""</code> |
| <a id="rust_toolchain-target_triple"></a>target_triple | The platform triple for the toolchains target environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | optional | <code>""</code> |
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index f6f632d..6fdc7b9 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -959,6 +959,7 @@
compilation_mode = get_compilation_mode_opts(ctx, toolchain)
rustc_flags.add(compilation_mode.opt_level, format = "--codegen=opt-level=%s")
rustc_flags.add(compilation_mode.debug_info, format = "--codegen=debuginfo=%s")
+ rustc_flags.add(compilation_mode.strip_level, format = "--codegen=strip=%s")
# For determinism to help with build distribution and such
if remap_path_prefix != None:
@@ -1288,12 +1289,15 @@
if rustc_output:
action_outputs.append(rustc_output)
+ # Get the compilation mode for the current target.
+ compilation_mode = get_compilation_mode_opts(ctx, toolchain)
+
# Rustc generates a pdb file (on Windows) or a dsym folder (on macos) so provide it in an output group for crate
# types that benefit from having debug information in a separate file.
pdb_file = None
dsym_folder = None
if crate_info.type in ("cdylib", "bin"):
- if toolchain.target_os == "windows":
+ if toolchain.target_os == "windows" and compilation_mode.strip_level == "none":
pdb_file = ctx.actions.declare_file(crate_info.output.basename[:-len(crate_info.output.extension)] + "pdb", sibling = crate_info.output)
action_outputs.append(pdb_file)
elif toolchain.target_os == "darwin":
diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl
index 36c42b7..9591fe2 100644
--- a/rust/toolchain.bzl
+++ b/rust/toolchain.bzl
@@ -490,11 +490,13 @@
list: A list containing the target's toolchain Provider info
"""
compilation_mode_opts = {}
- for k, v in ctx.attr.opt_level.items():
+ for k, opt_level in ctx.attr.opt_level.items():
if not k in ctx.attr.debug_info:
fail("Compilation mode {} is not defined in debug_info but is defined opt_level".format(k))
- compilation_mode_opts[k] = struct(debug_info = ctx.attr.debug_info[k], opt_level = v)
- for k, v in ctx.attr.debug_info.items():
+ if not k in ctx.attr.strip_level:
+ fail("Compilation mode {} is not defined in strip_level but is defined opt_level".format(k))
+ compilation_mode_opts[k] = struct(debug_info = ctx.attr.debug_info[k], opt_level = opt_level, strip_level = ctx.attr.strip_level[k])
+ for k in ctx.attr.debug_info.keys():
if not k in ctx.attr.opt_level:
fail("Compilation mode {} is not defined in opt_level but is defined debug_info".format(k))
@@ -817,6 +819,17 @@
),
mandatory = True,
),
+ "strip_level": attr.string_dict(
+ doc = (
+ "Rustc strip levels. For all potential options, see " +
+ "https://doc.rust-lang.org/rustc/codegen-options/index.html#strip"
+ ),
+ default = {
+ "dbg": "none",
+ "fastbuild": "none",
+ "opt": "debuginfo",
+ },
+ ),
"target_json": attr.string(
doc = ("Override the target_triple with a custom target specification. " +
"For more details see: https://doc.rust-lang.org/rustc/targets/custom.html"),
diff --git a/test/unit/debug_info/debug_info_analysis_test.bzl b/test/unit/debug_info/debug_info_analysis_test.bzl
index 361640d..ad5bbf6 100644
--- a/test/unit/debug_info/debug_info_analysis_test.bzl
+++ b/test/unit/debug_info/debug_info_analysis_test.bzl
@@ -3,18 +3,59 @@
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//rust:defs.bzl", "rust_binary", "rust_shared_library", "rust_test")
-def _pdb_file_test_impl(ctx):
+def _pdb_file_test_impl(ctx, expect_pdb_file):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)
-
files = target[DefaultInfo].files.to_list()
+
+ if not expect_pdb_file:
+ asserts.equals(env, len(files), 0)
+ return analysistest.end(env)
+
asserts.equals(env, len(files), 1)
file = files[0]
asserts.equals(env, file.extension, "pdb")
-
return analysistest.end(env)
-pdb_file_test = analysistest.make(_pdb_file_test_impl)
+def _pdb_file_for_dbg_test_impl(ctx):
+ """Test for dbg compilation mode."""
+ return _pdb_file_test_impl(ctx, True)
+
+pdb_file_dbg_test = analysistest.make(
+ _pdb_file_for_dbg_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "dbg",
+ },
+)
+
+def _pdb_file_for_fastbuild_test_impl(ctx):
+ """Test for fastbuild compilation mode."""
+ return _pdb_file_test_impl(ctx, True)
+
+pdb_file_fastbuild_test = analysistest.make(
+ _pdb_file_for_fastbuild_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "fastbuild",
+ },
+)
+
+def _pdb_file_for_opt_test_impl(ctx):
+ """Test for opt compilation mode."""
+ return _pdb_file_test_impl(ctx, False)
+
+pdb_file_opt_test = analysistest.make(
+ _pdb_file_for_opt_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "opt",
+ },
+)
+
+# Mapping from compilation mode to pdb file test.
+pdb_file_tests = {
+ "dbg": pdb_file_dbg_test,
+ "fastbuild": pdb_file_fastbuild_test,
+ "opt": pdb_file_opt_test,
+}
def _dsym_folder_test_impl(ctx):
env = analysistest.begin(ctx)
@@ -47,11 +88,12 @@
output_group = "pdb_file",
)
- pdb_file_test(
- name = "lib_pdb_test",
- target_under_test = ":mylib.pdb",
- target_compatible_with = ["@platforms//os:windows"],
- )
+ for compilation_mode, pdb_test in pdb_file_tests.items():
+ pdb_test(
+ name = "lib_pdb_test_{}".format(compilation_mode),
+ target_under_test = ":mylib.pdb",
+ target_compatible_with = ["@platforms//os:windows"],
+ )
native.filegroup(
name = "mylib.dSYM",
@@ -77,11 +119,12 @@
output_group = "pdb_file",
)
- pdb_file_test(
- name = "bin_pdb_test",
- target_under_test = ":mybin.pdb",
- target_compatible_with = ["@platforms//os:windows"],
- )
+ for compilation_mode, pdb_test in pdb_file_tests.items():
+ pdb_test(
+ name = "bin_pdb_test_{}".format(compilation_mode),
+ target_under_test = ":mybin.pdb",
+ target_compatible_with = ["@platforms//os:windows"],
+ )
native.filegroup(
name = "mybin.dSYM",
@@ -108,11 +151,12 @@
testonly = True,
)
- pdb_file_test(
- name = "test_pdb_test",
- target_under_test = ":mytest.pdb",
- target_compatible_with = ["@platforms//os:windows"],
- )
+ for compilation_mode, pdb_test in pdb_file_tests.items():
+ pdb_test(
+ name = "test_pdb_test_{}".format(compilation_mode),
+ target_under_test = ":mytest.pdb",
+ target_compatible_with = ["@platforms//os:windows"],
+ )
native.filegroup(
name = "mytest.dSYM",
@@ -130,11 +174,17 @@
native.test_suite(
name = name,
tests = [
- ":lib_pdb_test",
":lib_dsym_test",
- ":bin_pdb_test",
":bin_dsym_test",
- ":test_pdb_test",
":test_dsym_test",
+ ] + [
+ ":lib_pdb_test_{}".format(compilation_mode)
+ for compilation_mode in pdb_file_tests
+ ] + [
+ ":bin_pdb_test_{}".format(compilation_mode)
+ for compilation_mode in pdb_file_tests
+ ] + [
+ ":test_pdb_test_{}".format(compilation_mode)
+ for compilation_mode in pdb_file_tests
],
)
diff --git a/test/unit/strip_level/BUILD.bazel b/test/unit/strip_level/BUILD.bazel
new file mode 100644
index 0000000..d342c6a
--- /dev/null
+++ b/test/unit/strip_level/BUILD.bazel
@@ -0,0 +1,5 @@
+load(":strip_level_test_suite.bzl", "strip_level_test_suite")
+
+strip_level_test_suite(
+ name = "strip_level_test_suite",
+)
diff --git a/test/unit/strip_level/strip_level_test_suite.bzl b/test/unit/strip_level/strip_level_test_suite.bzl
new file mode 100644
index 0000000..a4b6b30
--- /dev/null
+++ b/test/unit/strip_level/strip_level_test_suite.bzl
@@ -0,0 +1,95 @@
+"""Starlark tests for `rust_toolchain.strip_level`"""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest")
+load("@bazel_skylib//rules:write_file.bzl", "write_file")
+load("//rust:defs.bzl", "rust_binary")
+load(
+ "//test/unit:common.bzl",
+ "assert_action_mnemonic",
+ "assert_argv_contains",
+)
+
+def _strip_level_test_impl(ctx, expected_level):
+ env = analysistest.begin(ctx)
+ target = analysistest.target_under_test(env)
+
+ action = target.actions[0]
+ assert_action_mnemonic(env, action, "Rustc")
+
+ assert_argv_contains(env, action, "--codegen=strip={}".format(expected_level))
+ return analysistest.end(env)
+
+def _strip_level_for_dbg_test_impl(ctx):
+ return _strip_level_test_impl(ctx, "none")
+
+_strip_level_for_dbg_test = analysistest.make(
+ _strip_level_for_dbg_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "dbg",
+ },
+)
+
+def _strip_level_for_fastbuild_test_impl(ctx):
+ return _strip_level_test_impl(ctx, "none")
+
+_strip_level_for_fastbuild_test = analysistest.make(
+ _strip_level_for_fastbuild_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "fastbuild",
+ },
+)
+
+def _strip_level_for_opt_test_impl(ctx):
+ return _strip_level_test_impl(ctx, "debuginfo")
+
+_strip_level_for_opt_test = analysistest.make(
+ _strip_level_for_opt_test_impl,
+ config_settings = {
+ "//command_line_option:compilation_mode": "opt",
+ },
+)
+
+def strip_level_test_suite(name):
+ """Entry-point macro called from the BUILD file.
+
+ Args:
+ name (str): The name of the test suite.
+ """
+ write_file(
+ name = "bin_main",
+ out = "main.rs",
+ content = [
+ "fn main() {}",
+ "",
+ ],
+ )
+
+ rust_binary(
+ name = "bin",
+ srcs = [":main.rs"],
+ edition = "2021",
+ )
+
+ _strip_level_for_dbg_test(
+ name = "strip_level_for_dbg_test",
+ target_under_test = ":bin",
+ )
+
+ _strip_level_for_fastbuild_test(
+ name = "strip_level_for_fastbuild_test",
+ target_under_test = ":bin",
+ )
+
+ _strip_level_for_opt_test(
+ name = "strip_level_for_opt_test",
+ target_under_test = ":bin",
+ )
+
+ native.test_suite(
+ name = name,
+ tests = [
+ ":strip_level_for_dbg_test",
+ ":strip_level_for_fastbuild_test",
+ ":strip_level_for_opt_test",
+ ],
+ )