]>
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::*; |
7453a54e | 51 | use syntax::abi::Abi; |
1a4d82fc | 52 | |
d9579d0f | 53 | mod android_base; |
1a4d82fc | 54 | mod apple_base; |
85aaf69f | 55 | mod apple_ios_base; |
c34b1796 | 56 | mod bitrig_base; |
d9579d0f AL |
57 | mod dragonfly_base; |
58 | mod freebsd_base; | |
59 | mod linux_base; | |
a7813a04 | 60 | mod linux_musl_base; |
85aaf69f | 61 | mod openbsd_base; |
c1a9b12d | 62 | mod netbsd_base; |
7453a54e | 63 | mod solaris_base; |
d9579d0f | 64 | mod windows_base; |
62682a34 | 65 | mod windows_msvc_base; |
1a4d82fc | 66 | |
5bcae85e SL |
67 | pub type TargetResult = Result<Target, String>; |
68 | ||
7453a54e SL |
69 | macro_rules! supported_targets { |
70 | ( $(($triple:expr, $module:ident)),+ ) => ( | |
71 | $(mod $module;)* | |
72 | ||
73 | /// List of supported targets | |
5bcae85e SL |
74 | const TARGETS: &'static [&'static str] = &[$($triple),*]; |
75 | ||
76 | fn load_specific(target: &str) -> TargetResult { | |
77 | match target { | |
78 | $( | |
79 | $triple => { | |
80 | let mut t = try!($module::target()); | |
81 | t.options.is_builtin = true; | |
82 | ||
83 | // round-trip through the JSON parser to ensure at | |
84 | // run-time that the parser works correctly | |
85 | t = try!(Target::from_json(t.to_json())); | |
86 | debug!("Got builtin target: {:?}", t); | |
87 | Ok(t) | |
88 | }, | |
89 | )+ | |
90 | _ => Err(format!("Unable to find target: {}", target)) | |
91 | } | |
92 | } | |
93 | ||
94 | pub fn get_targets() -> Box<Iterator<Item=String>> { | |
95 | Box::new(TARGETS.iter().filter_map(|t| -> Option<String> { | |
96 | load_specific(t) | |
97 | .and(Ok(t.to_string())) | |
98 | .ok() | |
99 | })) | |
100 | } | |
101 | ||
102 | #[cfg(test)] | |
103 | mod test_json_encode_decode { | |
104 | use serialize::json::ToJson; | |
105 | use super::Target; | |
106 | $(use super::$module;)* | |
7453a54e | 107 | |
7453a54e | 108 | $( |
5bcae85e SL |
109 | #[test] |
110 | fn $module() { | |
111 | // Grab the TargetResult struct. If we successfully retrieved | |
112 | // a Target, then the test JSON encoding/decoding can run for this | |
113 | // Target on this testing platform (i.e., checking the iOS targets | |
114 | // only on a Mac test platform). | |
115 | let _ = $module::target().map(|original| { | |
116 | let as_json = original.to_json(); | |
117 | let parsed = Target::from_json(as_json).unwrap(); | |
118 | assert_eq!(original, parsed); | |
119 | }); | |
7453a54e SL |
120 | } |
121 | )* | |
7453a54e SL |
122 | } |
123 | ) | |
124 | } | |
125 | ||
126 | supported_targets! { | |
127 | ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu), | |
128 | ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), | |
129 | ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), | |
130 | ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), | |
131 | ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), | |
132 | ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), | |
133 | ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), | |
134 | ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), | |
135 | ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), | |
136 | ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), | |
5bcae85e SL |
137 | ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), |
138 | ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), | |
7453a54e | 139 | ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), |
5bcae85e | 140 | ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), |
7453a54e SL |
141 | ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), |
142 | ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), | |
143 | ("i686-unknown-linux-musl", i686_unknown_linux_musl), | |
144 | ("mips-unknown-linux-musl", mips_unknown_linux_musl), | |
145 | ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl), | |
146 | ||
147 | ("i686-linux-android", i686_linux_android), | |
148 | ("arm-linux-androideabi", arm_linux_androideabi), | |
a7813a04 | 149 | ("armv7-linux-androideabi", armv7_linux_androideabi), |
7453a54e SL |
150 | ("aarch64-linux-android", aarch64_linux_android), |
151 | ||
152 | ("i686-unknown-freebsd", i686_unknown_freebsd), | |
153 | ("x86_64-unknown-freebsd", x86_64_unknown_freebsd), | |
154 | ||
155 | ("i686-unknown-dragonfly", i686_unknown_dragonfly), | |
156 | ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), | |
157 | ||
158 | ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), | |
159 | ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), | |
160 | ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), | |
161 | ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), | |
162 | ||
163 | ("x86_64-apple-darwin", x86_64_apple_darwin), | |
164 | ("i686-apple-darwin", i686_apple_darwin), | |
165 | ||
166 | ("i386-apple-ios", i386_apple_ios), | |
167 | ("x86_64-apple-ios", x86_64_apple_ios), | |
168 | ("aarch64-apple-ios", aarch64_apple_ios), | |
169 | ("armv7-apple-ios", armv7_apple_ios), | |
170 | ("armv7s-apple-ios", armv7s_apple_ios), | |
171 | ||
172 | ("x86_64-sun-solaris", x86_64_sun_solaris), | |
173 | ||
174 | ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), | |
175 | ("i686-pc-windows-gnu", i686_pc_windows_gnu), | |
176 | ||
177 | ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), | |
178 | ("i686-pc-windows-msvc", i686_pc_windows_msvc), | |
54a0048b | 179 | ("i586-pc-windows-msvc", i586_pc_windows_msvc), |
7453a54e SL |
180 | |
181 | ("le32-unknown-nacl", le32_unknown_nacl), | |
182 | ("asmjs-unknown-emscripten", asmjs_unknown_emscripten) | |
183 | } | |
184 | ||
1a4d82fc JJ |
185 | /// Everything `rustc` knows about how to compile for a specific target. |
186 | /// | |
187 | /// Every field here must be specified, and has no default value. | |
5bcae85e | 188 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 189 | pub struct Target { |
1a4d82fc JJ |
190 | /// Target triple to pass to LLVM. |
191 | pub llvm_target: String, | |
192 | /// String to use as the `target_endian` `cfg` variable. | |
193 | pub target_endian: String, | |
194 | /// String to use as the `target_pointer_width` `cfg` variable. | |
195 | pub target_pointer_width: String, | |
196 | /// OS name to use for conditional compilation. | |
197 | pub target_os: String, | |
d9579d0f AL |
198 | /// Environment name to use for conditional compilation. |
199 | pub target_env: String, | |
b039eaaf SL |
200 | /// Vendor name to use for conditional compilation. |
201 | pub target_vendor: String, | |
7453a54e SL |
202 | /// Architecture to use for ABI considerations. Valid options: "x86", |
203 | /// "x86_64", "arm", "aarch64", "mips", "powerpc", and "powerpc64". | |
1a4d82fc | 204 | pub arch: String, |
54a0048b SL |
205 | /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. |
206 | pub data_layout: String, | |
1a4d82fc JJ |
207 | /// Optional settings with defaults. |
208 | pub options: TargetOptions, | |
209 | } | |
210 | ||
211 | /// Optional aspects of a target specification. | |
212 | /// | |
213 | /// This has an implementation of `Default`, see each field for what the default is. In general, | |
214 | /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. | |
5bcae85e | 215 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 216 | pub struct TargetOptions { |
54a0048b SL |
217 | /// Whether the target is built-in or loaded from a custom target specification. |
218 | pub is_builtin: bool, | |
219 | ||
1a4d82fc JJ |
220 | /// Linker to invoke. Defaults to "cc". |
221 | pub linker: String, | |
62682a34 SL |
222 | /// Archive utility to use when managing archives. Defaults to "ar". |
223 | pub ar: String, | |
92a42be0 | 224 | |
d9579d0f AL |
225 | /// Linker arguments that are unconditionally passed *before* any |
226 | /// user-defined libraries. | |
1a4d82fc | 227 | pub pre_link_args: Vec<String>, |
92a42be0 SL |
228 | /// Objects to link before all others, always found within the |
229 | /// sysroot folder. | |
230 | pub pre_link_objects_exe: Vec<String>, // ... when linking an executable | |
231 | pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib | |
232 | /// Linker arguments that are unconditionally passed after any | |
233 | /// user-defined but before post_link_objects. Standard platform | |
234 | /// libraries that should be always be linked to, usually go here. | |
235 | pub late_link_args: Vec<String>, | |
236 | /// Objects to link after all others, always found within the | |
237 | /// sysroot folder. | |
238 | pub post_link_objects: Vec<String>, | |
d9579d0f AL |
239 | /// Linker arguments that are unconditionally passed *after* any |
240 | /// user-defined libraries. | |
1a4d82fc | 241 | pub post_link_args: Vec<String>, |
92a42be0 | 242 | |
d9579d0f | 243 | /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults |
a7813a04 | 244 | /// to "generic". |
1a4d82fc | 245 | pub cpu: String, |
d9579d0f AL |
246 | /// Default target features to pass to LLVM. These features will *always* be |
247 | /// passed, and cannot be disabled even via `-C`. Corresponds to `llc | |
248 | /// -mattr=$features`. | |
1a4d82fc JJ |
249 | pub features: String, |
250 | /// Whether dynamic linking is available on this target. Defaults to false. | |
251 | pub dynamic_linking: bool, | |
252 | /// Whether executables are available on this target. iOS, for example, only allows static | |
253 | /// libraries. Defaults to false. | |
254 | pub executables: bool, | |
1a4d82fc JJ |
255 | /// Relocation model to use in object file. Corresponds to `llc |
256 | /// -relocation-model=$relocation_model`. Defaults to "pic". | |
257 | pub relocation_model: String, | |
258 | /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default". | |
259 | pub code_model: String, | |
260 | /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. | |
261 | pub disable_redzone: bool, | |
262 | /// Eliminate frame pointers from stack frames if possible. Defaults to true. | |
263 | pub eliminate_frame_pointer: bool, | |
264 | /// Emit each function in its own section. Defaults to true. | |
265 | pub function_sections: bool, | |
266 | /// String to prepend to the name of every dynamic library. Defaults to "lib". | |
267 | pub dll_prefix: String, | |
268 | /// String to append to the name of every dynamic library. Defaults to ".so". | |
269 | pub dll_suffix: String, | |
270 | /// String to append to the name of every executable. | |
271 | pub exe_suffix: String, | |
272 | /// String to prepend to the name of every static library. Defaults to "lib". | |
273 | pub staticlib_prefix: String, | |
274 | /// String to append to the name of every static library. Defaults to ".a". | |
275 | pub staticlib_suffix: String, | |
92a42be0 SL |
276 | /// OS family to use for conditional compilation. Valid options: "unix", "windows". |
277 | pub target_family: Option<String>, | |
1a4d82fc JJ |
278 | /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in |
279 | /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. | |
280 | pub is_like_osx: bool, | |
7453a54e SL |
281 | /// Whether the target toolchain is like Solaris's. |
282 | /// Only useful for compiling against Illumos/Solaris, | |
283 | /// as they have a different set of linker flags. Defaults to false. | |
284 | pub is_like_solaris: bool, | |
1a4d82fc | 285 | /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows, |
c34b1796 | 286 | /// only really used for figuring out how to find libraries, since Windows uses its own |
1a4d82fc JJ |
287 | /// library naming convention. Defaults to false. |
288 | pub is_like_windows: bool, | |
62682a34 | 289 | pub is_like_msvc: bool, |
85aaf69f SL |
290 | /// Whether the target toolchain is like Android's. Only useful for compiling against Android. |
291 | /// Defaults to false. | |
292 | pub is_like_android: bool, | |
1a4d82fc JJ |
293 | /// Whether the linker support GNU-like arguments such as -O. Defaults to false. |
294 | pub linker_is_gnu: bool, | |
5bcae85e SL |
295 | /// The MinGW toolchain has a known issue that prevents it from correctly |
296 | /// handling COFF object files with more than 2^15 sections. Since each weak | |
297 | /// symbol needs its own COMDAT section, weak linkage implies a large | |
298 | /// number sections that easily exceeds the given limit for larger | |
299 | /// codebases. Consequently we want a way to disallow weak linkage on some | |
300 | /// platforms. | |
301 | pub allows_weak_linkage: bool, | |
1a4d82fc JJ |
302 | /// Whether the linker support rpaths or not. Defaults to false. |
303 | pub has_rpath: bool, | |
62682a34 SL |
304 | /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM |
305 | /// will emit references to the functions that compiler-rt provides. | |
1a4d82fc | 306 | pub no_compiler_rt: bool, |
b039eaaf SL |
307 | /// Whether to disable linking to the default libraries, typically corresponds |
308 | /// to `-nodefaultlibs`. Defaults to true. | |
309 | pub no_default_libraries: bool, | |
62682a34 SL |
310 | /// Dynamically linked executables can be compiled as position independent |
311 | /// if the default relocation model of position independent code is not | |
312 | /// changed. This is a requirement to take advantage of ASLR, as otherwise | |
313 | /// the functions in the executable are not randomized and can be used | |
314 | /// during an exploit of a vulnerability in any code. | |
1a4d82fc | 315 | pub position_independent_executables: bool, |
c1a9b12d SL |
316 | /// Format that archives should be emitted in. This affects whether we use |
317 | /// LLVM to assemble an archive or fall back to the system linker, and | |
318 | /// currently only "gnu" is used to fall into LLVM. Unknown strings cause | |
319 | /// the system linker to be used. | |
320 | pub archive_format: String, | |
e9174d1e SL |
321 | /// Is asm!() allowed? Defaults to true. |
322 | pub allow_asm: bool, | |
c1a9b12d SL |
323 | /// Whether the target uses a custom unwind resumption routine. |
324 | /// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume` | |
325 | /// defined in libgcc. If this option is enabled, the target must provide | |
326 | /// `eh_unwind_resume` lang item. | |
327 | pub custom_unwind_resume: bool, | |
e9174d1e SL |
328 | |
329 | /// Default crate for allocation symbols to link against | |
330 | pub lib_allocation_crate: String, | |
331 | pub exe_allocation_crate: String, | |
9cc50fc6 SL |
332 | |
333 | /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for | |
334 | /// this target. | |
335 | pub has_elf_tls: bool, | |
7453a54e SL |
336 | // This is mainly for easy compatibility with emscripten. |
337 | // If we give emcc .o files that are actually .bc files it | |
338 | // will 'just work'. | |
339 | pub obj_is_bitcode: bool, | |
a7813a04 XL |
340 | |
341 | /// Maximum integer size in bits that this target can perform atomic | |
342 | /// operations on. | |
343 | pub max_atomic_width: u64, | |
1a4d82fc JJ |
344 | } |
345 | ||
346 | impl Default for TargetOptions { | |
62682a34 SL |
347 | /// Create a set of "sane defaults" for any target. This is still |
348 | /// incomplete, and if used for compilation, will certainly not work. | |
1a4d82fc JJ |
349 | fn default() -> TargetOptions { |
350 | TargetOptions { | |
54a0048b | 351 | is_builtin: false, |
e9174d1e SL |
352 | linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), |
353 | ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), | |
1a4d82fc JJ |
354 | pre_link_args: Vec::new(), |
355 | post_link_args: Vec::new(), | |
356 | cpu: "generic".to_string(), | |
357 | features: "".to_string(), | |
358 | dynamic_linking: false, | |
359 | executables: false, | |
1a4d82fc JJ |
360 | relocation_model: "pic".to_string(), |
361 | code_model: "default".to_string(), | |
362 | disable_redzone: false, | |
363 | eliminate_frame_pointer: true, | |
364 | function_sections: true, | |
365 | dll_prefix: "lib".to_string(), | |
366 | dll_suffix: ".so".to_string(), | |
367 | exe_suffix: "".to_string(), | |
368 | staticlib_prefix: "lib".to_string(), | |
369 | staticlib_suffix: ".a".to_string(), | |
92a42be0 | 370 | target_family: None, |
1a4d82fc | 371 | is_like_osx: false, |
7453a54e | 372 | is_like_solaris: false, |
1a4d82fc | 373 | is_like_windows: false, |
85aaf69f | 374 | is_like_android: false, |
62682a34 | 375 | is_like_msvc: false, |
1a4d82fc | 376 | linker_is_gnu: false, |
5bcae85e | 377 | allows_weak_linkage: true, |
1a4d82fc JJ |
378 | has_rpath: false, |
379 | no_compiler_rt: false, | |
b039eaaf | 380 | no_default_libraries: true, |
1a4d82fc | 381 | position_independent_executables: false, |
92a42be0 SL |
382 | pre_link_objects_exe: Vec::new(), |
383 | pre_link_objects_dll: Vec::new(), | |
d9579d0f | 384 | post_link_objects: Vec::new(), |
92a42be0 | 385 | late_link_args: Vec::new(), |
7453a54e | 386 | archive_format: "gnu".to_string(), |
c1a9b12d | 387 | custom_unwind_resume: false, |
e9174d1e SL |
388 | lib_allocation_crate: "alloc_system".to_string(), |
389 | exe_allocation_crate: "alloc_system".to_string(), | |
390 | allow_asm: true, | |
9cc50fc6 | 391 | has_elf_tls: false, |
7453a54e | 392 | obj_is_bitcode: false, |
a7813a04 | 393 | max_atomic_width: 0, |
1a4d82fc JJ |
394 | } |
395 | } | |
396 | } | |
397 | ||
398 | impl Target { | |
399 | /// Given a function ABI, turn "System" into the correct ABI for this target. | |
7453a54e | 400 | pub fn adjust_abi(&self, abi: Abi) -> Abi { |
1a4d82fc | 401 | match abi { |
7453a54e | 402 | Abi::System => { |
1a4d82fc | 403 | if self.options.is_like_windows && self.arch == "x86" { |
7453a54e | 404 | Abi::Stdcall |
1a4d82fc | 405 | } else { |
7453a54e | 406 | Abi::C |
1a4d82fc JJ |
407 | } |
408 | }, | |
409 | abi => abi | |
410 | } | |
411 | } | |
412 | ||
413 | /// Load a target descriptor from a JSON object. | |
5bcae85e SL |
414 | pub fn from_json(obj: Json) -> TargetResult { |
415 | // While ugly, this code must remain this way to retain | |
416 | // compatibility with existing JSON fields and the internal | |
417 | // expected naming of the Target and TargetOptions structs. | |
418 | // To ensure compatibility is retained, the built-in targets | |
419 | // are round-tripped through this code to catch cases where | |
420 | // the JSON parser is not updated to match the structs. | |
1a4d82fc | 421 | |
85aaf69f | 422 | let get_req_field = |name: &str| { |
1a4d82fc JJ |
423 | match obj.find(name) |
424 | .map(|s| s.as_string()) | |
425 | .and_then(|os| os.map(|s| s.to_string())) { | |
5bcae85e | 426 | Some(val) => Ok(val), |
92a42be0 | 427 | None => { |
5bcae85e | 428 | return Err(format!("Field {} in target specification is required", name)) |
92a42be0 | 429 | } |
1a4d82fc JJ |
430 | } |
431 | }; | |
432 | ||
b039eaaf SL |
433 | let get_opt_field = |name: &str, default: &str| { |
434 | obj.find(name).and_then(|s| s.as_string()) | |
435 | .map(|s| s.to_string()) | |
436 | .unwrap_or(default.to_string()) | |
437 | }; | |
438 | ||
1a4d82fc | 439 | let mut base = Target { |
5bcae85e SL |
440 | llvm_target: try!(get_req_field("llvm-target")), |
441 | target_endian: try!(get_req_field("target-endian")), | |
442 | target_pointer_width: try!(get_req_field("target-pointer-width")), | |
443 | data_layout: try!(get_req_field("data-layout")), | |
444 | arch: try!(get_req_field("arch")), | |
445 | target_os: try!(get_req_field("os")), | |
b039eaaf SL |
446 | target_env: get_opt_field("env", ""), |
447 | target_vendor: get_opt_field("vendor", "unknown"), | |
1a4d82fc JJ |
448 | options: Default::default(), |
449 | }; | |
450 | ||
a7813a04 XL |
451 | // Default max-atomic-width to target-pointer-width |
452 | base.options.max_atomic_width = base.target_pointer_width.parse().unwrap(); | |
453 | ||
1a4d82fc JJ |
454 | macro_rules! key { |
455 | ($key_name:ident) => ( { | |
456 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 457 | obj.find(&name[..]).map(|o| o.as_string() |
1a4d82fc JJ |
458 | .map(|s| base.options.$key_name = s.to_string())); |
459 | } ); | |
460 | ($key_name:ident, bool) => ( { | |
461 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 462 | obj.find(&name[..]) |
1a4d82fc JJ |
463 | .map(|o| o.as_boolean() |
464 | .map(|s| base.options.$key_name = s)); | |
465 | } ); | |
a7813a04 XL |
466 | ($key_name:ident, u64) => ( { |
467 | let name = (stringify!($key_name)).replace("_", "-"); | |
468 | obj.find(&name[..]) | |
469 | .map(|o| o.as_u64() | |
470 | .map(|s| base.options.$key_name = s)); | |
471 | } ); | |
1a4d82fc JJ |
472 | ($key_name:ident, list) => ( { |
473 | let name = (stringify!($key_name)).replace("_", "-"); | |
85aaf69f | 474 | obj.find(&name[..]).map(|o| o.as_array() |
1a4d82fc JJ |
475 | .map(|v| base.options.$key_name = v.iter() |
476 | .map(|a| a.as_string().unwrap().to_string()).collect() | |
477 | ) | |
478 | ); | |
479 | } ); | |
e9174d1e SL |
480 | ($key_name:ident, optional) => ( { |
481 | let name = (stringify!($key_name)).replace("_", "-"); | |
482 | if let Some(o) = obj.find(&name[..]) { | |
483 | base.options.$key_name = o | |
484 | .as_string() | |
485 | .map(|s| s.to_string() ); | |
486 | } | |
487 | } ); | |
1a4d82fc JJ |
488 | } |
489 | ||
5bcae85e | 490 | key!(is_builtin, bool); |
1a4d82fc | 491 | key!(linker); |
5bcae85e SL |
492 | key!(ar); |
493 | key!(pre_link_args, list); | |
494 | key!(pre_link_objects_exe, list); | |
495 | key!(pre_link_objects_dll, list); | |
496 | key!(late_link_args, list); | |
497 | key!(post_link_objects, list); | |
498 | key!(post_link_args, list); | |
499 | key!(cpu); | |
500 | key!(features); | |
501 | key!(dynamic_linking, bool); | |
502 | key!(executables, bool); | |
1a4d82fc JJ |
503 | key!(relocation_model); |
504 | key!(code_model); | |
5bcae85e SL |
505 | key!(disable_redzone, bool); |
506 | key!(eliminate_frame_pointer, bool); | |
507 | key!(function_sections, bool); | |
1a4d82fc JJ |
508 | key!(dll_prefix); |
509 | key!(dll_suffix); | |
510 | key!(exe_suffix); | |
511 | key!(staticlib_prefix); | |
512 | key!(staticlib_suffix); | |
92a42be0 | 513 | key!(target_family, optional); |
1a4d82fc | 514 | key!(is_like_osx, bool); |
5bcae85e | 515 | key!(is_like_solaris, bool); |
1a4d82fc | 516 | key!(is_like_windows, bool); |
a7813a04 | 517 | key!(is_like_msvc, bool); |
5bcae85e | 518 | key!(is_like_android, bool); |
1a4d82fc | 519 | key!(linker_is_gnu, bool); |
5bcae85e | 520 | key!(allows_weak_linkage, bool); |
1a4d82fc JJ |
521 | key!(has_rpath, bool); |
522 | key!(no_compiler_rt, bool); | |
b039eaaf | 523 | key!(no_default_libraries, bool); |
5bcae85e | 524 | key!(position_independent_executables, bool); |
92a42be0 | 525 | key!(archive_format); |
e9174d1e | 526 | key!(allow_asm, bool); |
92a42be0 | 527 | key!(custom_unwind_resume, bool); |
5bcae85e SL |
528 | key!(lib_allocation_crate); |
529 | key!(exe_allocation_crate); | |
530 | key!(has_elf_tls, bool); | |
531 | key!(obj_is_bitcode, bool); | |
a7813a04 | 532 | key!(max_atomic_width, u64); |
1a4d82fc | 533 | |
5bcae85e | 534 | Ok(base) |
1a4d82fc JJ |
535 | } |
536 | ||
c34b1796 AL |
537 | /// Search RUST_TARGET_PATH for a JSON file specifying the given target |
538 | /// triple. Note that it could also just be a bare filename already, so also | |
539 | /// check for that. If one of the hardcoded targets we know about, just | |
540 | /// return it directly. | |
1a4d82fc | 541 | /// |
c34b1796 AL |
542 | /// The error string could come from any of the APIs called, including |
543 | /// filesystem access and JSON decoding. | |
1a4d82fc | 544 | pub fn search(target: &str) -> Result<Target, String> { |
85aaf69f SL |
545 | use std::env; |
546 | use std::ffi::OsString; | |
c34b1796 AL |
547 | use std::fs::File; |
548 | use std::path::{Path, PathBuf}; | |
1a4d82fc JJ |
549 | use serialize::json; |
550 | ||
551 | fn load_file(path: &Path) -> Result<Target, String> { | |
54a0048b | 552 | let mut f = File::open(path).map_err(|e| e.to_string())?; |
c34b1796 | 553 | let mut contents = Vec::new(); |
54a0048b SL |
554 | f.read_to_end(&mut contents).map_err(|e| e.to_string())?; |
555 | let obj = json::from_reader(&mut &contents[..]) | |
556 | .map_err(|e| e.to_string())?; | |
5bcae85e | 557 | Target::from_json(obj) |
1a4d82fc JJ |
558 | } |
559 | ||
5bcae85e | 560 | if let Ok(t) = load_specific(target) { |
7453a54e | 561 | return Ok(t) |
1a4d82fc JJ |
562 | } |
563 | ||
1a4d82fc JJ |
564 | let path = Path::new(target); |
565 | ||
566 | if path.is_file() { | |
567 | return load_file(&path); | |
568 | } | |
569 | ||
570 | let path = { | |
571 | let mut target = target.to_string(); | |
572 | target.push_str(".json"); | |
c34b1796 | 573 | PathBuf::from(target) |
1a4d82fc JJ |
574 | }; |
575 | ||
c34b1796 AL |
576 | let target_path = env::var_os("RUST_TARGET_PATH") |
577 | .unwrap_or(OsString::new()); | |
1a4d82fc | 578 | |
1a4d82fc JJ |
579 | // FIXME 16351: add a sane default search path? |
580 | ||
85aaf69f | 581 | for dir in env::split_paths(&target_path) { |
c34b1796 | 582 | let p = dir.join(&path); |
1a4d82fc JJ |
583 | if p.is_file() { |
584 | return load_file(&p); | |
585 | } | |
586 | } | |
587 | ||
588 | Err(format!("Could not find specification for target {:?}", target)) | |
589 | } | |
590 | } | |
e9174d1e | 591 | |
5bcae85e SL |
592 | impl ToJson for Target { |
593 | fn to_json(&self) -> Json { | |
594 | let mut d = BTreeMap::new(); | |
595 | let default: TargetOptions = Default::default(); | |
596 | ||
597 | macro_rules! target_val { | |
598 | ($attr:ident) => ( { | |
599 | let name = (stringify!($attr)).replace("_", "-"); | |
600 | d.insert(name.to_string(), self.$attr.to_json()); | |
601 | } ); | |
602 | ($attr:ident, $key_name:expr) => ( { | |
603 | let name = $key_name; | |
604 | d.insert(name.to_string(), self.$attr.to_json()); | |
605 | } ); | |
606 | } | |
607 | ||
608 | macro_rules! target_option_val { | |
609 | ($attr:ident) => ( { | |
610 | let name = (stringify!($attr)).replace("_", "-"); | |
611 | if default.$attr != self.options.$attr { | |
612 | d.insert(name.to_string(), self.options.$attr.to_json()); | |
613 | } | |
614 | } ); | |
615 | ($attr:ident, $key_name:expr) => ( { | |
616 | let name = $key_name; | |
617 | if default.$attr != self.options.$attr { | |
618 | d.insert(name.to_string(), self.options.$attr.to_json()); | |
619 | } | |
620 | } ); | |
621 | } | |
622 | ||
623 | target_val!(llvm_target); | |
624 | target_val!(target_endian); | |
625 | target_val!(target_pointer_width); | |
626 | target_val!(arch); | |
627 | target_val!(target_os, "os"); | |
628 | target_val!(target_env, "env"); | |
629 | target_val!(target_vendor, "vendor"); | |
630 | target_val!(arch); | |
631 | target_val!(data_layout); | |
632 | ||
633 | target_option_val!(is_builtin); | |
634 | target_option_val!(linker); | |
635 | target_option_val!(ar); | |
636 | target_option_val!(pre_link_args); | |
637 | target_option_val!(pre_link_objects_exe); | |
638 | target_option_val!(pre_link_objects_dll); | |
639 | target_option_val!(late_link_args); | |
640 | target_option_val!(post_link_objects); | |
641 | target_option_val!(post_link_args); | |
642 | target_option_val!(cpu); | |
643 | target_option_val!(features); | |
644 | target_option_val!(dynamic_linking); | |
645 | target_option_val!(executables); | |
646 | target_option_val!(relocation_model); | |
647 | target_option_val!(code_model); | |
648 | target_option_val!(disable_redzone); | |
649 | target_option_val!(eliminate_frame_pointer); | |
650 | target_option_val!(function_sections); | |
651 | target_option_val!(dll_prefix); | |
652 | target_option_val!(dll_suffix); | |
653 | target_option_val!(exe_suffix); | |
654 | target_option_val!(staticlib_prefix); | |
655 | target_option_val!(staticlib_suffix); | |
656 | target_option_val!(target_family); | |
657 | target_option_val!(is_like_osx); | |
658 | target_option_val!(is_like_solaris); | |
659 | target_option_val!(is_like_windows); | |
660 | target_option_val!(is_like_msvc); | |
661 | target_option_val!(is_like_android); | |
662 | target_option_val!(linker_is_gnu); | |
663 | target_option_val!(allows_weak_linkage); | |
664 | target_option_val!(has_rpath); | |
665 | target_option_val!(no_compiler_rt); | |
666 | target_option_val!(no_default_libraries); | |
667 | target_option_val!(position_independent_executables); | |
668 | target_option_val!(archive_format); | |
669 | target_option_val!(allow_asm); | |
670 | target_option_val!(custom_unwind_resume); | |
671 | target_option_val!(lib_allocation_crate); | |
672 | target_option_val!(exe_allocation_crate); | |
673 | target_option_val!(has_elf_tls); | |
674 | target_option_val!(obj_is_bitcode); | |
675 | target_option_val!(max_atomic_width); | |
676 | ||
677 | Json::Object(d) | |
678 | } | |
679 | } | |
680 | ||
b039eaaf | 681 | fn maybe_jemalloc() -> String { |
7453a54e | 682 | if cfg!(feature = "jemalloc") { |
e9174d1e | 683 | "alloc_jemalloc".to_string() |
7453a54e SL |
684 | } else { |
685 | "alloc_system".to_string() | |
e9174d1e SL |
686 | } |
687 | } |