diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index e46bdbb5ccf4..ad8e0c1ee59f 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -636,7 +636,7 @@ fn link_natively(sess: &Session, { let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, - objects, out_filename, outputs); + objects, out_filename, outputs, trans); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -711,7 +711,8 @@ fn link_args(cmd: &mut Linker, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, - outputs: &OutputFilenames) { + outputs: &OutputFilenames, + trans: &CrateTranslation) { // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -726,6 +727,13 @@ fn link_args(cmd: &mut Linker, } cmd.output_filename(out_filename); + if crate_type == config::CrateTypeExecutable && + sess.target.target.options.is_like_windows { + if let Some(ref s) = trans.windows_subsystem { + cmd.subsystem(s); + } + } + // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. if crate_type != config::CrateTypeExecutable { diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 3222571a76e1..860903d259fe 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -92,6 +92,7 @@ pub trait Linker { fn whole_archives(&mut self); fn no_whole_archives(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); + fn subsystem(&mut self, subsystem: &str); } pub struct GnuLinker<'a> { @@ -294,6 +295,10 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg(arg); } + + fn subsystem(&mut self, subsystem: &str) { + self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); + } } pub struct MsvcLinker<'a> { @@ -441,6 +446,30 @@ impl<'a> Linker for MsvcLinker<'a> { arg.push(path); self.cmd.arg(&arg); } + + fn subsystem(&mut self, subsystem: &str) { + // Note that previous passes of the compiler validated this subsystem, + // so we just blindly pass it to the linker. + self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); + + // Windows has two subsystems we're interested in right now, the console + // and windows subsystems. These both implicitly have different entry + // points (starting symbols). The console entry point starts with + // `mainCRTStartup` and the windows entry point starts with + // `WinMainCRTStartup`. These entry points, defined in system libraries, + // will then later probe for either `main` or `WinMain`, respectively to + // start the application. + // + // In Rust we just always generate a `main` function so we want control + // to always start there, so we force the entry point on the windows + // subsystem to be `mainCRTStartup` to get everything booted up + // correctly. + // + // For more information see RFC #1665 + if subsystem == "windows" { + self.cmd.arg("/ENTRY:mainCRTStartup"); + } + } } fn exported_symbols(scx: &SharedCrateContext, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 977ababbf568..d30183a13f1f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1611,7 +1611,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: vec![], no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: None, }; } @@ -1747,6 +1748,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); + let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + CrateTranslation { modules: modules, metadata_module: metadata_module, @@ -1754,7 +1766,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: reachable_symbols, no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: windows_subsystem, } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 07acc54962b8..37304f28e03f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -169,6 +169,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub no_builtins: bool, + pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 129e4a823380..bf6482e5b99d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -309,6 +309,9 @@ declare_features! ( // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (active, field_init_shorthand, "1.14.0", Some(37340)), + + // The #![windows_subsystem] attribute + (active, windows_subsystem, "1.14.0", Some(37499)), ); declare_features! ( @@ -713,6 +716,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat "defining reflective traits is still evolving", cfg_fn!(reflect))), + ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, + "windows_subsystem", + "the windows subsystem attribute \ + id currently unstable", + cfg_fn!(windows_subsystem))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/compile-fail/windows-subsystem-gated.rs new file mode 100644 index 000000000000..4b563e78e55c --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-gated.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![windows_subsystem = "console"] +//~^ ERROR: the windows subsystem attribute is currently unstable + +fn main() {} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs new file mode 100644 index 000000000000..28c3950e76f2 --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(windows_subsystem)] +#![windows_subsystem = "wrong"] +//~^ ERROR: invalid subsystem `wrong`, only `windows` and `console` are allowed + +fn main() {} diff --git a/src/test/run-make/windows-subsystem/Makefile b/src/test/run-make/windows-subsystem/Makefile new file mode 100644 index 000000000000..34fb5db32f95 --- /dev/null +++ b/src/test/run-make/windows-subsystem/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + $(RUSTC) windows.rs + $(RUSTC) console.rs diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs new file mode 100644 index 000000000000..3aedb0ecab72 --- /dev/null +++ b/src/test/run-make/windows-subsystem/console.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(windows_subsystem)] +#![windows_subsystem = "console"] + +fn main() {} + diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs new file mode 100644 index 000000000000..5d875a5a1bf1 --- /dev/null +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(windows_subsystem)] +#![windows_subsystem = "windows"] + +fn main() {}