]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131) | |
12 | //! | |
13 | //! Rust targets a wide variety of usecases, and in the interest of flexibility, | |
14 | //! allows new target triples to be defined in configuration files. Most users | |
15 | //! will not need to care about these, but this is invaluable when porting Rust | |
16 | //! to a new platform, and allows for an unprecedented level of control over how | |
17 | //! the compiler works. | |
18 | //! | |
19 | //! # Using custom targets | |
20 | //! | |
21 | //! A target triple, as passed via `rustc --target=TRIPLE`, will first be | |
22 | //! compared against the list of built-in targets. This is to ease distributing | |
23 | //! rustc (no need for configuration files) and also to hold these built-in | |
24 | //! targets as immutable and sacred. If `TRIPLE` is not one of the built-in | |
25 | //! targets, rustc will check if a file named `TRIPLE` exists. If it does, it | |
26 | //! will be loaded as the target configuration. If the file does not exist, | |
27 | //! rustc will search each directory in the environment variable | |
28 | //! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will | |
29 | //! be loaded. If no file is found in any of those directories, a fatal error | |
a7813a04 | 30 | //! will be given. |
1a4d82fc JJ |
31 | //! |
32 | //! Projects defining their own targets should use | |
33 | //! `--target=path/to/my-awesome-platform.json` instead of adding to | |
34 | //! `RUST_TARGET_PATH`. | |
35 | //! | |
36 | //! # Defining a new target | |
37 | //! | |
38 | //! Targets are defined using [JSON](http://json.org/). The `Target` struct in | |
39 | //! this module defines the format the JSON file should take, though each | |
40 | //! underscore in the field names should be replaced with a hyphen (`-`) in the | |
41 | //! JSON file. Some fields are required in every target specification, such as | |
54a0048b SL |
42 | //! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`, |
43 | //! `arch`, and `os`. In general, options passed to rustc with `-C` override | |
44 | //! the target's settings, though `target-feature` and `link-args` will *add* | |
45 | //! to the list specified by the target, rather than replace. | |
1a4d82fc | 46 | |
5bcae85e SL |
47 | use serialize::json::{Json, ToJson}; |
48 | use std::collections::BTreeMap; | |
1a4d82fc | 49 | use std::default::Default; |
c34b1796 | 50 | use std::io::prelude::*; |
c30ab7b3 SL |
51 | use syntax::abi::{Abi, lookup as lookup_abi}; |
52 | ||
53 | use PanicStrategy; | |
1a4d82fc | 54 | |
d9579d0f | 55 | mod android_base; |
1a4d82fc | 56 | mod apple_base; |
85aaf69f | 57 | mod apple_ios_base; |
c30ab7b3 | 58 | mod arm_base; |
c34b1796 | 59 | mod bitrig_base; |
d9579d0f | 60 | mod dragonfly_base; |
32a655c1 | 61 | mod emscripten_base; |
d9579d0f | 62 | mod freebsd_base; |
9e0c209e | 63 | mod haiku_base; |
d9579d0f | 64 | mod linux_base; |
a7813a04 | 65 | mod linux_musl_base; |
85aaf69f | 66 | mod openbsd_base; |
c1a9b12d | 67 | mod netbsd_base; |
7453a54e | 68 | mod solaris_base; |
d9579d0f | 69 | mod windows_base; |
62682a34 | 70 | mod windows_msvc_base; |
c30ab7b3 SL |
71 | mod thumb_base; |
72 | mod fuchsia_base; | |
32a655c1 | 73 | mod redox_base; |
1a4d82fc | 74 | |
5bcae85e SL |
75 | pub type TargetResult = Result<Target, String>; |
76 | ||
7453a54e | 77 | macro_rules! supported_targets { |
c30ab7b3 | 78 | ( $(($triple:expr, $module:ident),)+ ) => ( |
7453a54e SL |
79 | $(mod $module;)* |
80 | ||
81 | /// List of supported targets | |
5bcae85e SL |
82 | const TARGETS: &'static [&'static str] = &[$($triple),*]; |
83 | ||
84 | fn load_specific(target: &str) -> TargetResult { | |
85 | match target { | |
86 | $( | |
87 | $triple => { | |
9e0c209e | 88 | let mut t = $module::target()?; |
5bcae85e SL |
89 | t.options.is_builtin = true; |
90 | ||
91 | // round-trip through the JSON parser to ensure at | |
92 | // run-time that the parser works correctly | |
9e0c209e | 93 | t = Target::from_json(t.to_json())?; |
5bcae85e SL |
94 | debug!("Got builtin target: {:?}", t); |
95 | Ok(t) | |
96 | }, | |
97 | )+ | |
98 | _ => Err(format!("Unable to find target: {}", target)) | |
99 | } | |
100 | } | |
101 | ||
102 | pub fn get_targets() -> Box<Iterator<Item=String>> { | |
103 | Box::new(TARGETS.iter().filter_map(|t| -> Option<String> { | |
104 | load_specific(t) | |
105 | .and(Ok(t.to_string())) | |
106 | .ok() | |
107 | })) | |
108 | } | |
109 | ||
110 | #[cfg(test)] | |
111 | mod test_json_encode_decode { | |
112 | use serialize::json::ToJson; | |
113 | use super::Target; | |
114 | $(use super::$module;)* | |
7453a54e | 115 | |
7453a54e | 116 | $( |
5bcae85e SL |
117 | #[test] |
118 | fn $module() { | |
119 | // Grab the TargetResult struct. If we successfully retrieved | |
120 | // a Target, then the test JSON encoding/decoding can run for this | |
121 | // Target on this testing platform (i.e., checking the iOS targets | |
122 | // only on a Mac test platform). | |
123 | let _ = $module::target().map(|original| { | |
124 | let as_json = original.to_json(); | |
125 | let parsed = Target::from_json(as_json).unwrap(); | |
126 | assert_eq!(original, parsed); | |
127 | }); | |
7453a54e SL |
128 | } |
129 | )* | |
7453a54e SL |
130 | } |
131 | ) | |
132 | } | |
133 | ||
134 | supported_targets! { | |
135 | ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu), | |
136 | ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), | |
137 | ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), | |
138 | ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), | |
9e0c209e SL |
139 | ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), |
140 | ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), | |
7453a54e SL |
141 | ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), |
142 | ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), | |
143 | ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), | |
144 | ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), | |
9e0c209e | 145 | ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), |
7453a54e SL |
146 | ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), |
147 | ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), | |
5bcae85e SL |
148 | ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), |
149 | ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), | |
476ff2be | 150 | ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), |
7453a54e | 151 | ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), |
5bcae85e | 152 | ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), |
7453a54e SL |
153 | ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), |
154 | ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), | |
155 | ("i686-unknown-linux-musl", i686_unknown_linux_musl), | |
156 | ("mips-unknown-linux-musl", mips_unknown_linux_musl), | |
157 | ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl), | |
9e0c209e SL |
158 | ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc), |
159 | ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc), | |
7453a54e | 160 | |
32a655c1 SL |
161 | ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), |
162 | ||
7453a54e SL |
163 | ("i686-linux-android", i686_linux_android), |
164 | ("arm-linux-androideabi", arm_linux_androideabi), | |
a7813a04 | 165 | ("armv7-linux-androideabi", armv7_linux_androideabi), |
7453a54e SL |
166 | ("aarch64-linux-android", aarch64_linux_android), |
167 | ||
8bb4bdeb | 168 | ("aarch64-unknown-freebsd", aarch64_unknown_freebsd), |
7453a54e SL |
169 | ("i686-unknown-freebsd", i686_unknown_freebsd), |
170 | ("x86_64-unknown-freebsd", x86_64_unknown_freebsd), | |
171 | ||
172 | ("i686-unknown-dragonfly", i686_unknown_dragonfly), | |
173 | ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), | |
174 | ||
175 | ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), | |
476ff2be SL |
176 | |
177 | ("i686-unknown-openbsd", i686_unknown_openbsd), | |
7453a54e | 178 | ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), |
476ff2be | 179 | |
8bb4bdeb | 180 | ("i686-unknown-netbsd", i686_unknown_netbsd), |
32a655c1 | 181 | ("sparc64-unknown-netbsd", sparc64_unknown_netbsd), |
7453a54e SL |
182 | ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), |
183 | ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), | |
184 | ||
c30ab7b3 SL |
185 | ("i686-unknown-haiku", i686_unknown_haiku), |
186 | ("x86_64-unknown-haiku", x86_64_unknown_haiku), | |
9e0c209e | 187 | |
7453a54e SL |
188 | ("x86_64-apple-darwin", x86_64_apple_darwin), |
189 | ("i686-apple-darwin", i686_apple_darwin), | |
190 | ||
c30ab7b3 SL |
191 | ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), |
192 | ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), | |
193 | ||
32a655c1 SL |
194 | ("x86_64-unknown-redox", x86_64_unknown_redox), |
195 | ||
7453a54e SL |
196 | ("i386-apple-ios", i386_apple_ios), |
197 | ("x86_64-apple-ios", x86_64_apple_ios), | |
198 | ("aarch64-apple-ios", aarch64_apple_ios), | |
199 | ("armv7-apple-ios", armv7_apple_ios), | |
200 | ("armv7s-apple-ios", armv7s_apple_ios), | |
201 | ||
202 | ("x86_64-sun-solaris", x86_64_sun_solaris), | |
8bb4bdeb | 203 | ("sparcv9-sun-solaris", sparcv9_sun_solaris), |
7453a54e SL |
204 | |
205 | ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), | |
206 | ("i686-pc-windows-gnu", i686_pc_windows_gnu), | |
207 | ||
208 | ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), | |
209 | ("i686-pc-windows-msvc", i686_pc_windows_msvc), | |
54a0048b | 210 | ("i586-pc-windows-msvc", i586_pc_windows_msvc), |
7453a54e SL |
211 | |
212 | ("le32-unknown-nacl", le32_unknown_nacl), | |
c30ab7b3 SL |
213 | ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), |
214 | ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), | |
215 | ||
216 | ("thumbv6m-none-eabi", thumbv6m_none_eabi), | |
217 | ("thumbv7m-none-eabi", thumbv7m_none_eabi), | |
218 | ("thumbv7em-none-eabi", thumbv7em_none_eabi), | |
219 | ("thumbv7em-none-eabihf", thumbv7em_none_eabihf), | |
7453a54e SL |
220 | } |
221 | ||
1a4d82fc JJ |
222 | /// Everything `rustc` knows about how to compile for a specific target. |
223 | /// | |
224 | /// Every field here must be specified, and has no default value. | |
5bcae85e | 225 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 226 | pub struct Target { |
1a4d82fc JJ |
227 | /// Target triple to pass to LLVM. |
228 | pub llvm_target: String, | |
229 | /// String to use as the `target_endian` `cfg` variable. | |
230 | pub target_endian: String, | |
231 | /// String to use as the `target_pointer_width` `cfg` variable. | |
232 | pub target_pointer_width: String, | |
233 | /// OS name to use for conditional compilation. | |
234 | pub target_os: String, | |
d9579d0f AL |
235 | /// Environment name to use for conditional compilation. |
236 | pub target_env: String, | |
b039eaaf SL |
237 | /// Vendor name to use for conditional compilation. |
238 | pub target_vendor: String, | |
7453a54e SL |
239 | /// Architecture to use for ABI considerations. Valid options: "x86", |
240 | /// "x86_64", "arm", "aarch64", "mips", "powerpc", and "powerpc64". | |
1a4d82fc | 241 | pub arch: String, |
54a0048b SL |
242 | /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. |
243 | pub data_layout: String, | |
1a4d82fc JJ |
244 | /// Optional settings with defaults. |
245 | pub options: TargetOptions, | |
246 | } | |
247 | ||
248 | /// Optional aspects of a target specification. | |
249 | /// | |
250 | /// This has an implementation of `Default`, see each field for what the default is. In general, | |
251 | /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. | |
5bcae85e | 252 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 253 | pub struct TargetOptions { |
54a0048b SL |
254 | /// Whether the target is built-in or loaded from a custom target specification. |
255 | pub is_builtin: bool, | |
256 | ||
1a4d82fc JJ |
257 | /// Linker to invoke. Defaults to "cc". |
258 | pub linker: String, | |
62682a34 SL |
259 | /// Archive utility to use when managing archives. Defaults to "ar". |
260 | pub ar: String, | |
92a42be0 | 261 | |
d9579d0f AL |
262 | /// Linker arguments that are unconditionally passed *before* any |
263 | /// user-defined libraries. | |
1a4d82fc | 264 | pub pre_link_args: Vec<String>, |
92a42be0 SL |
265 | /// Objects to link before all others, always found within the |
266 | /// sysroot folder. | |
267 | pub pre_link_objects_exe: Vec<String>, // ... when linking an executable | |
268 | pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib | |
269 | /// Linker arguments that are unconditionally passed after any | |
270 | /// user-defined but before post_link_objects. Standard platform | |
271 | /// libraries that should be always be linked to, usually go here. | |
272 | pub late_link_args: Vec<String>, | |
273 | /// Objects to link after all others, always found within the | |
274 | /// sysroot folder. | |
275 | pub post_link_objects: Vec<String>, | |
d9579d0f AL |
276 | /// Linker arguments that are unconditionally passed *after* any |
277 | /// user-defined libraries. | |
1a4d82fc | 278 | pub post_link_args: Vec<String>, |
92a42be0 | 279 | |
32a655c1 SL |
280 | /// Extra arguments to pass to the external assembler (when used) |
281 | pub asm_args: Vec<String>, | |
282 | ||
d9579d0f | 283 | /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults |
a7813a04 | 284 | /// to "generic". |
1a4d82fc | 285 | pub cpu: String, |
d9579d0f AL |
286 | /// Default target features to pass to LLVM. These features will *always* be |
287 | /// passed, and cannot be disabled even via `-C`. Corresponds to `llc | |
288 | /// -mattr=$features`. | |
1a4d82fc JJ |
289 | pub features: String, |
290 | /// Whether dynamic linking is available on this target. Defaults to false. | |
291 | pub dynamic_linking: bool, | |
292 | /// Whether executables are available on this target. iOS, for example, only allows static | |
293 | /// libraries. Defaults to false. | |
294 | pub executables: bool, | |
1a4d82fc JJ |
295 | /// Relocation model to use in object file. Corresponds to `llc |
296 | /// -relocation-model=$relocation_model`. Defaults to "pic". | |
297 | pub relocation_model: String, | |
298 | /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default". | |
299 | pub code_model: String, | |
300 | /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. | |
301 | pub disable_redzone: bool, | |
302 | /// Eliminate frame pointers from stack frames if possible. Defaults to true. | |
303 | pub eliminate_frame_pointer: bool, | |
304 | /// Emit each function in its own section. Defaults to true. | |
305 | pub function_sections: bool, | |
306 | /// String to prepend to the name of every dynamic library. Defaults to "lib". | |
307 | pub dll_prefix: String, | |
308 | /// String to append to the name of every dynamic library. Defaults to ".so". | |
309 | pub dll_suffix: String, | |
310 | /// String to append to the name of every executable. | |
311 | pub exe_suffix: String, | |
312 | /// String to prepend to the name of every static library. Defaults to "lib". | |
313 | pub staticlib_prefix: String, | |
314 | /// String to append to the name of every static library. Defaults to ".a". | |
315 | pub staticlib_suffix: String, | |
92a42be0 SL |
316 | /// OS family to use for conditional compilation. Valid options: "unix", "windows". |
317 | pub target_family: Option<String>, | |
476ff2be SL |
318 | /// Whether the target toolchain is like OpenBSD's. |
319 | /// Only useful for compiling against OpenBSD, for configuring abi when returning a struct. | |
320 | pub is_like_openbsd: bool, | |
1a4d82fc JJ |
321 | /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in |
322 | /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. | |
323 | pub is_like_osx: bool, | |
7453a54e SL |
324 | /// Whether the target toolchain is like Solaris's. |
325 | /// Only useful for compiling against Illumos/Solaris, | |
326 | /// as they have a different set of linker flags. Defaults to false. | |
327 | pub is_like_solaris: bool, | |
1a4d82fc | 328 | /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows, |
c34b1796 | 329 | /// only really used for figuring out how to find libraries, since Windows uses its own |
1a4d82fc JJ |
330 | /// library naming convention. Defaults to false. |
331 | pub is_like_windows: bool, | |
62682a34 | 332 | pub is_like_msvc: bool, |
85aaf69f SL |
333 | /// Whether the target toolchain is like Android's. Only useful for compiling against Android. |
334 | /// Defaults to false. | |
335 | pub is_like_android: bool, | |
8bb4bdeb XL |
336 | /// Whether the target toolchain is like Emscripten's. Only useful for compiling with |
337 | /// Emscripten toolchain. | |
338 | /// Defaults to false. | |
339 | pub is_like_emscripten: bool, | |
1a4d82fc JJ |
340 | /// Whether the linker support GNU-like arguments such as -O. Defaults to false. |
341 | pub linker_is_gnu: bool, | |
5bcae85e SL |
342 | /// The MinGW toolchain has a known issue that prevents it from correctly |
343 | /// handling COFF object files with more than 2^15 sections. Since each weak | |
344 | /// symbol needs its own COMDAT section, weak linkage implies a large | |
345 | /// number sections that easily exceeds the given limit for larger | |
346 | /// codebases. Consequently we want a way to disallow weak linkage on some | |
347 | /// platforms. | |
348 | pub allows_weak_linkage: bool, | |
1a4d82fc JJ |
349 | /// Whether the linker support rpaths or not. Defaults to false. |
350 | pub has_rpath: bool, | |
b039eaaf SL |
351 | /// Whether to disable linking to the default libraries, typically corresponds |
352 | /// to `-nodefaultlibs`. Defaults to true. | |
353 | pub no_default_libraries: bool, | |
62682a34 SL |
354 | /// Dynamically linked executables can be compiled as position independent |
355 | /// if the default relocation model of position independent code is not | |
356 | /// changed. This is a requirement to take advantage of ASLR, as otherwise | |
357 | /// the functions in the executable are not randomized and can be used | |
358 | /// during an exploit of a vulnerability in any code. | |
1a4d82fc | 359 | pub position_independent_executables: bool, |
c1a9b12d SL |
360 | /// Format that archives should be emitted in. This affects whether we use |
361 | /// LLVM to assemble an archive or fall back to the system linker, and | |
362 | /// currently only "gnu" is used to fall into LLVM. Unknown strings cause | |
363 | /// the system linker to be used. | |
364 | pub archive_format: String, | |
e9174d1e SL |
365 | /// Is asm!() allowed? Defaults to true. |
366 | pub allow_asm: bool, | |
c1a9b12d SL |
367 | /// Whether the target uses a custom unwind resumption routine. |
368 | /// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume` | |
369 | /// defined in libgcc. If this option is enabled, the target must provide | |
370 | /// `eh_unwind_resume` lang item. | |
371 | pub custom_unwind_resume: bool, | |
e9174d1e SL |
372 | |
373 | /// Default crate for allocation symbols to link against | |
374 | pub lib_allocation_crate: String, | |
375 | pub exe_allocation_crate: String, | |
9cc50fc6 SL |
376 | |
377 | /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for | |
378 | /// this target. | |
379 | pub has_elf_tls: bool, | |
7453a54e SL |
380 | // This is mainly for easy compatibility with emscripten. |
381 | // If we give emcc .o files that are actually .bc files it | |
382 | // will 'just work'. | |
383 | pub obj_is_bitcode: bool, | |
a7813a04 | 384 | |
476ff2be SL |
385 | // LLVM can't produce object files for this target. Instead, we'll make LLVM |
386 | // emit assembly and then use `gcc` to turn that assembly into an object | |
387 | // file | |
388 | pub no_integrated_as: bool, | |
389 | ||
32a655c1 SL |
390 | /// Don't use this field; instead use the `.min_atomic_width()` method. |
391 | pub min_atomic_width: Option<u64>, | |
392 | ||
c30ab7b3 SL |
393 | /// Don't use this field; instead use the `.max_atomic_width()` method. |
394 | pub max_atomic_width: Option<u64>, | |
395 | ||
396 | /// Panic strategy: "unwind" or "abort" | |
397 | pub panic_strategy: PanicStrategy, | |
398 | ||
399 | /// A blacklist of ABIs unsupported by the current target. Note that generic | |
400 | /// ABIs are considered to be supported on all platforms and cannot be blacklisted. | |
401 | pub abi_blacklist: Vec<Abi>, | |
476ff2be SL |
402 | |
403 | /// Whether or not the CRT is statically linked by default. | |
404 | pub crt_static_default: bool, | |
1a4d82fc JJ |
405 | } |
406 | ||
407 | impl Default for TargetOptions { | |
62682a34 SL |
408 | /// Create a set of "sane defaults" for any target. This is still |
409 | /// incomplete, and if used for compilation, will certainly not work. | |
1a4d82fc JJ |
410 | fn default() -> TargetOptions { |
411 | TargetOptions { | |
54a0048b | 412 | is_builtin: false, |
e9174d1e SL |
413 | linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), |
414 | ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), | |
1a4d82fc JJ |
415 | pre_link_args: Vec::new(), |
416 | post_link_args: Vec::new(), | |
32a655c1 | 417 | asm_args: Vec::new(), |
1a4d82fc JJ |
418 | cpu: "generic".to_string(), |
419 | features: "".to_string(), | |
420 | dynamic_linking: false, | |
421 | executables: false, | |
1a4d82fc JJ |
422 | relocation_model: "pic".to_string(), |
423 | code_model: "default".to_string(), | |
424 | disable_redzone: false, | |
425 | eliminate_frame_pointer: true, | |
426 | function_sections: true, | |
427 | dll_prefix: "lib".to_string(), | |
428 | dll_suffix: ".so".to_string(), | |
429 | exe_suffix: "".to_string(), | |
430 | staticlib_prefix: "lib".to_string(), | |
431 | staticlib_suffix: ".a".to_string(), | |
92a42be0 | 432 | target_family: None, |
476ff2be | 433 | is_like_openbsd: false, |
1a4d82fc | 434 | is_like_osx: false, |
7453a54e | 435 | is_like_solaris: false, |
1a4d82fc | 436 | is_like_windows: false, |
85aaf69f | 437 | is_like_android: false, |
8bb4bdeb | 438 | is_like_emscripten: false, |
62682a34 | 439 | is_like_msvc: false, |
1a4d82fc | 440 | linker_is_gnu: false, |
5bcae85e | 441 | allows_weak_linkage: true, |
1a4d82fc | 442 | has_rpath: false, |
b039eaaf | 443 | no_default_libraries: true, |
1a4d82fc | 444 | position_independent_executables: false, |
92a42be0 SL |
445 | pre_link_objects_exe: Vec::new(), |
446 | pre_link_objects_dll: Vec::new(), | |
d9579d0f | 447 | post_link_objects: Vec::new(), |
92a42be0 | 448 | late_link_args: Vec::new(), |
7453a54e | 449 | archive_format: "gnu".to_string(), |
c1a9b12d | 450 | custom_unwind_resume: false, |
e9174d1e SL |
451 | lib_allocation_crate: "alloc_system".to_string(), |
452 | exe_allocation_crate: "alloc_system".to_string(), | |
453 | allow_asm: true, | |
9cc50fc6 | 454 | has_elf_tls: false, |
7453a54e | 455 | obj_is_bitcode: false, |
476ff2be | 456 | no_integrated_as: false, |
32a655c1 | 457 | min_atomic_width: None, |
c30ab7b3 SL |
458 | max_atomic_width: None, |
459 | panic_strategy: PanicStrategy::Unwind, | |
460 | abi_blacklist: vec![], | |
476ff2be | 461 | crt_static_default: false, |
1a4d82fc JJ |
462 | } |
463 | } | |
464 | } | |
465 | ||
466 | impl Target { | |
467 | /// Given a function ABI, turn "System" into the correct ABI for this target. | |
7453a54e | 468 | pub fn adjust_abi(&self, abi: Abi) -> Abi { |
1a4d82fc | 469 | match abi { |
7453a54e | 470 | Abi::System => { |
1a4d82fc | 471 | if self.options.is_like_windows && self.arch == "x86" { |
7453a54e | 472 | Abi::Stdcall |
1a4d82fc | 473 | } else { |
7453a54e | 474 | Abi::C |
1a4d82fc JJ |
475 | } |
476 | }, | |
477 | abi => abi | |
478 | } | |
479 | } | |
480 | ||
32a655c1 SL |
481 | /// Minimum integer size in bits that this target can perform atomic |
482 | /// operations on. | |
483 | pub fn min_atomic_width(&self) -> u64 { | |
484 | self.options.min_atomic_width.unwrap_or(8) | |
485 | } | |
486 | ||
c30ab7b3 SL |
487 | /// Maximum integer size in bits that this target can perform atomic |
488 | /// operations on. | |
489 | pub fn max_atomic_width(&self) -> u64 { | |
490 | self.options.max_atomic_width.unwrap_or(self.target_pointer_width.parse().unwrap()) | |
491 | } | |
492 | ||
493 | pub fn is_abi_supported(&self, abi: Abi) -> bool { | |
494 | abi.generic() || !self.options.abi_blacklist.contains(&abi) | |
495 | } | |
496 | ||
1a4d82fc | 497 | /// Load a target descriptor from a JSON object. |
5bcae85e SL |
498 | pub fn from_json(obj: Json) -> TargetResult { |
499 | // While ugly, this code must remain this way to retain | |
500 | // compatibility with existing JSON fields and the internal | |
501 | // expected naming of the Target and TargetOptions structs. | |
502 | // To ensure compatibility is retained, the built-in targets | |
503 | // are round-tripped through this code to catch cases where | |
504 | // the JSON parser is not updated to match the structs. | |
1a4d82fc | 505 | |
85aaf69f | 506 | let get_req_field = |name: &str| { |
1a4d82fc JJ |
507 | match obj.find(name) |
508 | .map(|s| s.as_string()) | |
509 | .and_then(|os| os.map(|s| s.to_string())) { | |
5bcae85e | 510 | Some(val) => Ok(val), |
92a42be0 | 511 | None => { |
5bcae85e | 512 | return Err(format!("Field {} in target specification is required", name)) |
92a42be0 | 513 | } |
1a4d82fc JJ |
514 | } |
515 | }; | |
516 | ||
b039eaaf SL |
517 | let get_opt_field = |name: &str, default: &str| { |
518 | obj.find(name).and_then(|s| s.as_string()) | |
519 | .map(|s| s.to_string()) | |
520 | .unwrap_or(default.to_string()) | |
521 | }; | |
522 | ||
1a4d82fc | 523 | let mut base = Target { |
9e0c209e SL |
524 | llvm_target: get_req_field("llvm-target")?, |
525 | target_endian: get_req_field("target-endian")?, | |
526 | target_pointer_width: get_req_field("target-pointer-width")?, | |
527 | data_layout: get_req_field("data-layout")?, | |
528 | arch: get_req_field("arch")?, | |
529 | target_os: get_req_field("os")?, | |
b039eaaf SL |
530 | target_env: get_opt_field("env", ""), |
531 | target_vendor: get_opt_field("vendor", "unknown"), | |
1a4d82fc JJ |
532 | options: Default::default(), |
533 | }; | |
534 | ||
535 | macro_rules! key { | |
536 | ($key_name:ident) => ( { | |
537 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 538 | obj.find(&name[..]).map(|o| o.as_string() |
1a4d82fc JJ |
539 | .map(|s| base.options.$key_name = s.to_string())); |
540 | } ); | |
541 | ($key_name:ident, bool) => ( { | |
542 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 543 | obj.find(&name[..]) |
1a4d82fc JJ |
544 | .map(|o| o.as_boolean() |
545 | .map(|s| base.options.$key_name = s)); | |
546 | } ); | |
c30ab7b3 | 547 | ($key_name:ident, Option<u64>) => ( { |
a7813a04 XL |
548 | let name = (stringify!($key_name)).replace("_", "-"); |
549 | obj.find(&name[..]) | |
550 | .map(|o| o.as_u64() | |
c30ab7b3 SL |
551 | .map(|s| base.options.$key_name = Some(s))); |
552 | } ); | |
553 | ($key_name:ident, PanicStrategy) => ( { | |
554 | let name = (stringify!($key_name)).replace("_", "-"); | |
555 | obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { | |
556 | match s { | |
557 | "unwind" => base.options.$key_name = PanicStrategy::Unwind, | |
558 | "abort" => base.options.$key_name = PanicStrategy::Abort, | |
559 | _ => return Some(Err(format!("'{}' is not a valid value for \ | |
560 | panic-strategy. Use 'unwind' or 'abort'.", | |
561 | s))), | |
562 | } | |
563 | Some(Ok(())) | |
564 | })).unwrap_or(Ok(())) | |
a7813a04 | 565 | } ); |
1a4d82fc JJ |
566 | ($key_name:ident, list) => ( { |
567 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 568 | obj.find(&name[..]).map(|o| o.as_array() |
1a4d82fc JJ |
569 | .map(|v| base.options.$key_name = v.iter() |
570 | .map(|a| a.as_string().unwrap().to_string()).collect() | |
571 | ) | |
572 | ); | |
573 | } ); | |
e9174d1e SL |
574 | ($key_name:ident, optional) => ( { |
575 | let name = (stringify!($key_name)).replace("_", "-"); | |
576 | if let Some(o) = obj.find(&name[..]) { | |
577 | base.options.$key_name = o | |
578 | .as_string() | |
579 | .map(|s| s.to_string() ); | |
580 | } | |
581 | } ); | |
1a4d82fc JJ |
582 | } |
583 | ||
5bcae85e | 584 | key!(is_builtin, bool); |
1a4d82fc | 585 | key!(linker); |
5bcae85e SL |
586 | key!(ar); |
587 | key!(pre_link_args, list); | |
588 | key!(pre_link_objects_exe, list); | |
589 | key!(pre_link_objects_dll, list); | |
590 | key!(late_link_args, list); | |
591 | key!(post_link_objects, list); | |
592 | key!(post_link_args, list); | |
32a655c1 | 593 | key!(asm_args, list); |
5bcae85e SL |
594 | key!(cpu); |
595 | key!(features); | |
596 | key!(dynamic_linking, bool); | |
597 | key!(executables, bool); | |
1a4d82fc JJ |
598 | key!(relocation_model); |
599 | key!(code_model); | |
5bcae85e SL |
600 | key!(disable_redzone, bool); |
601 | key!(eliminate_frame_pointer, bool); | |
602 | key!(function_sections, bool); | |
1a4d82fc JJ |
603 | key!(dll_prefix); |
604 | key!(dll_suffix); | |
605 | key!(exe_suffix); | |
606 | key!(staticlib_prefix); | |
607 | key!(staticlib_suffix); | |
92a42be0 | 608 | key!(target_family, optional); |
476ff2be | 609 | key!(is_like_openbsd, bool); |
1a4d82fc | 610 | key!(is_like_osx, bool); |
5bcae85e | 611 | key!(is_like_solaris, bool); |
1a4d82fc | 612 | key!(is_like_windows, bool); |
a7813a04 | 613 | key!(is_like_msvc, bool); |
8bb4bdeb | 614 | key!(is_like_emscripten, bool); |
5bcae85e | 615 | key!(is_like_android, bool); |
1a4d82fc | 616 | key!(linker_is_gnu, bool); |
5bcae85e | 617 | key!(allows_weak_linkage, bool); |
1a4d82fc | 618 | key!(has_rpath, bool); |
b039eaaf | 619 | key!(no_default_libraries, bool); |
5bcae85e | 620 | key!(position_independent_executables, bool); |
92a42be0 | 621 | key!(archive_format); |
e9174d1e | 622 | key!(allow_asm, bool); |
92a42be0 | 623 | key!(custom_unwind_resume, bool); |
5bcae85e SL |
624 | key!(lib_allocation_crate); |
625 | key!(exe_allocation_crate); | |
626 | key!(has_elf_tls, bool); | |
627 | key!(obj_is_bitcode, bool); | |
476ff2be | 628 | key!(no_integrated_as, bool); |
c30ab7b3 | 629 | key!(max_atomic_width, Option<u64>); |
32a655c1 | 630 | key!(min_atomic_width, Option<u64>); |
c30ab7b3 | 631 | try!(key!(panic_strategy, PanicStrategy)); |
476ff2be | 632 | key!(crt_static_default, bool); |
c30ab7b3 SL |
633 | |
634 | if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { | |
635 | for name in array.iter().filter_map(|abi| abi.as_string()) { | |
636 | match lookup_abi(name) { | |
637 | Some(abi) => { | |
638 | if abi.generic() { | |
639 | return Err(format!("The ABI \"{}\" is considered to be supported on \ | |
640 | all targets and cannot be blacklisted", abi)) | |
641 | } | |
642 | ||
643 | base.options.abi_blacklist.push(abi) | |
644 | } | |
645 | None => return Err(format!("Unknown ABI \"{}\" in target specification", name)) | |
646 | } | |
647 | } | |
648 | } | |
1a4d82fc | 649 | |
5bcae85e | 650 | Ok(base) |
1a4d82fc JJ |
651 | } |
652 | ||
c34b1796 AL |
653 | /// Search RUST_TARGET_PATH for a JSON file specifying the given target |
654 | /// triple. Note that it could also just be a bare filename already, so also | |
655 | /// check for that. If one of the hardcoded targets we know about, just | |
656 | /// return it directly. | |
1a4d82fc | 657 | /// |
c34b1796 AL |
658 | /// The error string could come from any of the APIs called, including |
659 | /// filesystem access and JSON decoding. | |
1a4d82fc | 660 | pub fn search(target: &str) -> Result<Target, String> { |
85aaf69f SL |
661 | use std::env; |
662 | use std::ffi::OsString; | |
c34b1796 AL |
663 | use std::fs::File; |
664 | use std::path::{Path, PathBuf}; | |
1a4d82fc JJ |
665 | use serialize::json; |
666 | ||
667 | fn load_file(path: &Path) -> Result<Target, String> { | |
54a0048b | 668 | let mut f = File::open(path).map_err(|e| e.to_string())?; |
c34b1796 | 669 | let mut contents = Vec::new(); |
54a0048b SL |
670 | f.read_to_end(&mut contents).map_err(|e| e.to_string())?; |
671 | let obj = json::from_reader(&mut &contents[..]) | |
672 | .map_err(|e| e.to_string())?; | |
5bcae85e | 673 | Target::from_json(obj) |
1a4d82fc JJ |
674 | } |
675 | ||
5bcae85e | 676 | if let Ok(t) = load_specific(target) { |
7453a54e | 677 | return Ok(t) |
1a4d82fc JJ |
678 | } |
679 | ||
1a4d82fc JJ |
680 | let path = Path::new(target); |
681 | ||
682 | if path.is_file() { | |
683 | return load_file(&path); | |
684 | } | |
685 | ||
686 | let path = { | |
687 | let mut target = target.to_string(); | |
688 | target.push_str(".json"); | |
c34b1796 | 689 | PathBuf::from(target) |
1a4d82fc JJ |
690 | }; |
691 | ||
c34b1796 AL |
692 | let target_path = env::var_os("RUST_TARGET_PATH") |
693 | .unwrap_or(OsString::new()); | |
1a4d82fc | 694 | |
1a4d82fc JJ |
695 | // FIXME 16351: add a sane default search path? |
696 | ||
85aaf69f | 697 | for dir in env::split_paths(&target_path) { |
c34b1796 | 698 | let p = dir.join(&path); |
1a4d82fc JJ |
699 | if p.is_file() { |
700 | return load_file(&p); | |
701 | } | |
702 | } | |
703 | ||
704 | Err(format!("Could not find specification for target {:?}", target)) | |
705 | } | |
706 | } | |
e9174d1e | 707 | |
5bcae85e SL |
708 | impl ToJson for Target { |
709 | fn to_json(&self) -> Json { | |
710 | let mut d = BTreeMap::new(); | |
711 | let default: TargetOptions = Default::default(); | |
712 | ||
713 | macro_rules! target_val { | |
714 | ($attr:ident) => ( { | |
715 | let name = (stringify!($attr)).replace("_", "-"); | |
716 | d.insert(name.to_string(), self.$attr.to_json()); | |
717 | } ); | |
718 | ($attr:ident, $key_name:expr) => ( { | |
719 | let name = $key_name; | |
720 | d.insert(name.to_string(), self.$attr.to_json()); | |
721 | } ); | |
722 | } | |
723 | ||
724 | macro_rules! target_option_val { | |
725 | ($attr:ident) => ( { | |
726 | let name = (stringify!($attr)).replace("_", "-"); | |
727 | if default.$attr != self.options.$attr { | |
728 | d.insert(name.to_string(), self.options.$attr.to_json()); | |
729 | } | |
730 | } ); | |
731 | ($attr:ident, $key_name:expr) => ( { | |
732 | let name = $key_name; | |
733 | if default.$attr != self.options.$attr { | |
734 | d.insert(name.to_string(), self.options.$attr.to_json()); | |
735 | } | |
736 | } ); | |
737 | } | |
738 | ||
739 | target_val!(llvm_target); | |
740 | target_val!(target_endian); | |
741 | target_val!(target_pointer_width); | |
742 | target_val!(arch); | |
743 | target_val!(target_os, "os"); | |
744 | target_val!(target_env, "env"); | |
745 | target_val!(target_vendor, "vendor"); | |
746 | target_val!(arch); | |
747 | target_val!(data_layout); | |
748 | ||
749 | target_option_val!(is_builtin); | |
750 | target_option_val!(linker); | |
751 | target_option_val!(ar); | |
752 | target_option_val!(pre_link_args); | |
753 | target_option_val!(pre_link_objects_exe); | |
754 | target_option_val!(pre_link_objects_dll); | |
755 | target_option_val!(late_link_args); | |
756 | target_option_val!(post_link_objects); | |
757 | target_option_val!(post_link_args); | |
32a655c1 | 758 | target_option_val!(asm_args); |
5bcae85e SL |
759 | target_option_val!(cpu); |
760 | target_option_val!(features); | |
761 | target_option_val!(dynamic_linking); | |
762 | target_option_val!(executables); | |
763 | target_option_val!(relocation_model); | |
764 | target_option_val!(code_model); | |
765 | target_option_val!(disable_redzone); | |
766 | target_option_val!(eliminate_frame_pointer); | |
767 | target_option_val!(function_sections); | |
768 | target_option_val!(dll_prefix); | |
769 | target_option_val!(dll_suffix); | |
770 | target_option_val!(exe_suffix); | |
771 | target_option_val!(staticlib_prefix); | |
772 | target_option_val!(staticlib_suffix); | |
773 | target_option_val!(target_family); | |
476ff2be | 774 | target_option_val!(is_like_openbsd); |
5bcae85e SL |
775 | target_option_val!(is_like_osx); |
776 | target_option_val!(is_like_solaris); | |
777 | target_option_val!(is_like_windows); | |
778 | target_option_val!(is_like_msvc); | |
8bb4bdeb | 779 | target_option_val!(is_like_emscripten); |
5bcae85e SL |
780 | target_option_val!(is_like_android); |
781 | target_option_val!(linker_is_gnu); | |
782 | target_option_val!(allows_weak_linkage); | |
783 | target_option_val!(has_rpath); | |
5bcae85e SL |
784 | target_option_val!(no_default_libraries); |
785 | target_option_val!(position_independent_executables); | |
786 | target_option_val!(archive_format); | |
787 | target_option_val!(allow_asm); | |
788 | target_option_val!(custom_unwind_resume); | |
789 | target_option_val!(lib_allocation_crate); | |
790 | target_option_val!(exe_allocation_crate); | |
791 | target_option_val!(has_elf_tls); | |
792 | target_option_val!(obj_is_bitcode); | |
476ff2be | 793 | target_option_val!(no_integrated_as); |
32a655c1 | 794 | target_option_val!(min_atomic_width); |
5bcae85e | 795 | target_option_val!(max_atomic_width); |
c30ab7b3 | 796 | target_option_val!(panic_strategy); |
476ff2be | 797 | target_option_val!(crt_static_default); |
c30ab7b3 SL |
798 | |
799 | if default.abi_blacklist != self.options.abi_blacklist { | |
800 | d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() | |
801 | .map(Abi::name).map(|name| name.to_json()) | |
802 | .collect::<Vec<_>>().to_json()); | |
803 | } | |
5bcae85e SL |
804 | |
805 | Json::Object(d) | |
806 | } | |
807 | } | |
808 | ||
b039eaaf | 809 | fn maybe_jemalloc() -> String { |
7453a54e | 810 | if cfg!(feature = "jemalloc") { |
e9174d1e | 811 | "alloc_jemalloc".to_string() |
7453a54e SL |
812 | } else { |
813 | "alloc_system".to_string() | |
e9174d1e SL |
814 | } |
815 | } |