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.
This commit is contained in:
Petr Hosek 2019-03-10 19:27:59 -07:00
parent f8673e0ad8
commit 86d1678403
9 changed files with 89 additions and 2 deletions

View file

@ -3849,6 +3849,7 @@ dependencies = [
name = "unwind" name = "unwind"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0", "core 0.0.0",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -421,6 +421,9 @@
# development of NLL # development of NLL
#test-compare-mode = false #test-compare-mode = false
# Use LLVM libunwind as the implementation for Rust's unwinder.
#llvm-libunwind = false
# ============================================================================= # =============================================================================
# Options for specific targets # Options for specific targets
# #

View file

@ -48,6 +48,7 @@ pub struct Config {
pub exclude: Vec<PathBuf>, pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>, pub rustc_error_format: Option<String>,
pub test_compare_mode: bool, pub test_compare_mode: bool,
pub llvm_libunwind: bool,
pub run_host_only: bool, pub run_host_only: bool,
@ -329,6 +330,7 @@ struct Rust {
remap_debuginfo: Option<bool>, remap_debuginfo: Option<bool>,
jemalloc: Option<bool>, jemalloc: Option<bool>,
test_compare_mode: Option<bool>, test_compare_mode: Option<bool>,
llvm_libunwind: Option<bool>,
} }
/// TOML representation of how each build target is configured. /// TOML representation of how each build target is configured.
@ -548,6 +550,7 @@ impl Config {
set(&mut config.rust_rpath, rust.rpath); set(&mut config.rust_rpath, rust.rpath);
set(&mut config.jemalloc, rust.jemalloc); set(&mut config.jemalloc, rust.jemalloc);
set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.test_compare_mode, rust.test_compare_mode);
set(&mut config.llvm_libunwind, rust.llvm_libunwind);
set(&mut config.backtrace, rust.backtrace); set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel.clone()); set(&mut config.channel, rust.channel.clone());
set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.rust_dist_src, rust.dist_src);

View file

@ -68,6 +68,8 @@ o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags")
o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")
o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags") o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")
o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind")
# Optimization and debugging options. These may be overridden by the release # Optimization and debugging options. These may be overridden by the release
# channel, etc. # channel, etc.
o("optimize", "rust.optimize", "build optimized rust code") o("optimize", "rust.optimize", "build optimized rust code")

View file

@ -506,6 +506,9 @@ impl Build {
fn std_features(&self) -> String { fn std_features(&self) -> String {
let mut features = "panic-unwind".to_string(); let mut features = "panic-unwind".to_string();
if self.config.llvm_libunwind {
features.push_str(" llvm-libunwind");
}
if self.config.backtrace { if self.config.backtrace {
features.push_str(" backtrace"); features.push_str(" backtrace");
} }

View file

@ -54,6 +54,7 @@ backtrace = ["backtrace-sys"]
panic-unwind = ["panic_unwind"] panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"] profiler = ["profiler_builtins"]
compiler_builtins_c = ["compiler_builtins/c"] compiler_builtins_c = ["compiler_builtins/c"]
llvm-libunwind = ["unwind/llvm-libunwind"]
# Make panics and failed asserts immediately abort without formatting any message # Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = ["core/panic_immediate_abort"] panic_immediate_abort = ["core/panic_immediate_abort"]

View file

@ -4,6 +4,9 @@ name = "unwind"
version = "0.0.0" version = "0.0.0"
build = "build.rs" build = "build.rs"
edition = "2018" edition = "2018"
include = [
'/libunwind/*',
]
[lib] [lib]
name = "unwind" name = "unwind"
@ -16,3 +19,9 @@ doc = false
core = { path = "../libcore" } core = { path = "../libcore" }
libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false } libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false }
compiler_builtins = "0.1.0" compiler_builtins = "0.1.0"
[build-dependencies]
cc = { optional = true, version = "1.0.1" }
[features]
llvm-libunwind = ["cc"]

View file

@ -4,7 +4,13 @@ fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set"); let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("linux") { if cfg!(feature = "llvm-libunwind") &&
(target.contains("linux") ||
target.contains("fuchsia")) {
// Build the unwinding from libunwind C/C++ source code.
#[cfg(feature = "llvm-libunwind")]
llvm_libunwind::compile();
} else if target.contains("linux") {
if target.contains("musl") { if target.contains("musl") {
// musl is handled in lib.rs // musl is handled in lib.rs
} else if !target.contains("android") { } else if !target.contains("android") {
@ -37,3 +43,62 @@ fn main() {
println!("cargo:rustc-link-lib=unwind"); println!("cargo:rustc-link-lib=unwind");
} }
} }
#[cfg(feature = "llvm-libunwind")]
mod llvm_libunwind {
use std::env;
use std::path::Path;
/// Compile the libunwind C/C++ source code.
pub fn compile() {
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
let cfg = &mut cc::Build::new();
cfg.cpp(true);
cfg.cpp_set_stdlib(None);
cfg.warnings(false);
if target_env == "msvc" {
// Don't pull in extra libraries on MSVC
cfg.flag("/Zl");
cfg.flag("/EHsc");
cfg.define("_CRT_SECURE_NO_WARNINGS", None);
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
} else {
cfg.flag("-std=c99");
cfg.flag("-std=c++11");
cfg.flag("-nostdinc++");
if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() &&
cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() {
cfg.flag("-funwind-tables");
cfg.flag("-fno-exceptions");
}
cfg.flag("-fno-rtti");
cfg.flag("-fstrict-aliasing");
}
let mut unwind_sources = vec![
"Unwind-EHABI.cpp",
"Unwind-seh.cpp",
"Unwind-sjlj.c",
"UnwindLevel1-gcc-ext.c",
"UnwindLevel1.c",
"UnwindRegistersRestore.S",
"UnwindRegistersSave.S",
"libunwind.cpp",
];
if target_vendor == "apple" {
unwind_sources.push("Unwind_AppleExtras.cpp");
}
let root = Path::new("../llvm-project/libunwind");
cfg.include(root.join("include"));
for src in unwind_sources {
cfg.file(root.join("src").join(src));
}
cfg.compile("unwind");
}
}

@ -1 +1 @@
Subproject commit 1f484cbe0e863e9e215f1b3d7198063444d60873 Subproject commit 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c85