Skip to content

Commit

Permalink
Auto merge of #59089 - petrhosek:llvm-unwind, r=petrhosek
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Apr 4, 2019
2 parents a5dfdc5 + 86d1678 commit f717b58
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Expand Up @@ -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)",
Expand Down
3 changes: 3 additions & 0 deletions config.toml.example
Expand Up @@ -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
#
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/config.rs
Expand Up @@ -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,

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/bootstrap/configure.py
Expand Up @@ -68,6 +68,8 @@ def v(*args):
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")
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/lib.rs
Expand Up @@ -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");
}
Expand Down
1 change: 1 addition & 0 deletions src/libstd/Cargo.toml
Expand Up @@ -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"]
Expand Down
9 changes: 9 additions & 0 deletions src/libunwind/Cargo.toml
Expand Up @@ -4,6 +4,9 @@ name = "unwind"
version = "0.0.0"
build = "build.rs"
edition = "2018"
include = [
'/libunwind/*',
]

[lib]
name = "unwind"
Expand All @@ -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"]
67 changes: 66 additions & 1 deletion src/libunwind/build.rs
Expand Up @@ -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") {
Expand Down Expand Up @@ -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");
}
}

0 comments on commit f717b58

Please sign in to comment.