Skip to content

Commit af56e2e

Browse files
committed
rustc_back: Tweak the MSVC target spec
This change primarily changes the default ar utility used by MSVC-targeting compilers as `llvm-ar`, adding comments along the way as to why.
1 parent 37659a1 commit af56e2e

File tree

4 files changed

+60
-13
lines changed

4 files changed

+60
-13
lines changed

src/librustc_back/target/mod.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ pub struct Target {
9393
pub struct TargetOptions {
9494
/// Linker to invoke. Defaults to "cc".
9595
pub linker: String,
96+
/// Archive utility to use when managing archives. Defaults to "ar".
97+
pub ar: String,
9698
/// Linker arguments that are unconditionally passed *before* any
9799
/// user-defined libraries.
98100
pub pre_link_args: Vec<String>,
@@ -154,22 +156,24 @@ pub struct TargetOptions {
154156
pub linker_is_gnu: bool,
155157
/// Whether the linker support rpaths or not. Defaults to false.
156158
pub has_rpath: bool,
157-
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
158-
/// to the functions that compiler-rt provides.
159+
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
160+
/// will emit references to the functions that compiler-rt provides.
159161
pub no_compiler_rt: bool,
160-
/// Dynamically linked executables can be compiled as position independent if the default
161-
/// relocation model of position independent code is not changed. This is a requirement to take
162-
/// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
163-
/// be used during an exploit of a vulnerability in any code.
162+
/// Dynamically linked executables can be compiled as position independent
163+
/// if the default relocation model of position independent code is not
164+
/// changed. This is a requirement to take advantage of ASLR, as otherwise
165+
/// the functions in the executable are not randomized and can be used
166+
/// during an exploit of a vulnerability in any code.
164167
pub position_independent_executables: bool,
165168
}
166169

167170
impl Default for TargetOptions {
168-
/// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
169-
/// compilation, will certainly not work.
171+
/// Create a set of "sane defaults" for any target. This is still
172+
/// incomplete, and if used for compilation, will certainly not work.
170173
fn default() -> TargetOptions {
171174
TargetOptions {
172175
linker: "cc".to_string(),
176+
ar: "ar".to_string(),
173177
pre_link_args: Vec::new(),
174178
post_link_args: Vec::new(),
175179
cpu: "generic".to_string(),

src/librustc_back/target/windows_msvc_base.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,38 @@ use std::default::Default;
1414
pub fn opts() -> TargetOptions {
1515
TargetOptions {
1616
function_sections: true,
17-
linker: "link".to_string(),
17+
linker: "link.exe".to_string(),
18+
// When taking a look at the value of this `ar` field, one might expect
19+
// `lib.exe` to be the value here! The `lib.exe` program is the default
20+
// tool for managing `.lib` archives on Windows, but unfortunately the
21+
// compiler cannot use it.
22+
//
23+
// To recap, we use `ar` here to manage rlibs (which are just archives).
24+
// LLVM does not expose bindings for modifying archives so we have to
25+
// invoke this utility for write operations (e.g. deleting files, adding
26+
// files, etc). Normally archives only have object files within them,
27+
// but the compiler also uses archives for storing metadata and
28+
// compressed bytecode, so we don't exactly fall within "normal use
29+
// cases".
30+
//
31+
// MSVC's `lib.exe` tool by default will choke when adding a non-object
32+
// file to an archive, which we do on a regular basis, making it
33+
// inoperable for us. Luckily, however, LLVM has already rewritten `ar`
34+
// in the form of `llvm-ar` which is built by default when we build
35+
// LLVM. This tool, unlike `lib.exe`, works just fine with non-object
36+
// files, so we use it instead.
37+
//
38+
// Note that there's a few caveats associated with this:
39+
//
40+
// * This still requires that the *linker* (the consumer of rlibs) will
41+
// ignore non-object files. Thankfully `link.exe` on Windows does
42+
// indeed ignore non-object files in archives.
43+
// * This requires `llvm-ar.exe` to be distributed with the compiler
44+
// itself, but we already make sure of this elsewhere.
45+
//
46+
// Perhaps one day we won't even need this tool at all and we'll just be
47+
// able to make library calls into LLVM!
48+
ar: "llvm-ar.exe".to_string(),
1849
dynamic_linking: true,
1950
executables: true,
2051
dll_prefix: "".to_string(),
@@ -25,7 +56,10 @@ pub fn opts() -> TargetOptions {
2556
morestack: false,
2657
is_like_windows: true,
2758
is_like_msvc: true,
28-
pre_link_args: Vec::new(),
59+
pre_link_args: vec![
60+
"/NOLOGO".to_string(),
61+
"/NXCOMPAT".to_string(),
62+
],
2963

3064
.. Default::default()
3165
}

src/librustc_back/target/x86_64_pc_windows_msvc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ pub fn target() -> Target {
1515
base.cpu = "x86-64".to_string();
1616

1717
Target {
18-
// FIXME: Test this. Copied from linux (#2398)
18+
// This is currently in sync with the specification for
19+
// x86_64-pc-windows-gnu but there's a comment in that file questioning
20+
// whether this is valid or not. Sounds like the two should stay in sync
21+
// at least for now.
1922
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
2023
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
2124
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),

src/librustc_trans/back/link.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ pub fn get_cc_prog(sess: &Session) -> String {
365365
}
366366
}
367367

368+
pub fn get_ar_prog(sess: &Session) -> String {
369+
sess.opts.cg.ar.clone().unwrap_or_else(|| {
370+
sess.target.target.options.ar.clone()
371+
})
372+
}
373+
368374
pub fn remove(sess: &Session, path: &Path) {
369375
match fs::remove_file(path) {
370376
Ok(..) => {}
@@ -547,7 +553,7 @@ fn link_rlib<'a>(sess: &'a Session,
547553
lib_search_paths: archive_search_paths(sess),
548554
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
549555
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
550-
maybe_ar_prog: sess.opts.cg.ar.clone()
556+
ar_prog: get_ar_prog(sess),
551557
};
552558
let mut ab = ArchiveBuilder::create(config);
553559
ab.add_file(obj_filename).unwrap();
@@ -1181,7 +1187,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
11811187
lib_search_paths: archive_search_paths(sess),
11821188
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
11831189
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
1184-
maybe_ar_prog: sess.opts.cg.ar.clone()
1190+
ar_prog: get_ar_prog(sess),
11851191
};
11861192
let mut archive = Archive::open(config);
11871193
archive.remove_file(&format!("{}.o", name));

0 commit comments

Comments
 (0)