diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 4c66d901e7a99..86aed9105aecf 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1571,9 +1571,19 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // OBJECT-FILES-NO, AUDIT-ORDER add_rpath_args(cmd, sess, codegen_results, out_filename); + // OBJECT-FILES-NO + if let Some(args) = sess.target.target.options.link_args.get(&flavor) { + cmd.args(&args.unordered_right_overridable); + } + // OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_user_defined_link_args(cmd, sess, codegen_results); + // OBJECT-FILES-NO + if let Some(args) = sess.target.target.options.link_args.get(&flavor) { + cmd.args(&args.unordered_left_overridable); + } + // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER cmd.finalize(); @@ -1586,6 +1596,11 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_post_link_args(cmd, sess, flavor); + // OBJECT-FILES-NO + if let Some(args) = sess.target.target.options.link_args.get(&flavor) { + cmd.args(&args.unordered_non_overridable); + } + cmd.take_cmd() } diff --git a/src/librustc_target/spec/i686_pc_windows_msvc.rs b/src/librustc_target/spec/i686_pc_windows_msvc.rs index 9d0922b8ce5a9..869559c9723a9 100644 --- a/src/librustc_target/spec/i686_pc_windows_msvc.rs +++ b/src/librustc_target/spec/i686_pc_windows_msvc.rs @@ -5,7 +5,7 @@ pub fn target() -> TargetResult { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - let pre_link_args_msvc = vec![ + let new_link_args = vec![ // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. "/LARGEADDRESSAWARE".to_string(), @@ -14,11 +14,16 @@ pub fn target() -> TargetResult { // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers "/SAFESEH".to_string(), ]; - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); - base.pre_link_args + base.link_args + .get_mut(&LinkerFlavor::Msvc) + .unwrap() + .unordered_right_overridable + .extend(new_link_args.clone()); + base.link_args .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) .unwrap() - .extend(pre_link_args_msvc); + .unordered_right_overridable + .extend(new_link_args); Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 8f3097ad4233e..17294aedf2bdd 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -549,6 +549,26 @@ impl HasTargetSpec for Target { } } +/// "Unordered" options are options applied to the whole linking process rather than to individual +/// input object files or libraries. So it doesn't matter whether they are passed before or after +/// input files. +#[derive(Default, PartialEq, Clone, Debug)] +pub struct NewLinkArgs { + /// These options cannot be overridden once specified. + /// So they can be passed anywhere on the command line. + pub unordered_non_overridable: Vec, + /// These option can be overridden by options placed to the left from them on the command line. + /// So they need to be placed after customization points like `-C link-args`. + /// (Library search directories traversed from left to right is a typical example.) + pub unordered_left_overridable: Vec, + /// These option can be overridden by options placed to the right from them on the command line. + /// So they need to be placed before customization points like `-C link-args`. + /// (Options like `-foo=yes` overridden by `-foo=no` is a typical example.) + pub unordered_right_overridable: Vec, +} + +type LinkArgsMap = BTreeMap; + /// Optional aspects of a target specification. /// /// This has an implementation of `Default`, see each field for what the default is. In general, @@ -565,6 +585,9 @@ pub struct TargetOptions { /// without clarifying its flavor in any way. pub lld_flavor: LldFlavor, + /// New style default linker arguments. + /// Other link arg fields are supposed to be migrated to them eventually. + pub link_args: LinkArgsMap, /// Linker arguments that are passed *before* any user-defined libraries. pub pre_link_args: LinkArgs, // ... unconditionally pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt @@ -812,6 +835,7 @@ impl Default for TargetOptions { is_builtin: false, linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()), lld_flavor: LldFlavor::Ld, + link_args: Default::default(), pre_link_args: LinkArgs::new(), pre_link_args_crt: LinkArgs::new(), post_link_args: LinkArgs::new(), diff --git a/src/librustc_target/spec/msvc_base.rs b/src/librustc_target/spec/msvc_base.rs index 817a322a9e4da..59629d5fd62a3 100644 --- a/src/librustc_target/spec/msvc_base.rs +++ b/src/librustc_target/spec/msvc_base.rs @@ -1,21 +1,39 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +// https://docs.microsoft.com/en-us/cpp/build/reference/linking +// https://docs.microsoft.com/en-us/cpp/build/reference/libpath-additional-libpath +// > LINK first processes options specified in the LINK environment variable, followed by options +// > in the order they are specified on the command line and in command files. +// > If an option is repeated with different arguments, the last one processed takes precedence. +// > Options apply to the entire build; no options can be applied to specific input files. +// > If you want to specify more than one directory, you must specify multiple /LIBPATH options. +// > The linker will then search the specified directories in order. +// +// Therefore all options that are not input files are order-independent and either non-overridable +// or right-overridable. Library search directories are left-overridable. + +use crate::spec::{LinkArgsMap, LinkerFlavor, LldFlavor, NewLinkArgs, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args_msvc = vec![ - // Suppress the verbose logo and authorship debugging output, which would needlessly - // clog any log files. - "/NOLOGO".to_string(), - // Tell the compiler that non-code sections can be marked as non-executable, - // including stack pages. - // UEFI is fully compatible to non-executable data pages. - // In fact, firmware might enforce this, so we better let the linker know about this, - // so it will fail if the compiler ever tries placing code on the stack - // (e.g., trampoline constructs and alike). - "/NXCOMPAT".to_string(), - ]; - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone()); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc); + let new_link_args = NewLinkArgs { + unordered_non_overridable: vec![ + // Suppress the verbose logo and authorship debugging output, which would needlessly + // clog any log files. + "/NOLOGO".to_string(), + ], + unordered_right_overridable: vec![ + // Tell the compiler that non-code sections can be marked as non-executable, + // including stack pages. + // UEFI is fully compatible to non-executable data pages. + // In fact, firmware might enforce this, so we better let the linker know about this, + // so it will fail if the compiler ever tries placing code on the stack + // (e.g., trampoline constructs and alike). + "/NXCOMPAT".to_string(), + ], + ..Default::default() + }; + + let mut link_args = LinkArgsMap::new(); + link_args.insert(LinkerFlavor::Msvc, new_link_args.clone()); + link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), new_link_args); TargetOptions { executables: true, @@ -26,7 +44,7 @@ pub fn opts() -> TargetOptions { // messages if a link error occurred. link_env: vec![("VSLANG".to_string(), "1033".to_string())], lld_flavor: LldFlavor::Link, - pre_link_args, + link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs b/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs index 21d62d252e09a..a7ca8d295f192 100644 --- a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs +++ b/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs @@ -10,12 +10,17 @@ pub fn target() -> TargetResult { // should be smart enough to insert branch islands only // where necessary, but this is not the observed behavior. // Disabling the LBR optimization works around the issue. - let pre_link_args_msvc = "/OPT:NOLBR".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(pre_link_args_msvc.clone()); - base.pre_link_args + let new_link_args = "/OPT:NOLBR".to_string(); + base.link_args + .get_mut(&LinkerFlavor::Msvc) + .unwrap() + .unordered_right_overridable + .push(new_link_args.clone()); + base.link_args .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) .unwrap() - .push(pre_link_args_msvc); + .unordered_right_overridable + .push(new_link_args); // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is // implemented for windows/arm in LLVM diff --git a/src/librustc_target/spec/uefi_msvc_base.rs b/src/librustc_target/spec/uefi_msvc_base.rs index 3f7c78c8e7d47..67b91476a6307 100644 --- a/src/librustc_target/spec/uefi_msvc_base.rs +++ b/src/librustc_target/spec/uefi_msvc_base.rs @@ -14,7 +14,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::msvc_base::opts(); - let pre_link_args_msvc = vec![ + let new_link_args = vec![ // Non-standard subsystems have no default entry-point in PE+ files. We have to define // one. "efi_main" seems to be a common choice amongst other implementations and the // spec. @@ -30,11 +30,16 @@ pub fn opts() -> TargetOptions { // exit (default for applications). "/subsystem:efi_application".to_string(), ]; - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); - base.pre_link_args + base.link_args + .get_mut(&LinkerFlavor::Msvc) + .unwrap() + .unordered_right_overridable + .extend(new_link_args.clone()); + base.link_args .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) .unwrap() - .extend(pre_link_args_msvc); + .unordered_right_overridable + .extend(new_link_args); TargetOptions { disable_redzone: true, diff --git a/src/librustc_target/spec/windows_uwp_msvc_base.rs b/src/librustc_target/spec/windows_uwp_msvc_base.rs index 04ffa1a0addbe..1d9fa04fb4314 100644 --- a/src/librustc_target/spec/windows_uwp_msvc_base.rs +++ b/src/librustc_target/spec/windows_uwp_msvc_base.rs @@ -3,7 +3,19 @@ use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let mut opts = super::windows_msvc_base::opts(); - let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()]; + let new_link_args = vec!["/APPCONTAINER".to_string()]; + opts.link_args + .get_mut(&LinkerFlavor::Msvc) + .unwrap() + .unordered_right_overridable + .extend(new_link_args.clone()); + opts.link_args + .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) + .unwrap() + .unordered_right_overridable + .extend(new_link_args); + + let pre_link_args_msvc = vec!["mincore.lib".to_string()]; opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); opts.pre_link_args .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))