| use std::assert_matches::assert_matches; |
| |
| use super::super::*; |
| |
| // Test target self-consistency and JSON encoding/decoding roundtrip. |
| pub(super) fn test_target(mut target: Target) { |
| let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j); |
| target.update_to_cli(); |
| target.check_consistency(); |
| assert_eq!(recycled_target, Ok(target)); |
| } |
| |
| impl Target { |
| fn check_consistency(&self) { |
| assert_eq!(self.is_like_osx, self.vendor == "apple"); |
| assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos"); |
| assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi"); |
| assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64"); |
| if self.is_like_msvc { |
| assert!(self.is_like_windows); |
| } |
| |
| // Check that default linker flavor is compatible with some other key properties. |
| assert_eq!(self.is_like_osx, matches!(self.linker_flavor, LinkerFlavor::Darwin(..))); |
| assert_eq!(self.is_like_msvc, matches!(self.linker_flavor, LinkerFlavor::Msvc(..))); |
| assert_eq!( |
| self.is_like_wasm && self.os != "emscripten", |
| matches!(self.linker_flavor, LinkerFlavor::WasmLld(..)) |
| ); |
| assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc)); |
| assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf)); |
| assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx)); |
| |
| for args in [ |
| &self.pre_link_args, |
| &self.late_link_args, |
| &self.late_link_args_dynamic, |
| &self.late_link_args_static, |
| &self.post_link_args, |
| ] { |
| for (&flavor, flavor_args) in args { |
| assert!(!flavor_args.is_empty()); |
| // Check that flavors mentioned in link args are compatible with the default flavor. |
| match self.linker_flavor { |
| LinkerFlavor::Gnu(..) => { |
| assert_matches!(flavor, LinkerFlavor::Gnu(..)); |
| } |
| LinkerFlavor::Darwin(..) => { |
| assert_matches!(flavor, LinkerFlavor::Darwin(..)) |
| } |
| LinkerFlavor::WasmLld(..) => { |
| assert_matches!(flavor, LinkerFlavor::WasmLld(..)) |
| } |
| LinkerFlavor::Unix(..) => { |
| assert_matches!(flavor, LinkerFlavor::Unix(..)); |
| } |
| LinkerFlavor::Msvc(..) => { |
| assert_matches!(flavor, LinkerFlavor::Msvc(..)) |
| } |
| LinkerFlavor::EmCc |
| | LinkerFlavor::Bpf |
| | LinkerFlavor::Ptx |
| | LinkerFlavor::Llbc => { |
| assert_eq!(flavor, self.linker_flavor) |
| } |
| } |
| |
| // Check that link args for cc and non-cc versions of flavors are consistent. |
| let check_noncc = |noncc_flavor| { |
| if let Some(noncc_args) = args.get(&noncc_flavor) { |
| for arg in flavor_args { |
| if let Some(suffix) = arg.strip_prefix("-Wl,") { |
| assert!(noncc_args.iter().any(|a| a == suffix)); |
| } |
| } |
| } |
| }; |
| |
| match self.linker_flavor { |
| LinkerFlavor::Gnu(Cc::Yes, lld) => check_noncc(LinkerFlavor::Gnu(Cc::No, lld)), |
| LinkerFlavor::WasmLld(Cc::Yes) => check_noncc(LinkerFlavor::WasmLld(Cc::No)), |
| LinkerFlavor::Unix(Cc::Yes) => check_noncc(LinkerFlavor::Unix(Cc::No)), |
| _ => {} |
| } |
| } |
| |
| // Check that link args for lld and non-lld versions of flavors are consistent. |
| for cc in [Cc::No, Cc::Yes] { |
| assert_eq!( |
| args.get(&LinkerFlavor::Gnu(cc, Lld::No)), |
| args.get(&LinkerFlavor::Gnu(cc, Lld::Yes)), |
| ); |
| assert_eq!( |
| args.get(&LinkerFlavor::Darwin(cc, Lld::No)), |
| args.get(&LinkerFlavor::Darwin(cc, Lld::Yes)), |
| ); |
| } |
| assert_eq!( |
| args.get(&LinkerFlavor::Msvc(Lld::No)), |
| args.get(&LinkerFlavor::Msvc(Lld::Yes)), |
| ); |
| } |
| |
| if self.link_self_contained.is_disabled() { |
| assert!( |
| self.pre_link_objects_self_contained.is_empty() |
| && self.post_link_objects_self_contained.is_empty() |
| ); |
| } |
| |
| // If your target really needs to deviate from the rules below, |
| // except it and document the reasons. |
| // Keep the default "unknown" vendor instead. |
| assert_ne!(self.vendor, ""); |
| assert_ne!(self.os, ""); |
| if !self.can_use_os_unknown() { |
| // Keep the default "none" for bare metal targets instead. |
| assert_ne!(self.os, "unknown"); |
| } |
| |
| // Check dynamic linking stuff |
| // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries. |
| // hexagon: when targeting QuRT, that OS can load dynamic libraries. |
| // wasm{32,64}: dynamic linking is inherent in the definition of the VM. |
| if self.os == "none" |
| && (self.arch != "bpf" |
| && self.arch != "hexagon" |
| && self.arch != "wasm32" |
| && self.arch != "wasm64") |
| { |
| assert!(!self.dynamic_linking); |
| } |
| if self.only_cdylib |
| || self.crt_static_allows_dylibs |
| || !self.late_link_args_dynamic.is_empty() |
| { |
| assert!(self.dynamic_linking); |
| } |
| // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs |
| if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") { |
| assert_eq!(self.relocation_model, RelocModel::Pic); |
| } |
| if self.position_independent_executables { |
| assert_eq!(self.relocation_model, RelocModel::Pic); |
| } |
| // The UEFI targets do not support dynamic linking but still require PIC (#101377). |
| if self.relocation_model == RelocModel::Pic && self.os != "uefi" { |
| assert!(self.dynamic_linking || self.position_independent_executables); |
| } |
| if self.static_position_independent_executables { |
| assert!(self.position_independent_executables); |
| } |
| if self.position_independent_executables { |
| assert!(self.executables); |
| } |
| |
| // Check crt static stuff |
| if self.crt_static_default || self.crt_static_allows_dylibs { |
| assert!(self.crt_static_respected); |
| } |
| |
| // Check that RISC-V targets always specify which ABI they use. |
| match &*self.arch { |
| "riscv32" => { |
| assert_matches!(&*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e") |
| } |
| "riscv64" => { |
| // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. |
| assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q" | "lp64e") |
| } |
| _ => {} |
| } |
| } |
| |
| // Add your target to the whitelist if it has `std` library |
| // and you certainly want "unknown" for the OS name. |
| fn can_use_os_unknown(&self) -> bool { |
| self.llvm_target == "wasm32-unknown-unknown" |
| || self.llvm_target == "wasm64-unknown-unknown" |
| || (self.env == "sgx" && self.vendor == "fortanix") |
| } |
| } |