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"
version = "0.0.0"
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)",
"core 0.0.0",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",

View File

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

View File

@ -48,6 +48,7 @@ pub struct Config {
pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>,
pub test_compare_mode: bool,
pub llvm_libunwind: bool,
pub run_host_only: bool,
@ -329,6 +330,7 @@ struct Rust {
remap_debuginfo: Option<bool>,
jemalloc: Option<bool>,
test_compare_mode: Option<bool>,
llvm_libunwind: Option<bool>,
}
/// 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.jemalloc, rust.jemalloc);
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.channel, rust.channel.clone());
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("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
# channel, etc.
o("optimize", "rust.optimize", "build optimized rust code")

View File

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

View File

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

View File

@ -4,6 +4,9 @@ name = "unwind"
version = "0.0.0"
build = "build.rs"
edition = "2018"
include = [
'/libunwind/*',
]
[lib]
name = "unwind"
@ -16,3 +19,9 @@ doc = false
core = { path = "../libcore" }
libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false }
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");
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") {
// musl is handled in lib.rs
} else if !target.contains("android") {
@ -37,3 +43,62 @@ fn main() {
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