println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
- if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
- // linking for Linux is handled in lib.rs
- return;
- }
-
- if cfg!(feature = "llvm-libunwind")
- && ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia"))
- {
- // Build the unwinding from libunwind C/C++ source code.
- llvm_libunwind::compile();
- } else if target.contains("x86_64-fortanix-unknown-sgx") {
- llvm_libunwind::compile();
- } else if target.contains("linux") {
- // linking for Linux is handled in lib.rs
- if target.contains("musl") {
- llvm_libunwind::compile();
- } else if target.contains("android") {
- let build = cc::Build::new();
+ if target.contains("android") {
+ let build = cc::Build::new();
- // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
- // check if we have `libunwind` available and if so use it. Otherwise
- // fall back to `libgcc` to support older ndk versions.
- let has_unwind =
- build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+ // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+ // check if we have `libunwind` available and if so use it. Otherwise
+ // fall back to `libgcc` to support older ndk versions.
+ let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
- if has_unwind {
- println!("cargo:rustc-link-lib=unwind");
- } else {
- println!("cargo:rustc-link-lib=gcc");
- }
+ if has_unwind {
+ println!("cargo:rustc-link-lib=unwind");
+ } else {
+ println!("cargo:rustc-link-lib=gcc");
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
// redox is handled in lib.rs
}
}
-
-mod llvm_libunwind {
- use std::env;
- use std::path::Path;
-
- /// Compile the libunwind C/C++ source code.
- pub fn compile() {
- let target = env::var("TARGET").expect("TARGET was not set");
- let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
- let mut cc_cfg = cc::Build::new();
- let mut cpp_cfg = cc::Build::new();
- let root = Path::new("../../src/llvm-project/libunwind");
-
- 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.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);
- }
- }
-
- 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.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 c_sources = vec![
- "Unwind-sjlj.c",
- "UnwindLevel1-gcc-ext.c",
- "UnwindLevel1.c",
- "UnwindRegistersRestore.S",
- "UnwindRegistersSave.S",
- ];
-
- 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") {
- c_sources.push("UnwindRustSgx.c");
- }
-
- for src in c_sources {
- cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
- }
-
- for src in cpp_sources {
- cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
- }
-
- 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");
- }
-}
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
#![feature(link_cfg)]
+#![feature(native_link_modifiers)]
+#![feature(native_link_modifiers_bundle)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(static_nobundle)]
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")]
+ #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
extern "C" {}
} else if #[cfg(feature = "system-llvm-libunwind")] {
- #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+ #[link(name = "unwind", kind = "static", modifiers = "-bundle", 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 = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
}
extern "C" {}
#[cfg(target_os = "redox")]
-#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[link(name = "unwind", kind = "static")]
+#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
extern "C" {}
pub type _Unwind_Exception_Cleanup_Fn =
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
+
+// FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
+// the block are reexported in dylib build of libstd. This is needed when build rustc with
+// feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols.
+// However the `link` attribute is duplicated multiple times and does not just export symbol,
+// a better way to manually export symbol would be another attribute like `#[export]`.
+// See the logic in function rustc_codegen_ssa::src::back::exported_symbols, module
+// rustc_codegen_ssa::src::back::symbol_export, rustc_middle::middle::exported_symbols
+// and RFC 2841
#[cfg_attr(
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
- link(name = "unwind", kind = "static")
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
extern "C-unwind" {
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
}
pub use _Unwind_Action::*;
- #[cfg_attr(all(feature = "llvm-libunwind",
- any(target_os = "fuchsia", target_os = "linux")),
- link(name = "unwind", kind = "static"))]
+ #[cfg_attr(
+ all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
+ )]
extern "C" {
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
pub const UNWIND_SP_REG: c_int = 13;
pub const UNWIND_IP_REG: c_int = 15;
- #[cfg_attr(all(feature = "llvm-libunwind",
- any(target_os = "fuchsia", target_os = "linux")),
- link(name = "unwind", kind = "static"))]
+ #[cfg_attr(
+ all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
+ )]
extern "C" {
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
regclass: _Unwind_VRS_RegClass,
cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
// Not 32-bit iOS
- #[cfg_attr(all(feature = "llvm-libunwind",
- any(target_os = "fuchsia", target_os = "linux")),
- link(name = "unwind", kind = "static"))]
+ #[cfg_attr(
+ all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
+ )]
extern "C-unwind" {
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
}
} else {
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
- #[cfg_attr(all(feature = "llvm-libunwind",
- any(target_os = "fuchsia", target_os = "linux")),
- link(name = "unwind", kind = "static"))]
extern "C-unwind" {
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
use crate::builder::Cargo;
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
-use crate::config::TargetSelection;
+use crate::config::{LlvmLibunwind, TargetSelection};
use crate::dist;
use crate::native;
use crate::tool::SourceType;
}
}
+ if target.contains("musl")
+ || target.contains("x86_64-fortanix-unknown-sgx")
+ || builder.config.llvm_libunwind == LlvmLibunwind::InTree
+ && (target.contains("linux") || target.contains("fuchsia"))
+ {
+ let libunwind_path = builder.ensure(native::Libunwind { target });
+ let libunwind_source = libunwind_path.join("libunwind.a");
+ let libunwind_target = libdir_self_contained.join("libunwind.a");
+ builder.copy(&libunwind_source, &libunwind_target);
+ target_deps.push((libunwind_target, DependencyType::TargetSelfContained));
+ }
+
target_deps
}
use std::env;
use std::env::consts::EXE_EXTENSION;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
out_dir
}
}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Libunwind {
+ pub target: TargetSelection,
+}
+
+impl Step for Libunwind {
+ type Output = PathBuf;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("src/llvm-project/libunwind")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(Libunwind { target: run.target });
+ }
+
+ /// Build linunwind.a
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ if builder.config.dry_run {
+ return PathBuf::new();
+ }
+
+ let out_dir = builder.native_dir(self.target).join("libunwind");
+ let root = builder.src.join("src/llvm-project/libunwind");
+
+ if up_to_date(&root, &out_dir.join("libunwind.a")) {
+ return out_dir;
+ }
+
+ builder.info(&format!("Building libunwind.a for {}", self.target.triple));
+ t!(fs::create_dir_all(&out_dir));
+
+ let mut cc_cfg = cc::Build::new();
+ let mut cpp_cfg = cc::Build::new();
+
+ 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");
+
+ for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
+ if let Some(ar) = builder.ar(self.target) {
+ cfg.archiver(ar);
+ }
+ cfg.target(&self.target.triple);
+ cfg.host(&builder.config.build.triple);
+ cfg.warnings(false);
+ cfg.debug(false);
+ // get_compiler() need set opt_level first.
+ cfg.opt_level(3);
+ cfg.flag("-fstrict-aliasing");
+ cfg.flag("-funwind-tables");
+ cfg.flag("-fvisibility=hidden");
+ cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+ cfg.include(root.join("include"));
+ cfg.cargo_metadata(false);
+ cfg.out_dir(&out_dir);
+
+ if self.target.contains("x86_64-fortanix-unknown-sgx") {
+ cfg.static_flag(true);
+ 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);
+ }
+ }
+
+ cc_cfg.compiler(builder.cc(self.target));
+ if let Ok(cxx) = builder.cxx(self.target) {
+ cpp_cfg.compiler(cxx);
+ } else {
+ cc_cfg.compiler(builder.cc(self.target));
+ }
+
+ // 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 cc_cfg.get_compiler().is_like_gnu() {
+ cc_cfg.flag("-std=c99");
+ }
+ if cpp_cfg.get_compiler().is_like_gnu() {
+ cpp_cfg.flag("-std=c++11");
+ }
+
+ if self.target.contains("x86_64-fortanix-unknown-sgx") || self.target.contains("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);
+ cpp_cfg.compiler(builder.cc(self.target));
+ }
+ }
+
+ let mut c_sources = vec![
+ "Unwind-sjlj.c",
+ "UnwindLevel1-gcc-ext.c",
+ "UnwindLevel1.c",
+ "UnwindRegistersRestore.S",
+ "UnwindRegistersSave.S",
+ ];
+
+ let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
+ let cpp_len = cpp_sources.len();
+
+ if self.target.contains("x86_64-fortanix-unknown-sgx") {
+ c_sources.push("UnwindRustSgx.c");
+ }
+
+ for src in c_sources {
+ cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
+ }
+
+ for src in &cpp_sources {
+ cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
+ }
+
+ cpp_cfg.compile("unwind-cpp");
+
+ // FIXME: https://github.com/alexcrichton/cc-rs/issues/545#issuecomment-679242845
+ let mut count = 0;
+ for entry in fs::read_dir(&out_dir).unwrap() {
+ let file = entry.unwrap().path().canonicalize().unwrap();
+ if file.is_file() && file.extension() == Some(OsStr::new("o")) {
+ // file name starts with "Unwind-EHABI", "Unwind-seh" or "libunwind"
+ let file_name = file.file_name().unwrap().to_str().expect("UTF-8 file name");
+ if cpp_sources.iter().any(|f| file_name.starts_with(&f[..f.len() - 4])) {
+ cc_cfg.object(&file);
+ count += 1;
+ }
+ }
+ }
+ assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+
+ cc_cfg.compile("unwind");
+ out_dir
+ }
+}