Skip to content

Commit

Permalink
cleanup and fix compiling of libunwind
Browse files Browse the repository at this point in the history
fix conditional compiling of llvm-libunwind feaure for musl target.
update document of llvm-libunwind feature.
  • Loading branch information
12101111 committed May 26, 2021
1 parent 126561c commit 52a3365
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 76 deletions.
8 changes: 8 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,14 @@ changelog-seen = 2

# Use LLVM libunwind as the implementation for Rust's unwinder.
# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
# This option only applies for Linux and Fuchsia targets.
# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both
# means static link to the in-tree build of llvm libunwind, and 'system' means
# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
#llvm-libunwind = 'no'

# Enable Windows Control Flow Guard checks in the standard library.
Expand Down
7 changes: 7 additions & 0 deletions library/unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,12 @@ cfg-if = "0.1.8"
cc = "1.0.67"

[features]

# Only applies for Linux and Fuchsia targets
# Static link to the in-tree build of llvm libunwind
llvm-libunwind = []

# Only applies for Linux and Fuchsia targets
# If crt-static is enabled, static link to `libunwind.a` provided by system
# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
system-llvm-libunwind = []
146 changes: 74 additions & 72 deletions library/unwind/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ fn main() {
println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");

if cfg!(feature = "system-llvm-libunwind") {
if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
// linking for Linux is handled in lib.rs
return;
}

Expand Down Expand Up @@ -57,101 +58,102 @@ mod llvm_libunwind {
pub fn compile() {
let target = env::var("TARGET").expect("TARGET was not set");
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
let cfg = &mut cc::Build::new();

cfg.cpp(true);
cfg.cpp_set_stdlib(None);
cfg.warnings(false);
let mut cc_cfg = cc::Build::new();
let mut cpp_cfg = cc::Build::new();
let root = Path::new("../../src/llvm-project/libunwind");

// libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
if target_endian_little {
cfg.define("__LITTLE_ENDIAN__", Some("1"));
cpp_cfg.cpp(true);
cpp_cfg.cpp_set_stdlib(None);
cpp_cfg.flag("-nostdinc++");
cpp_cfg.flag("-fno-exceptions");
cpp_cfg.flag("-fno-rtti");
cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");

// Don't set this for clang
// By default, Clang builds C code in GNU C17 mode.
// By default, Clang builds C++ code according to the C++98 standard,
// with many C++11 features accepted as extensions.
if cpp_cfg.get_compiler().is_like_gnu() {
cpp_cfg.flag("-std=c++11");
cc_cfg.flag("-std=c99");
}

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 if target.contains("x86_64-fortanix-unknown-sgx") {
cfg.cpp(false);

cfg.static_flag(true);
cfg.opt_level(3);

cfg.flag("-nostdinc++");
cfg.flag("-fno-exceptions");
cfg.flag("-fno-rtti");
cfg.flag("-fstrict-aliasing");
cfg.flag("-funwind-tables");
cfg.flag("-fvisibility=hidden");
cfg.flag("-fno-stack-protector");
cfg.flag("-ffreestanding");
cfg.flag("-fexceptions");

// easiest way to undefine since no API available in cc::Build to undefine
cfg.flag("-U_FORTIFY_SOURCE");
cfg.define("_FORTIFY_SOURCE", "0");

cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
// use the same GCC C compiler command to compile C++ code so we do not need to setup the
// C++ compiler env variables on the builders.
// Don't set this for clang++, as clang++ is able to compile this without libc++.
if cpp_cfg.get_compiler().is_like_gnu() {
cpp_cfg.cpp(false);
}
}

cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
cfg.define("RUST_SGX", "1");
cfg.define("__NO_STRING_INLINES", None);
cfg.define("__NO_MATH_INLINES", None);
cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
cfg.define("NDEBUG", None);
} else {
cfg.flag("-std=c99");
cfg.flag("-std=c++11");
cfg.flag("-nostdinc++");
cfg.flag("-fno-exceptions");
cfg.flag("-fno-rtti");
for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
cfg.warnings(false);
cfg.flag("-fstrict-aliasing");
cfg.flag("-funwind-tables");
cfg.flag("-fvisibility=hidden");
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
cfg.include(root.join("include"));
cfg.cargo_metadata(false);

if target.contains("x86_64-fortanix-unknown-sgx") {
cfg.static_flag(true);
cfg.opt_level(3);
cfg.flag("-fno-stack-protector");
cfg.flag("-ffreestanding");
cfg.flag("-fexceptions");

// easiest way to undefine since no API available in cc::Build to undefine
cfg.flag("-U_FORTIFY_SOURCE");
cfg.define("_FORTIFY_SOURCE", "0");
cfg.define("RUST_SGX", "1");
cfg.define("__NO_STRING_INLINES", None);
cfg.define("__NO_MATH_INLINES", None);
cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
cfg.define("NDEBUG", None);
}
}

let mut unwind_sources = vec![
"Unwind-EHABI.cpp",
"Unwind-seh.cpp",
let mut c_sources = vec![
"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 cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
let cpp_len = cpp_sources.len();

if target.contains("x86_64-fortanix-unknown-sgx") {
unwind_sources.push("UnwindRustSgx.c");
c_sources.push("UnwindRustSgx.c");
}

let root = Path::new("../../src/llvm-project/libunwind");
cfg.include(root.join("include"));
for src in unwind_sources {
cfg.file(root.join("src").join(src));
for src in c_sources {
cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}

if target_env == "musl" {
// use the same C compiler command to compile C++ code so we do not need to setup the
// C++ compiler env variables on the builders
cfg.cpp(false);
// linking for musl is handled in lib.rs
cfg.cargo_metadata(false);
println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
for src in cpp_sources {
cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}

cfg.compile("unwind");
let out_dir = env::var("OUT_DIR").unwrap();
println!("cargo:rustc-link-search=native={}", &out_dir);

cpp_cfg.compile("unwind-cpp");

let mut count = 0;
for entry in std::fs::read_dir(&out_dir).unwrap() {
let obj = entry.unwrap().path().canonicalize().unwrap();
if let Some(ext) = obj.extension() {
if ext == "o" {
cc_cfg.object(&obj);
count += 1;
}
}
}
assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
cc_cfg.compile("unwind");
}
}
21 changes: 17 additions & 4 deletions library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,22 @@ cfg_if::cfg_if! {
}

#[cfg(target_env = "musl")]
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
cfg_if::cfg_if! {
if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
} else if #[cfg(feature = "llvm-libunwind")] {
#[link(name = "unwind", kind = "static")]
extern "C" {}
} else if #[cfg(feature = "system-llvm-libunwind")] {
#[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
extern "C" {}
} else {
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
}
}

// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
// glibc needs it, and needs it listed later on the linker command line. We
Expand Down Expand Up @@ -68,5 +81,5 @@ extern "C" {}
extern "C" {}

#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
#[link(name = "unwind", kind = "static-nobundle")]
#[link(name = "unwind", kind = "static")]
extern "C" {}

0 comments on commit 52a3365

Please sign in to comment.