]> git.lizzy.rs Git - rust.git/commitdiff
build llvm libunwind.a in rustbuild
author12101111 <w12101111@gmail.com>
Mon, 26 Jul 2021 14:47:07 +0000 (22:47 +0800)
committer12101111 <w12101111@gmail.com>
Sat, 28 Aug 2021 06:14:22 +0000 (14:14 +0800)
library/unwind/build.rs
library/unwind/src/lib.rs
library/unwind/src/libunwind.rs
src/bootstrap/compile.rs
src/bootstrap/native.rs

index 0529d24a27408002b3b36c500c9b87b8cd925d62..1d0b4a59a287b05969080147a5aab691d0e36603 100644 (file)
@@ -4,36 +4,18 @@ fn main() {
     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");
@@ -63,111 +45,3 @@ fn main() {
         // 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");
-    }
-}
index 53b13b9043b3a2e9fef7fe26e318e2f8a83303e4..06384b159264789108eb7329e14b5eb85437e6d4 100644 (file)
@@ -1,6 +1,8 @@
 #![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" {}
index 196be74decba4e4fb9c454f3fdf7a50ede26585e..5e15fe75a2463632f14850d7433168c16936eed8 100644 (file)
@@ -77,9 +77,18 @@ pub enum _Unwind_Context {}
 
 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) -> !;
@@ -106,9 +115,10 @@ pub enum _Unwind_Action {
     }
     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);
@@ -163,9 +173,10 @@ enum _Unwind_VRS_DataRepresentation {
     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,
@@ -228,9 +239,10 @@ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
 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;
     }
@@ -241,9 +253,6 @@ pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
     }
 } 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;
     }
index d25989954783ae05ce240f9ffcebf595622e71c7..afddbc1da9e702176ab947c57697c6b544cd3865 100644 (file)
@@ -23,7 +23,7 @@
 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;
@@ -234,6 +234,18 @@ fn copy_self_contained_objects(
         }
     }
 
+    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
 }
 
index 2172b01706d8845ccd8c6e581e520cc879d53383..0a23d4fff6bda0127bab325e210217b0be8cec10 100644 (file)
@@ -10,7 +10,7 @@
 
 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};
@@ -952,3 +952,154 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
         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
+    }
+}