Skip to content

Commit 926f069

Browse files
committed
Auto merge of #85600 - 12101111:rustbuild-libunwind, r=petrochenkov
build llvm libunwind.a in rustbuild This PR move the building of llvm-libunwind from build script of libunwind to rustbuild, so user don't need a C compiler and recompile this C/C++ library when using build-std, and user can use codegen flags `link-self-contained` and cargo flag `build-std-features` to control the behavior of libunwind linking.
2 parents 42a2a53 + 9a53d59 commit 926f069

File tree

6 files changed

+212
-157
lines changed

6 files changed

+212
-157
lines changed

library/unwind/build.rs

+10-136
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,18 @@ fn main() {
44
println!("cargo:rerun-if-changed=build.rs");
55
let target = env::var("TARGET").expect("TARGET was not set");
66

7-
if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
8-
// linking for Linux is handled in lib.rs
9-
return;
10-
}
11-
12-
if cfg!(feature = "llvm-libunwind")
13-
&& ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia"))
14-
{
15-
// Build the unwinding from libunwind C/C++ source code.
16-
llvm_libunwind::compile();
17-
} else if target.contains("x86_64-fortanix-unknown-sgx") {
18-
llvm_libunwind::compile();
19-
} else if target.contains("linux") {
20-
// linking for Linux is handled in lib.rs
21-
if target.contains("musl") {
22-
llvm_libunwind::compile();
23-
} else if target.contains("android") {
24-
let build = cc::Build::new();
7+
if target.contains("android") {
8+
let build = cc::Build::new();
259

26-
// Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
27-
// check if we have `libunwind` available and if so use it. Otherwise
28-
// fall back to `libgcc` to support older ndk versions.
29-
let has_unwind =
30-
build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
10+
// Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
11+
// check if we have `libunwind` available and if so use it. Otherwise
12+
// fall back to `libgcc` to support older ndk versions.
13+
let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
3114

32-
if has_unwind {
33-
println!("cargo:rustc-link-lib=unwind");
34-
} else {
35-
println!("cargo:rustc-link-lib=gcc");
36-
}
15+
if has_unwind {
16+
println!("cargo:rustc-link-lib=unwind");
17+
} else {
18+
println!("cargo:rustc-link-lib=gcc");
3719
}
3820
} else if target.contains("freebsd") {
3921
println!("cargo:rustc-link-lib=gcc_s");
@@ -63,111 +45,3 @@ fn main() {
6345
// redox is handled in lib.rs
6446
}
6547
}
66-
67-
mod llvm_libunwind {
68-
use std::env;
69-
use std::path::Path;
70-
71-
/// Compile the libunwind C/C++ source code.
72-
pub fn compile() {
73-
let target = env::var("TARGET").expect("TARGET was not set");
74-
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
75-
let mut cc_cfg = cc::Build::new();
76-
let mut cpp_cfg = cc::Build::new();
77-
let root = Path::new("../../src/llvm-project/libunwind");
78-
79-
cpp_cfg.cpp(true);
80-
cpp_cfg.cpp_set_stdlib(None);
81-
cpp_cfg.flag("-nostdinc++");
82-
cpp_cfg.flag("-fno-exceptions");
83-
cpp_cfg.flag("-fno-rtti");
84-
cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
85-
86-
// Don't set this for clang
87-
// By default, Clang builds C code in GNU C17 mode.
88-
// By default, Clang builds C++ code according to the C++98 standard,
89-
// with many C++11 features accepted as extensions.
90-
if cpp_cfg.get_compiler().is_like_gnu() {
91-
cpp_cfg.flag("-std=c++11");
92-
cc_cfg.flag("-std=c99");
93-
}
94-
95-
if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
96-
// use the same GCC C compiler command to compile C++ code so we do not need to setup the
97-
// C++ compiler env variables on the builders.
98-
// Don't set this for clang++, as clang++ is able to compile this without libc++.
99-
if cpp_cfg.get_compiler().is_like_gnu() {
100-
cpp_cfg.cpp(false);
101-
}
102-
}
103-
104-
for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
105-
cfg.warnings(false);
106-
cfg.flag("-fstrict-aliasing");
107-
cfg.flag("-funwind-tables");
108-
cfg.flag("-fvisibility=hidden");
109-
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
110-
cfg.include(root.join("include"));
111-
cfg.cargo_metadata(false);
112-
113-
if target.contains("x86_64-fortanix-unknown-sgx") {
114-
cfg.static_flag(true);
115-
cfg.opt_level(3);
116-
cfg.flag("-fno-stack-protector");
117-
cfg.flag("-ffreestanding");
118-
cfg.flag("-fexceptions");
119-
120-
// easiest way to undefine since no API available in cc::Build to undefine
121-
cfg.flag("-U_FORTIFY_SOURCE");
122-
cfg.define("_FORTIFY_SOURCE", "0");
123-
cfg.define("RUST_SGX", "1");
124-
cfg.define("__NO_STRING_INLINES", None);
125-
cfg.define("__NO_MATH_INLINES", None);
126-
cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
127-
cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
128-
cfg.define("NDEBUG", None);
129-
}
130-
}
131-
132-
let mut c_sources = vec![
133-
"Unwind-sjlj.c",
134-
"UnwindLevel1-gcc-ext.c",
135-
"UnwindLevel1.c",
136-
"UnwindRegistersRestore.S",
137-
"UnwindRegistersSave.S",
138-
];
139-
140-
let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
141-
let cpp_len = cpp_sources.len();
142-
143-
if target.contains("x86_64-fortanix-unknown-sgx") {
144-
c_sources.push("UnwindRustSgx.c");
145-
}
146-
147-
for src in c_sources {
148-
cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
149-
}
150-
151-
for src in cpp_sources {
152-
cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
153-
}
154-
155-
let out_dir = env::var("OUT_DIR").unwrap();
156-
println!("cargo:rustc-link-search=native={}", &out_dir);
157-
158-
cpp_cfg.compile("unwind-cpp");
159-
160-
let mut count = 0;
161-
for entry in std::fs::read_dir(&out_dir).unwrap() {
162-
let obj = entry.unwrap().path().canonicalize().unwrap();
163-
if let Some(ext) = obj.extension() {
164-
if ext == "o" {
165-
cc_cfg.object(&obj);
166-
count += 1;
167-
}
168-
}
169-
}
170-
assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
171-
cc_cfg.compile("unwind");
172-
}
173-
}

