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