]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_back/target/mod.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_back / target / mod.rs
index 2163a8a1689b601e7240806ed25563cf88294852..18686e3f1d6489e642f0735755485cba953fbe62 100644 (file)
@@ -44,7 +44,8 @@
 //! the target's settings, though `target-feature` and `link-args` will *add*
 //! to the list specified by the target, rather than replace.
 
-use serialize::json::Json;
+use serialize::json::{Json, ToJson};
+use std::collections::BTreeMap;
 use std::default::Default;
 use std::io::prelude::*;
 use syntax::abi::Abi;
@@ -63,27 +64,61 @@ mod solaris_base;
 mod windows_base;
 mod windows_msvc_base;
 
+pub type TargetResult = Result<Target, String>;
+
 macro_rules! supported_targets {
     ( $(($triple:expr, $module:ident)),+ ) => (
         $(mod $module;)*
 
         /// List of supported targets
-        pub const TARGETS: &'static [&'static str] = &[$($triple),*];
+        const TARGETS: &'static [&'static str] = &[$($triple),*];
+
+        fn load_specific(target: &str) -> TargetResult {
+            match target {
+                $(
+                    $triple => {
+                        let mut t = try!($module::target());
+                        t.options.is_builtin = true;
+
+                        // round-trip through the JSON parser to ensure at
+                        // run-time that the parser works correctly
+                        t = try!(Target::from_json(t.to_json()));
+                        debug!("Got builtin target: {:?}", t);
+                        Ok(t)
+                    },
+                )+
+                _ => Err(format!("Unable to find target: {}", target))
+            }
+        }
+
+        pub fn get_targets() -> Box<Iterator<Item=String>> {
+            Box::new(TARGETS.iter().filter_map(|t| -> Option<String> {
+                load_specific(t)
+                    .and(Ok(t.to_string()))
+                    .ok()
+            }))
+        }
+
+        #[cfg(test)]
+        mod test_json_encode_decode {
+            use serialize::json::ToJson;
+            use super::Target;
+            $(use super::$module;)*
 
-        // this would use a match if stringify! were allowed in pattern position
-        fn load_specific(target: &str) -> Option<Target> {
-            let target = target.replace("-", "_");
-            if false { }
             $(
-                else if target == stringify!($module) {
-                    let mut t = $module::target();
-                    t.options.is_builtin = true;
-                    debug!("Got builtin target: {:?}", t);
-                    return Some(t);
+                #[test]
+                fn $module() {
+                    // Grab the TargetResult struct. If we successfully retrieved
+                    // a Target, then the test JSON encoding/decoding can run for this
+                    // Target on this testing platform (i.e., checking the iOS targets
+                    // only on a Mac test platform).
+                    let _ = $module::target().map(|original| {
+                        let as_json = original.to_json();
+                        let parsed = Target::from_json(as_json).unwrap();
+                        assert_eq!(original, parsed);
+                    });
                 }
             )*
-
-            None
         }
     )
 }