library/unwind/src/lib.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![no_std]
22
#![unstable(feature = "panic_unwind", issue = "32837")]
33
#![feature(link_cfg)]
4+
#![feature(native_link_modifiers)]
5+
#![feature(native_link_modifiers_bundle)]
46
#![feature(nll)]
57
#![feature(staged_api)]
68
#![feature(static_nobundle)]
@@ -42,14 +44,14 @@ cfg_if::cfg_if! {
4244
if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
4345
compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
4446
} else if #[cfg(feature = "llvm-libunwind")] {
45-
#[link(name = "unwind", kind = "static")]
47+
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
4648
extern "C" {}
4749
} else if #[cfg(feature = "system-llvm-libunwind")] {
48-
#[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
50+
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
4951
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
5052
extern "C" {}
5153
} else {
52-
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
54+
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
5355
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
5456
extern "C" {}
5557
}
@@ -77,10 +79,10 @@ extern "C" {}
7779
extern "C" {}
7880

7981
#[cfg(target_os = "redox")]
80-
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
82+
#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
8183
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
8284
extern "C" {}
8385

8486
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
85-
#[link(name = "unwind", kind = "static")]
87+
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
8688
extern "C" {}

library/unwind/src/libunwind.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,18 @@ pub enum _Unwind_Context {}
7777

