Skip to content

Commit 20c3013

Browse files
committed
rustc: Add knowledge of Windows subsystems.
This commit is an implementation of [RFC 1665] which adds support for the `#![windows_subsystem]` attribute. This attribute allows specifying either the "windows" or "console" subsystems on Windows to the linker. [RFC 1665]: https://github.com/rust-lang/rfcs/blob/master/text/1665-windows-subsystem.md Previously all Rust executables were compiled as the "console" subsystem which meant that if you wanted a graphical application it would erroneously pop up a console whenever opened. When compiling an application, however, this is undesired behavior and the "windows" subsystem is used instead to have control over user interactions. This attribute is validated, but ignored on all non-Windows platforms. cc #37499
1 parent 074d30d commit 20c3013

File tree

10 files changed

+127
-4
lines changed

10 files changed

+127
-4
lines changed

src/librustc_trans/back/link.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ fn link_natively(sess: &Session,
636636
{
637637
let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
638638
link_args(&mut *linker, sess, crate_type, tmpdir,
639-
objects, out_filename, outputs);
639+
objects, out_filename, outputs, trans);
640640
}
641641
cmd.args(&sess.target.target.options.late_link_args);
642642
for obj in &sess.target.target.options.post_link_objects {
@@ -711,7 +711,8 @@ fn link_args(cmd: &mut Linker,
711711
tmpdir: &Path,
712712
objects: &[PathBuf],
713713
out_filename: &Path,
714-
outputs: &OutputFilenames) {
714+
outputs: &OutputFilenames,
715+
trans: &CrateTranslation) {
715716

716717
// The default library location, we need this to find the runtime.
717718
// The location of crates will be determined as needed.
@@ -726,6 +727,13 @@ fn link_args(cmd: &mut Linker,
726727
}
727728
cmd.output_filename(out_filename);
728729

730+
if crate_type == config::CrateTypeExecutable &&
731+
sess.target.target.options.is_like_windows {
732+
if let Some(ref s) = trans.windows_subsystem {
733+
cmd.subsystem(s);
734+
}
735+
}
736+
729737
// If we're building a dynamic library then some platforms need to make sure
730738
// that all symbols are exported correctly from the dynamic library.
731739
if crate_type != config::CrateTypeExecutable {

src/librustc_trans/back/linker.rs

+29
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub trait Linker {
9292
fn whole_archives(&mut self);
9393
fn no_whole_archives(&mut self);
9494
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
95+
fn subsystem(&mut self, subsystem: &str);
9596
}
9697

9798
pub struct GnuLinker<'a> {
@@ -294,6 +295,10 @@ impl<'a> Linker for GnuLinker<'a> {
294295

295296
self.cmd.arg(arg);
296297
}
298+
299+
fn subsystem(&mut self, subsystem: &str) {
300+
self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
301+
}
297302
}
298303

299304
pub struct MsvcLinker<'a> {
@@ -441,6 +446,30 @@ impl<'a> Linker for MsvcLinker<'a> {
441446
arg.push(path);
442447
self.cmd.arg(&arg);
443448
}
449+
450+
fn subsystem(&mut self, subsystem: &str) {
451+
// Note that previous passes of the compiler validated this subsystem,
452+
// so we just blindly pass it to the linker.
453+
self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
454+
455+
// Windows has two subsystems we're interested in right now, the console
456+
// and windows subsystems. These both implicitly have different entry
457+
// points (starting symbols). The console entry point starts with
458+
// `mainCRTStartup` and the windows entry point starts with
459+
// `WinMainCRTStartup`. These entry points, defined in system libraries,
460+
// will then later probe for either `main` or `WinMain`, respectively to
461+
// start the application.
462+
//
463+
// In Rust we just always generate a `main` function so we want control
464+
// to always start there, so we force the entry point on the windows
465+
// subsystem to be `mainCRTStartup` to get everything booted up
466+
// correctly.
467+
//
468+
// For more information see RFC #1665
469+
if subsystem == "windows" {
470+
self.cmd.arg("/ENTRY:mainCRTStartup");
471+
}
472+
}
444473
}
445474

446475
fn exported_symbols(scx: &SharedCrateContext,

src/librustc_trans/base.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
16111611
metadata: metadata,
16121612
reachable: vec![],
16131613
no_builtins: no_builtins,
1614-
linker_info: linker_info
1614+
linker_info: linker_info,
1615+
windows_subsystem: None,
16151616
};
16161617
}
16171618

@@ -1747,14 +1748,26 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
17471748

17481749
let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols);
17491750

1751+
let subsystem = attr::first_attr_value_str_by_name(&krate.attrs,
1752+
"windows_subsystem");
1753+
let windows_subsystem = subsystem.map(|subsystem| {
1754+
if subsystem != "windows" && subsystem != "console" {
1755+
tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \
1756+
`windows` and `console` are allowed",
1757+
subsystem));
1758+
}
1759+
subsystem.to_string()
1760+
});
1761+
17501762
CrateTranslation {
17511763
modules: modules,
17521764
metadata_module: metadata_module,
17531765
link: link_meta,
17541766
metadata: metadata,
17551767
reachable: reachable_symbols,
17561768
no_builtins: no_builtins,
1757-
linker_info: linker_info
1769+
linker_info: linker_info,
1770+
windows_subsystem: windows_subsystem,
17581771
}
17591772
}
17601773

src/librustc_trans/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ pub struct CrateTranslation {
169169
pub metadata: Vec<u8>,
170170
pub reachable: Vec<String>,
171171
pub no_builtins: bool,
172+
pub windows_subsystem: Option<String>,
172173
pub linker_info: back::linker::LinkerInfo
173174
}
174175

src/libsyntax/feature_gate.rs

+9
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ declare_features! (
309309

310310
// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
311311
(active, field_init_shorthand, "1.14.0", Some(37340)),
312+
313+
// The #![windows_subsystem] attribute
314+
(active, windows_subsystem, "1.14.0", Some(37499)),
312315
);
313316

314317
declare_features! (
@@ -713,6 +716,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
713716
"defining reflective traits is still evolving",
714717
cfg_fn!(reflect))),
715718

719+
("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
720+
"windows_subsystem",
721+
"the windows subsystem attribute \
722+
id currently unstable",
723+
cfg_fn!(windows_subsystem))),
724+
716725
// Crate level attributes
717726
("crate_name", CrateLevel, Ungated),
718727
("crate_type", CrateLevel, Ungated),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2016 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+
#![windows_subsystem = "console"]
12+
//~^ ERROR: the windows subsystem attribute is currently unstable
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2016 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+
#![feature(windows_subsystem)]
12+
#![windows_subsystem = "wrong"]
13+
//~^ ERROR: invalid subsystem `wrong`, only `windows` and `console` are allowed
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) windows.rs
5+
$(RUSTC) console.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2016 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+
#![feature(windows_subsystem)]
12+
#![windows_subsystem = "console"]
13+
14+
fn main() {}
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2016 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+
#![feature(windows_subsystem)]
12+
#![windows_subsystem = "windows"]
13+
14+
fn main() {}

0 commit comments

Comments
 (0)