Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 86d1678

Browse files
committedApr 3, 2019
Support using LLVM's libunwind as the unwinder implementation
This avoids the dependency on host libraries such as libgcc_s which may be undesirable in some deployment environments where these aren't available.
1 parent f8673e0 commit 86d1678

File tree

9 files changed

+89
-2
lines changed

9 files changed

+89
-2
lines changed
 

‎Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3849,6 +3849,7 @@ dependencies = [
38493849
name = "unwind"
38503850
version = "0.0.0"
38513851
dependencies = [
3852+
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
38523853
"compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
38533854
"core 0.0.0",
38543855
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",

‎config.toml.example

+3
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,9 @@
421421
# development of NLL
422422
#test-compare-mode = false
423423

424+
# Use LLVM libunwind as the implementation for Rust's unwinder.
425+
#llvm-libunwind = false
426+
424427
# =============================================================================
425428
# Options for specific targets
426429
#

‎src/bootstrap/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub struct Config {
4848
pub exclude: Vec<PathBuf>,
4949
pub rustc_error_format: Option<String>,
5050
pub test_compare_mode: bool,
51+
pub llvm_libunwind: bool,
5152

5253
pub run_host_only: bool,
5354

@@ -329,6 +330,7 @@ struct Rust {
329330
remap_debuginfo: Option<bool>,
330331
jemalloc: Option<bool>,
331332
test_compare_mode: Option<bool>,
333+
llvm_libunwind: Option<bool>,
332334
}
333335

334336
/// TOML representation of how each build target is configured.
@@ -548,6 +550,7 @@ impl Config {
548550
set(&mut config.rust_rpath, rust.rpath);
549551
set(&mut config.jemalloc, rust.jemalloc);
550552
set(&mut config.test_compare_mode, rust.test_compare_mode);
553+
set(&mut config.llvm_libunwind, rust.llvm_libunwind);
551554
set(&mut config.backtrace, rust.backtrace);
552555
set(&mut config.channel, rust.channel.clone());
553556
set(&mut config.rust_dist_src, rust.dist_src);

‎src/bootstrap/configure.py

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def v(*args):
6868
o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")
6969
o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")
7070

71+
o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind")
72+
7173
# Optimization and debugging options. These may be overridden by the release
7274
# channel, etc.
7375
o("optimize", "rust.optimize", "build optimized rust code")

‎src/bootstrap/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ impl Build {
506506
fn std_features(&self) -> String {
507507
let mut features = "panic-unwind".to_string();
508508

509+
if self.config.llvm_libunwind {
510+
features.push_str(" llvm-libunwind");
511+
}
509512
if self.config.backtrace {
510513
features.push_str(" backtrace");
511514
}

‎src/libstd/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ backtrace = ["backtrace-sys"]
5454
panic-unwind = ["panic_unwind"]
5555
profiler = ["profiler_builtins"]
5656
compiler_builtins_c = ["compiler_builtins/c"]
57+
llvm-libunwind = ["unwind/llvm-libunwind"]
5758

5859
# Make panics and failed asserts immediately abort without formatting any message
5960
panic_immediate_abort = ["core/panic_immediate_abort"]

‎src/libunwind/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ name = "unwind"
44
version = "0.0.0"
55
build = "build.rs"
66
edition = "2018"
7+
include = [
8+
'/libunwind/*',
9+
]
710

811
[lib]
912
name = "unwind"
@@ -16,3 +19,9 @@ doc = false
1619
core = { path = "../libcore" }
1720
libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false }
1821
compiler_builtins = "0.1.0"
22+
23+
[build-dependencies]
24+
cc = { optional = true, version = "1.0.1" }
25+
26+
[features]
27+
llvm-libunwind = ["cc"]

‎src/libunwind/build.rs

+66-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ fn main() {
44
println!("cargo:rerun-if-changed=build.rs");
55
let target = env::var("TARGET").expect("TARGET was not set");
66

7-
if target.contains("linux") {
7+
if cfg!(feature = "llvm-libunwind") &&
8+
(target.contains("linux") ||
9+
target.contains("fuchsia")) {
10+
// Build the unwinding from libunwind C/C++ source code.
11+
#[cfg(feature = "llvm-libunwind")]
12+
llvm_libunwind::compile();
13+
} else if target.contains("linux") {
814
if target.contains("musl") {
915
// musl is handled in lib.rs
1016
} else if !target.contains("android") {
@@ -37,3 +43,62 @@ fn main() {
3743
println!("cargo:rustc-link-lib=unwind");
3844
}
3945
}
46+
47+
#[cfg(feature = "llvm-libunwind")]
48+
mod llvm_libunwind {
49+
use std::env;
50+
use std::path::Path;
51+
52+
/// Compile the libunwind C/C++ source code.
53+
pub fn compile() {
54+
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
55+
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
56+
let cfg = &mut cc::Build::new();
57+
58+
cfg.cpp(true);
59+
cfg.cpp_set_stdlib(None);
60+
cfg.warnings(false);
61+
62+
if target_env == "msvc" {
63+
// Don't pull in extra libraries on MSVC
64+
cfg.flag("/Zl");
65+
cfg.flag("/EHsc");
66+
cfg.define("_CRT_SECURE_NO_WARNINGS", None);
67+
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
68+
} else {
69+
cfg.flag("-std=c99");
70+
cfg.flag("-std=c++11");
71+
cfg.flag("-nostdinc++");
72+
if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() &&
73+
cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() {
74+
cfg.flag("-funwind-tables");
75+
cfg.flag("-fno-exceptions");
76+
}
77+
cfg.flag("-fno-rtti");
78+
cfg.flag("-fstrict-aliasing");
79+
}
80+
81+
let mut unwind_sources = vec![
82+
"Unwind-EHABI.cpp",
83+
"Unwind-seh.cpp",
84+
"Unwind-sjlj.c",
85+
"UnwindLevel1-gcc-ext.c",
86+
"UnwindLevel1.c",
87+
"UnwindRegistersRestore.S",
88+
"UnwindRegistersSave.S",
89+
"libunwind.cpp",
90+
];
91+
92+
if target_vendor == "apple" {
93+
unwind_sources.push("Unwind_AppleExtras.cpp");
94+
}
95+
96+
let root = Path::new("../llvm-project/libunwind");
97+
cfg.include(root.join("include"));
98+
for src in unwind_sources {
99+
cfg.file(root.join("src").join(src));
100+
}
101+
102+
cfg.compile("unwind");
103+
}
104+
}

1 commit comments

Comments
 (1)

AdrianCX commented on Apr 17, 2020

@AdrianCX
Contributor

A question on llvm_libunwind::compile

  • Does using 'build.rs' skip the 'CMakeLists.txt' from libunwind
  • If yes - isn't this duplication - with problem being that changes to external CMakeLists.txt will need to be duplicated here - or have weird issues after upgrades?
Please sign in to comment.