7878
pub type _Unwind_Exception_Cleanup_Fn =
7979
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
80+
81+
// FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
82+
// the block are reexported in dylib build of libstd. This is needed when build rustc with
83+
// feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols.
84+
// However the `link` attribute is duplicated multiple times and does not just export symbol,
85+
// a better way to manually export symbol would be another attribute like `#[export]`.
86+
// See the logic in function rustc_codegen_ssa::src::back::exported_symbols, module
87+
// rustc_codegen_ssa::src::back::symbol_export, rustc_middle::middle::exported_symbols
88+
// and RFC 2841
8089
#[cfg_attr(
8190
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
82-
link(name = "unwind", kind = "static")
91+
link(name = "unwind", kind = "static", modifiers = "-bundle")
8392
)]
8493
extern "C-unwind" {
8594
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
@@ -106,9 +115,10 @@ if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))
106115
}
107116
pub use _Unwind_Action::*;
108117

109-
#[cfg_attr(all(feature = "llvm-libunwind",
110-
any(target_os = "fuchsia", target_os = "linux")),
111-
link(name = "unwind", kind = "static"))]
118+
#[cfg_attr(
119+
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
120+
link(name = "unwind", kind = "static", modifiers = "-bundle")
121+
)]
112122
extern "C" {
113123
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
114124
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
@@ -163,9 +173,10 @@ if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))
163173
pub const UNWIND_SP_REG: c_int = 13;
164174
pub const UNWIND_IP_REG: c_int = 15;
165175

166-
#[cfg_attr(all(feature = "llvm-libunwind",
167-
any(target_os = "fuchsia", target_os = "linux")),
168-
link(name = "unwind", kind = "static"))]
176+
#[cfg_attr(
177+
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
178+
link(name = "unwind", kind = "static", modifiers = "-bundle")
179+
)]
169180
extern "C" {
170181
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
171182
regclass: _Unwind_VRS_RegClass,
@@ -228,9 +239,10 @@ if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))
228239
cfg_if::cfg_if! {
229240
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
230241
// Not 32-bit iOS
231-
#[cfg_attr(all(feature = "llvm-libunwind",
232-
any(target_os = "fuchsia", target_os = "linux")),
233-
link(name = "unwind", kind = "static"))]
242+
#[cfg_attr(
243+
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
244+
link(name = "unwind", kind = "static", modifiers = "-bundle")
245+
)]
234246
extern "C-unwind" {
235247
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
236248
}
@@ -241,9 +253,6 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
241253
}
242254
} else {
243255
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
244-
#[cfg_attr(all(feature = "llvm-libunwind",
245-
any(target_os = "fuchsia", target_os = "linux")),
246-
link(name = "unwind", kind = "static"))]
247256
extern "C-unwind" {
248257
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
249258
}

src/bootstrap/compile.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use serde::Deserialize;
2323
use crate::builder::Cargo;
2424
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
2525
use crate::cache::{Interned, INTERNER};
26-
use crate::config::TargetSelection;
26+
use crate::config::{LlvmLibunwind, TargetSelection};
2727
use crate::dist;
2828
use crate::native;
2929
use crate::tool::SourceType;
@@ -234,6 +234,18 @@ fn copy_self_contained_objects(
234234
}
235235
}
236236

237+
if target.contains("musl")
238+
|| target.contains("x86_64-fortanix-unknown-sgx")
239+
|| builder.config.llvm_libunwind == LlvmLibunwind::InTree
240+
&& (target.contains("linux") || target.contains("fuchsia"))
241+
{
242+
let libunwind_path = builder.ensure(native::Libunwind { target });
243+
let libunwind_source = libunwind_path.join("libunwind.a");
244+
let libunwind_target = libdir_self_contained.join("libunwind.a");
245+
builder.copy(&libunwind_source, &libunwind_target);
246+
target_deps.push((libunwind_target, DependencyType::TargetSelfContained));
247+
}
248+
237249
target_deps
238250
}
239251

0 commit comments

Comments
 (0)