@@ -99,7 +134,10 @@ supported_targets! {
     ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
     ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
     ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
+    ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
+    ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
     ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
+    ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
     ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
     ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
     ("i686-unknown-linux-musl", i686_unknown_linux_musl),
@@ -147,7 +185,7 @@ supported_targets! {
 /// Everything `rustc` knows about how to compile for a specific target.
 ///
 /// Every field here must be specified, and has no default value.
-#[derive(Clone, Debug)]
+#[derive(PartialEq, Clone, Debug)]
 pub struct Target {
     /// Target triple to pass to LLVM.
     pub llvm_target: String,
@@ -174,7 +212,7 @@ pub struct Target {
 ///
 /// This has an implementation of `Default`, see each field for what the default is. In general,
 /// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
-#[derive(Clone, Debug)]
+#[derive(PartialEq, Clone, Debug)]
 pub struct TargetOptions {
     /// Whether the target is built-in or loaded from a custom target specification.
     pub is_builtin: bool,
@@ -254,6 +292,13 @@ pub struct TargetOptions {
     pub is_like_android: bool,
     /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
     pub linker_is_gnu: bool,
+    /// The MinGW toolchain has a known issue that prevents it from correctly
+    /// handling COFF object files with more than 2^15 sections. Since each weak
+    /// symbol needs its own COMDAT section, weak linkage implies a large
+    /// number sections that easily exceeds the given limit for larger
+    /// codebases. Consequently we want a way to disallow weak linkage on some
+    /// platforms.
+    pub allows_weak_linkage: bool,
     /// Whether the linker support rpaths or not. Defaults to false.
     pub has_rpath: bool,
     /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
@@ -329,6 +374,7 @@ impl Default for TargetOptions {
             is_like_android: false,
             is_like_msvc: false,
             linker_is_gnu: false,
+            allows_weak_linkage: true,
             has_rpath: false,
             no_compiler_rt: false,
             no_default_libraries: true,
@@ -365,16 +411,21 @@ impl Target {
     }
 
     /// Load a target descriptor from a JSON object.
-    pub fn from_json(obj: Json) -> Target {
-        // this is 1. ugly, 2. error prone.
+    pub fn from_json(obj: Json) -> TargetResult {
+        // While ugly, this code must remain this way to retain
+        // compatibility with existing JSON fields and the internal
+        // expected naming of the Target and TargetOptions structs.
+        // To ensure compatibility is retained, the built-in targets
+        // are round-tripped through this code to catch cases where
+        // the JSON parser is not updated to match the structs.
 
         let get_req_field = |name: &str| {
             match obj.find(name)
                      .map(|s| s.as_string())
                      .and_then(|os| os.map(|s| s.to_string())) {
-                Some(val) => val,
+                Some(val) => Ok(val),
                 None => {
-                    panic!("Field {} in target specification is required", name)
+                    return Err(format!("Field {} in target specification is required", name))
                 }
             }
         };
@@ -386,12 +437,12 @@ impl Target {
         };
 
         let mut base = Target {
-            llvm_target: get_req_field("llvm-target"),
-            target_endian: get_req_field("target-endian"),
-            target_pointer_width: get_req_field("target-pointer-width"),
-            data_layout: get_req_field("data-layout"),
-            arch: get_req_field("arch"),
-            target_os: get_req_field("os"),
+            llvm_target: try!(get_req_field("llvm-target")),
+            target_endian: try!(get_req_field("target-endian")),
+            target_pointer_width: try!(get_req_field("target-pointer-width")),
+            data_layout: try!(get_req_field("data-layout")),
+            arch: try!(get_req_field("arch")),
+            target_os: try!(get_req_field("os")),
             target_env: get_opt_field("env", ""),
             target_vendor: get_opt_field("vendor", "unknown"),
             options: Default::default(),
@@ -436,38 +487,51 @@ impl Target {
             } );
         }
 
-        key!(cpu);
-        key!(ar);
+        key!(is_builtin, bool);
         key!(linker);
+        key!(ar);
+        key!(pre_link_args, list);
+        key!(pre_link_objects_exe, list);
+        key!(pre_link_objects_dll, list);
+        key!(late_link_args, list);
+        key!(post_link_objects, list);
+        key!(post_link_args, list);
+        key!(cpu);
+        key!(features);
+        key!(dynamic_linking, bool);
+        key!(executables, bool);
         key!(relocation_model);
         key!(code_model);
+        key!(disable_redzone, bool);
+        key!(eliminate_frame_pointer, bool);
+        key!(function_sections, bool);
         key!(dll_prefix);
         key!(dll_suffix);
         key!(exe_suffix);
         key!(staticlib_prefix);
         key!(staticlib_suffix);
-        key!(features);
-        key!(dynamic_linking, bool);
-        key!(executables, bool);
-        key!(disable_redzone, bool);
-        key!(eliminate_frame_pointer, bool);
-        key!(function_sections, bool);
         key!(target_family, optional);
         key!(is_like_osx, bool);
+        key!(is_like_solaris, bool);
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
+        key!(is_like_android, bool);
         key!(linker_is_gnu, bool);
+        key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
         key!(no_compiler_rt, bool);
         key!(no_default_libraries, bool);
-        key!(pre_link_args, list);
-        key!(post_link_args, list);
+        key!(position_independent_executables, bool);
         key!(archive_format);
         key!(allow_asm, bool);
         key!(custom_unwind_resume, bool);
+        key!(lib_allocation_crate);
+        key!(exe_allocation_crate);
+        key!(has_elf_tls, bool);
+        key!(obj_is_bitcode, bool);
         key!(max_atomic_width, u64);
 
-        base
+        Ok(base)
     }
 
     /// Search RUST_TARGET_PATH for a JSON file specifying the given target
@@ -490,10 +554,10 @@ impl Target {
             f.read_to_end(&mut contents).map_err(|e| e.to_string())?;
             let obj = json::from_reader(&mut &contents[..])
                            .map_err(|e| e.to_string())?;
-            Ok(Target::from_json(obj))
+            Target::from_json(obj)
         }
 
-        if let Some(t) = load_specific(target) {
+        if let Ok(t) = load_specific(target) {
             return Ok(t)
         }
 
@@ -525,6 +589,95 @@ impl Target {
     }
 }
 
+impl ToJson for Target {
+    fn to_json(&self) -> Json {
+        let mut d = BTreeMap::new();
+        let default: TargetOptions = Default::default();
+
+        macro_rules! target_val {
+            ($attr:ident) => ( {
+                let name = (stringify!($attr)).replace("_", "-");
+                d.insert(name.to_string(), self.$attr.to_json());
+            } );
+            ($attr:ident, $key_name:expr) => ( {
+                let name = $key_name;
+                d.insert(name.to_string(), self.$attr.to_json());
+            } );
+        }
+
+        macro_rules! target_option_val {
+            ($attr:ident) => ( {
+                let name = (stringify!($attr)).replace("_", "-");
+                if default.$attr != self.options.$attr {
+                    d.insert(name.to_string(), self.options.$attr.to_json());
+                }
+            } );
+            ($attr:ident, $key_name:expr) => ( {
+                let name = $key_name;
+                if default.$attr != self.options.$attr {
+                    d.insert(name.to_string(), self.options.$attr.to_json());
+                }
+            } );
+        }
+
+        target_val!(llvm_target);
+        target_val!(target_endian);
+        target_val!(target_pointer_width);
+        target_val!(arch);
+        target_val!(target_os, "os");
+        target_val!(target_env, "env");
+        target_val!(target_vendor, "vendor");
+        target_val!(arch);
+        target_val!(data_layout);
+
+        target_option_val!(is_builtin);
+        target_option_val!(linker);
+        target_option_val!(ar);
+        target_option_val!(pre_link_args);
+        target_option_val!(pre_link_objects_exe);
+        target_option_val!(pre_link_objects_dll);
+        target_option_val!(late_link_args);
+        target_option_val!(post_link_objects);
+        target_option_val!(post_link_args);
+        target_option_val!(cpu);
+        target_option_val!(features);
+        target_option_val!(dynamic_linking);
+        target_option_val!(executables);
+        target_option_val!(relocation_model);
+        target_option_val!(code_model);
+        target_option_val!(disable_redzone);
+        target_option_val!(eliminate_frame_pointer);
+        target_option_val!(function_sections);
+        target_option_val!(dll_prefix);
+        target_option_val!(dll_suffix);
+        target_option_val!(exe_suffix);
+        target_option_val!(staticlib_prefix);
+        target_option_val!(staticlib_suffix);
+        target_option_val!(target_family);
+        target_option_val!(is_like_osx);
+        target_option_val!(is_like_solaris);
+        target_option_val!(is_like_windows);
+        target_option_val!(is_like_msvc);
+        target_option_val!(is_like_android);
+        target_option_val!(linker_is_gnu);
+        target_option_val!(allows_weak_linkage);
+        target_option_val!(has_rpath);
+        target_option_val!(no_compiler_rt);
+        target_option_val!(no_default_libraries);
+        target_option_val!(position_independent_executables);
+        target_option_val!(archive_format);
+        target_option_val!(allow_asm);
+        target_option_val!(custom_unwind_resume);
+        target_option_val!(lib_allocation_crate);
+        target_option_val!(exe_allocation_crate);
+        target_option_val!(has_elf_tls);
+        target_option_val!(obj_is_bitcode);
+        target_option_val!(max_atomic_width);
+
+        Json::Object(d)
+    }
+}
+
 fn maybe_jemalloc() -> String {
     if cfg!(feature = "jemalloc") {
         "alloc_jemalloc".to_string()