pub struct TargetOptions {
/// Linker to invoke. Defaults to "cc".
pub linker: String,
+ /// Archive utility to use when managing archives. Defaults to "ar".
+ pub ar: String,
/// Linker arguments that are unconditionally passed *before* any
/// user-defined libraries.
pub pre_link_args: Vec<String>,
pub linker_is_gnu: bool,
/// Whether the linker support rpaths or not. Defaults to false.
pub has_rpath: bool,
- /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
- /// to the functions that compiler-rt provides.
+ /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
+ /// will emit references to the functions that compiler-rt provides.
pub no_compiler_rt: bool,
- /// Dynamically linked executables can be compiled as position independent if the default
- /// relocation model of position independent code is not changed. This is a requirement to take
- /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
- /// be used during an exploit of a vulnerability in any code.
+ /// Dynamically linked executables can be compiled as position independent
+ /// if the default relocation model of position independent code is not
+ /// changed. This is a requirement to take advantage of ASLR, as otherwise
+ /// the functions in the executable are not randomized and can be used
+ /// during an exploit of a vulnerability in any code.
pub position_independent_executables: bool,
}
impl Default for TargetOptions {
- /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
- /// compilation, will certainly not work.
+ /// Create a set of "sane defaults" for any target. This is still
+ /// incomplete, and if used for compilation, will certainly not work.
fn default() -> TargetOptions {
TargetOptions {
linker: "cc".to_string(),
+ ar: "ar".to_string(),
pre_link_args: Vec::new(),
post_link_args: Vec::new(),
cpu: "generic".to_string(),
pub fn opts() -> TargetOptions {
TargetOptions {
function_sections: true,
- linker: "link".to_string(),
+ linker: "link.exe".to_string(),
+ // When taking a look at the value of this `ar` field, one might expect
+ // `lib.exe` to be the value here! The `lib.exe` program is the default
+ // tool for managing `.lib` archives on Windows, but unfortunately the
+ // compiler cannot use it.
+ //
+ // To recap, we use `ar` here to manage rlibs (which are just archives).
+ // LLVM does not expose bindings for modifying archives so we have to
+ // invoke this utility for write operations (e.g. deleting files, adding
+ // files, etc). Normally archives only have object files within them,
+ // but the compiler also uses archives for storing metadata and
+ // compressed bytecode, so we don't exactly fall within "normal use
+ // cases".
+ //
+ // MSVC's `lib.exe` tool by default will choke when adding a non-object
+ // file to an archive, which we do on a regular basis, making it
+ // inoperable for us. Luckily, however, LLVM has already rewritten `ar`
+ // in the form of `llvm-ar` which is built by default when we build
+ // LLVM. This tool, unlike `lib.exe`, works just fine with non-object
+ // files, so we use it instead.
+ //
+ // Note that there's a few caveats associated with this:
+ //
+ // * This still requires that the *linker* (the consumer of rlibs) will
+ // ignore non-object files. Thankfully `link.exe` on Windows does
+ // indeed ignore non-object files in archives.
+ // * This requires `llvm-ar.exe` to be distributed with the compiler
+ // itself, but we already make sure of this elsewhere.
+ //
+ // Perhaps one day we won't even need this tool at all and we'll just be
+ // able to make library calls into LLVM!
+ ar: "llvm-ar.exe".to_string(),
dynamic_linking: true,
executables: true,
dll_prefix: "".to_string(),
morestack: false,
is_like_windows: true,
is_like_msvc: true,
- pre_link_args: Vec::new(),
+ pre_link_args: vec![
+ "/NOLOGO".to_string(),
+ "/NXCOMPAT".to_string(),
+ ],
.. Default::default()
}
base.cpu = "x86-64".to_string();
Target {
- // FIXME: Test this. Copied from linux (#2398)
+ // This is currently in sync with the specification for
+ // x86_64-pc-windows-gnu but there's a comment in that file questioning
+ // whether this is valid or not. Sounds like the two should stay in sync
+ // at least for now.
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
}
}
+pub fn get_ar_prog(sess: &Session) -> String {
+ sess.opts.cg.ar.clone().unwrap_or_else(|| {
+ sess.target.target.options.ar.clone()
+ })
+}
+
pub fn remove(sess: &Session, path: &Path) {
match fs::remove_file(path) {
Ok(..) => {}
lib_search_paths: archive_search_paths(sess),
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
- maybe_ar_prog: sess.opts.cg.ar.clone()
+ ar_prog: get_ar_prog(sess),
};
let mut ab = ArchiveBuilder::create(config);
ab.add_file(obj_filename).unwrap();
lib_search_paths: archive_search_paths(sess),
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
- maybe_ar_prog: sess.opts.cg.ar.clone()
+ ar_prog: get_ar_prog(sess),
};
let mut archive = Archive::open(config);
archive.remove_file(&format!("{}.o", name));