Skip to content

Commit d5277eb

Browse files
authored
Merge pull request #2691 from benesch/linux-binsize
build: reduce linux release binary size by 87%
2 parents 9e52887 + 02cc34c commit d5277eb

File tree

6 files changed

+48
-10
lines changed

6 files changed

+48
-10
lines changed

.cargo/config

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[target."x86_64-unknown-linux-gnu"]
2+
# Compressing debug information can yield hundreds of megabytes of savings.
3+
# The Rust toolchain does not currently perform dead code elimination on
4+
# debug info.
5+
#
6+
# See: https://github.com/rust-lang/rust/issues/56068
7+
# See: https://reviews.llvm.org/D74169#1990180
8+
rustflags = ["-C", "link-arg=-Wl,--compress-debug-sections=zlib-gabi"]

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
target
1313
miri-target
14-
/.cargo
1514
.mtrlz.log
1615
**/*.rs.bk
1716
.netlify

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ members = [
2323
]
2424

2525
[profile.release]
26-
debug = true
26+
# Emit only the line info tables, not full debug info, in release builds, to
27+
# substantially reduce the size of the debug info. Line info tables are enough
28+
# to correctly symbolicate a backtrace, but do not produce an ideal interactive
29+
# debugger experience. This seems to be the right tradeoff for release builds:
30+
# it's unlikely we're going to get interactive access to a debugger in
31+
# production installations, but we still want useful crash reports.
32+
debug = 1
2733

2834
[patch.crates-io]
2935
# Waiting on a release with this commit:

bin/lint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ copyright_files=$(grep -vE \
6060
-e '(^|/)\.gitmodules$' \
6161
-e '(^|/)go\.sum$' \
6262
-e '(^|/)Cargo\.toml$' \
63+
-e '^\.cargo/config$' \
6364
-e '^Cargo\.lock$' \
6465
-e '^deny\.toml$' \
6566
-e '^netlify\.toml$' \

bin/xcompile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
set -euo pipefail
1515

16-
root=$(dirname "$0")/..
16+
root=$(cd "$(dirname "$0")/.." && pwd)
1717

1818
# shellcheck source=SCRIPTDIR/../misc/shlib/shlib.bash
1919
. "$root/misc/shlib/shlib.bash"
@@ -61,6 +61,7 @@ do_cargo() {
6161
export TARGET_CXX=$CXX
6262
export TARGET_CFLAGS=$CFLAGS
6363
export TARGET_CXXFLAGS=$CXXFLAGS
64+
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=$CC
6465

6566
cargo "$subcommand" --target=x86_64-unknown-linux-gnu "$@"
6667
}

misc/python/mzbuild.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,15 @@ def xcargo_target_dir(root: Path) -> Path:
9898
return root / "target" / "x86_64-unknown-linux-gnu"
9999

100100

101-
def xstrip(root: Path) -> str:
101+
def xbinutil(tool: str) -> str:
102102
if sys.platform == "linux":
103-
return "strip"
103+
return tool
104104
else:
105-
return "x86_64-unknown-linux-gnu-strip"
105+
return f"x86_64-unknown-linux-gnu-{tool}"
106+
107+
108+
xobjcopy = xbinutil("objcopy")
109+
xstrip = xbinutil("strip")
106110

107111

108112
def docker_images() -> Set[str]:
@@ -157,13 +161,32 @@ def run(self, root: Path, path: Path) -> None:
157161
# down CI, since we're packaging these binaries up into Docker
158162
# images and shipping them around. A bit unfortunate, since it'd be
159163
# nice to have useful backtraces if the binary crashes.
160-
runv([xstrip(root), path / self.bin])
164+
runv([xstrip, path / self.bin])
165+
else:
166+
# Even if we've been asked not to strip the binary, remove the
167+
# `.debug_pubnames` and `.debug_pubtypes` sections. These are just
168+
# indexes that speed up launching a debugger against the binary,
169+
# and we're happy to have slower debugger start up in exchange for
170+
# smaller binaries. Plus the sections have been obsoleted by a
171+
# `.debug_names` section in DWARF 5, and so debugger support for
172+
# `.debug_pubnames`/`.debug_pubtypes` is minimal anyway.
173+
# See: https://github.com/rust-lang/rust/issues/46034
174+
runv(
175+
[
176+
xobjcopy,
177+
"-R",
178+
".debug_pubnames",
179+
"-R",
180+
".debug_pubtypes",
181+
path / self.bin,
182+
]
183+
)
161184

162185
def depends(self, root: Path, path: Path) -> List[bytes]:
163186
# TODO(benesch): this should be much smarter about computing the Rust
164187
# files that actually contribute to this binary target.
165188
return super().depends(root, path) + git_ls_files(
166-
root, "src/**", "Cargo.toml", "Cargo.lock"
189+
root, "src/**", "Cargo.toml", "Cargo.lock", ".cargo"
167190
)
168191

169192

@@ -216,7 +239,7 @@ def run(self, root: Path, path: Path) -> None:
216239
with open(path / "tests" / "manifest", "w") as manifest:
217240
for (executable, slug, crate_path) in tests:
218241
shutil.copy(executable, path / "tests" / slug)
219-
runv([xstrip(root), path / "tests" / slug])
242+
runv([xstrip, path / "tests" / slug])
220243
manifest.write(f"{slug} {crate_path}\n")
221244
shutil.move(str(path / "testdrive"), path / "tests")
222245
shutil.copy(
@@ -229,7 +252,7 @@ def depends(self, root: Path, path: Path) -> List[bytes]:
229252
# TODO(benesch): this should be much smarter about computing the Rust
230253
# files that actually contribute to this binary target.
231254
return super().depends(root, path) + git_ls_files(
232-
root, "src/**", "Cargo.toml", "Cargo.lock"
255+
root, "src/**", "Cargo.toml", "Cargo.lock", ".cargo"
233256
)
234257

235258

0 commit comments

Comments
 (0)