1 extern crate cc;
2
3 use std::env;
4 use std::fs::File;
5 use std::path::PathBuf;
6
main()7 fn main() {
8 let target = env::var("TARGET").unwrap();
9
10 if target.contains("msvc") || // libbacktrace isn't used on MSVC windows
11 target.contains("emscripten") || // no way this will ever compile for emscripten
12 target.contains("cloudabi") ||
13 target.contains("wasm32") ||
14 target.contains("fuchsia")
15 // fuchsia uses external out-of-process symbolization
16 {
17 println!("cargo:rustc-cfg=empty");
18 return;
19 }
20
21 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
22
23 let mut build = cc::Build::new();
24 build
25 .include("src/libbacktrace")
26 .include(&out_dir)
27 .warnings(false)
28 .file("src/libbacktrace/alloc.c")
29 .file("src/libbacktrace/dwarf.c")
30 .file("src/libbacktrace/fileline.c")
31 .file("src/libbacktrace/posix.c")
32 .file("src/libbacktrace/read.c")
33 .file("src/libbacktrace/sort.c")
34 .file("src/libbacktrace/state.c");
35
36 // No need to have any symbols reexported form shared objects
37 build.flag("-fvisibility=hidden");
38
39 if target.contains("darwin") {
40 build.file("src/libbacktrace/macho.c");
41 } else if target.contains("windows") {
42 build.file("src/libbacktrace/pecoff.c");
43 } else {
44 build.file("src/libbacktrace/elf.c");
45
46 let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
47 if pointer_width == "64" {
48 build.define("BACKTRACE_ELF_SIZE", "64");
49 } else {
50 build.define("BACKTRACE_ELF_SIZE", "32");
51 }
52 }
53
54 File::create(out_dir.join("backtrace-supported.h")).unwrap();
55 build.define("BACKTRACE_SUPPORTED", "1");
56 build.define("BACKTRACE_USES_MALLOC", "1");
57 build.define("BACKTRACE_SUPPORTS_THREADS", "0");
58 build.define("BACKTRACE_SUPPORTS_DATA", "0");
59
60 File::create(out_dir.join("config.h")).unwrap();
61 if target.contains("android") {
62 maybe_enable_dl_iterate_phdr_android(&mut build);
63 } else if !target.contains("apple-ios")
64 && !target.contains("solaris")
65 && !target.contains("redox")
66 && !target.contains("haiku")
67 && !target.contains("vxworks")
68 {
69 build.define("HAVE_DL_ITERATE_PHDR", "1");
70 }
71 build.define("_GNU_SOURCE", "1");
72 build.define("_LARGE_FILES", "1");
73
74 // When we're built as part of the Rust compiler, this is used to enable
75 // debug information in libbacktrace itself.
76 let any_debug = env::var("RUSTC_DEBUGINFO").unwrap_or_default() == "true"
77 || env::var("RUSTC_DEBUGINFO_LINES").unwrap_or_default() == "true";
78 build.debug(any_debug);
79
80 let syms = [
81 "backtrace_full",
82 "backtrace_dwarf_add",
83 "backtrace_initialize",
84 "backtrace_pcinfo",
85 "backtrace_syminfo",
86 "backtrace_get_view",
87 "backtrace_release_view",
88 "backtrace_alloc",
89 "backtrace_free",
90 "backtrace_vector_finish",
91 "backtrace_vector_grow",
92 "backtrace_vector_release",
93 "backtrace_close",
94 "backtrace_open",
95 "backtrace_print",
96 "backtrace_simple",
97 "backtrace_qsort",
98 "backtrace_create_state",
99 "backtrace_uncompress_zdebug",
100 // These should be `static` in C, but they aren't...
101 "macho_get_view",
102 "macho_symbol_type_relevant",
103 "macho_get_commands",
104 "macho_try_dsym",
105 "macho_try_dwarf",
106 "macho_get_addr_range",
107 "macho_get_uuid",
108 "macho_add",
109 "macho_add_symtab",
110 "macho_file_to_host_u64",
111 "macho_file_to_host_u32",
112 "macho_file_to_host_u16",
113 ];
114 let prefix = if cfg!(feature = "rustc-dep-of-std") {
115 println!("cargo:rustc-cfg=rdos");
116 "__rdos_"
117 } else {
118 println!("cargo:rustc-cfg=rbt");
119 "__rbt_"
120 };
121 for sym in syms.iter() {
122 build.define(sym, &format!("{}{}", prefix, sym)[..]);
123 }
124
125 build.compile("backtrace");
126 }
127
128 // The `dl_iterate_phdr` API was added in Android API 21+ (according to #227),
129 // so if we can dynamically detect an appropriately configured C compiler for
130 // that then let's enable the `dl_iterate_phdr` API, otherwise Android just
131 // won't have any information.
maybe_enable_dl_iterate_phdr_android(build: &mut cc::Build)132 fn maybe_enable_dl_iterate_phdr_android(build: &mut cc::Build) {
133 let expansion = cc::Build::new().file("src/android-api.c").expand();
134 let expansion = match std::str::from_utf8(&expansion) {
135 Ok(s) => s,
136 Err(_) => return,
137 };
138 println!("expanded android version detection:\n{}", expansion);
139 let marker = "APIVERSION";
140 let i = match expansion.find(marker) {
141 Some(i) => i,
142 None => return,
143 };
144 let version = match expansion[i + marker.len() + 1..].split_whitespace().next() {
145 Some(s) => s,
146 None => return,
147 };
148 let version = match version.parse::<u32>() {
149 Ok(n) => n,
150 Err(_) => return,
151 };
152 if version >= 21 {
153 build.define("HAVE_DL_ITERATE_PHDR", "1");
154 }
155 }
156