Rollup merge of #42225 - brson:vs2017, r=alexcrichton

Support VS 2017

Fixes #38584

This replaces all the MSVC linker logic with that from the 'gcc' crate. The code looks the same, but there could be regressions.

I've only tested this with x86_64.

r? @alexcrichton
cc @vadimcn @retep998
This commit is contained in:
Mark Simulacrum 2017-06-02 09:10:42 -06:00 committed by GitHub
commit 551dd7c7a2
14 changed files with 63 additions and 533 deletions

35
src/Cargo.lock generated
View File

@ -44,7 +44,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"core 0.0.0", "core 0.0.0",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0", "libc 0.0.0",
] ]
@ -84,7 +84,7 @@ name = "backtrace-sys"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -110,7 +110,7 @@ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -239,7 +239,7 @@ name = "cmake"
version = "0.1.23" version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -257,7 +257,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"core 0.0.0", "core 0.0.0",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -308,7 +308,7 @@ name = "curl-sys"
version = "0.3.11" version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
@ -411,7 +411,7 @@ name = "flate"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -444,7 +444,7 @@ dependencies = [
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.3.46" version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -605,7 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -630,7 +630,7 @@ name = "libz-sys"
version = "1.0.13" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -650,7 +650,7 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -697,7 +697,7 @@ name = "miniz-sys"
version = "0.1.9" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -830,7 +830,7 @@ name = "openssl-sys"
version = "0.9.12" version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1248,7 +1248,7 @@ name = "rustc_llvm"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_bitflags 0.0.0", "rustc_bitflags 0.0.0",
] ]
@ -1375,6 +1375,7 @@ name = "rustc_trans"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"flate 0.0.0", "flate 0.0.0",
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0", "rustc 0.0.0",
@ -1425,7 +1426,7 @@ dependencies = [
"arena 0.0.0", "arena 0.0.0",
"build_helper 0.1.0", "build_helper 0.1.0",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0", "rustc 0.0.0",
@ -1577,7 +1578,7 @@ dependencies = [
"collections 0.0.0", "collections 0.0.0",
"compiler_builtins 0.0.0", "compiler_builtins 0.0.0",
"core 0.0.0", "core 0.0.0",
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0", "libc 0.0.0",
"panic_abort 0.0.0", "panic_abort 0.0.0",
"panic_unwind 0.0.0", "panic_unwind 0.0.0",
@ -2042,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" "checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
"checksum gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "181e3cebba1d663bd92eb90e2da787e10597e027eb00de8d742b260a7850948f" "checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9de9df4358c17e448a778d90cd0272e1dab5eae30244502333fa2001c4e24357" "checksum git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9de9df4358c17e448a778d90cd0272e1dab5eae30244502333fa2001c4e24357"

View File

@ -36,5 +36,5 @@ num_cpus = "1.0"
toml = "0.1" toml = "0.1"
getopts = "0.2" getopts = "0.2"
rustc-serialize = "0.3" rustc-serialize = "0.3"
gcc = "0.3.46" gcc = "0.3.50"
libc = "0.2" libc = "0.2"

View File

@ -17,7 +17,7 @@ libc = { path = "../rustc/libc_shim" }
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"
[features] [features]
debug = [] debug = []

View File

@ -16,4 +16,4 @@ core = { path = "../libcore" }
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"

View File

@ -11,4 +11,4 @@ crate-type = ["dylib"]
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"

View File

@ -17,4 +17,4 @@ rustc_bitflags = { path = "../librustc_bitflags" }
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"

View File

@ -25,3 +25,6 @@ rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
serialize = { path = "../libserialize" } serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" } syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" } syntax_pos = { path = "../libsyntax_pos" }
[target."cfg(windows)".dependencies]
gcc = "0.3.50"

View File

@ -12,7 +12,6 @@ use super::archive::{ArchiveBuilder, ArchiveConfig};
use super::linker::Linker; use super::linker::Linker;
use super::rpath::RPathConfig; use super::rpath::RPathConfig;
use super::rpath; use super::rpath;
use super::msvc;
use metadata::METADATA_FILENAME; use metadata::METADATA_FILENAME;
use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType}; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
use rustc::session::filesearch; use rustc::session::filesearch;
@ -142,20 +141,41 @@ pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMet
return r; return r;
} }
// The third parameter is for an extra path to add to PATH for MSVC // The third parameter is for an env vars, used to set up the path for MSVC
// cross linkers for host toolchain DLL dependencies // to find its DLLs
pub fn get_linker(sess: &Session) -> (String, Command, Option<PathBuf>) { pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) {
if let Some(ref linker) = sess.opts.cg.linker { if let Some(ref linker) = sess.opts.cg.linker {
(linker.clone(), Command::new(linker), None) (linker.clone(), Command::new(linker), vec![])
} else if sess.target.target.options.is_like_msvc { } else if sess.target.target.options.is_like_msvc {
let (cmd, host) = msvc::link_exe_cmd(sess); let (cmd, envs) = msvc_link_exe_cmd(sess);
("link.exe".to_string(), cmd, host) ("link.exe".to_string(), cmd, envs)
} else { } else {
(sess.target.target.options.linker.clone(), (sess.target.target.options.linker.clone(),
Command::new(&sess.target.target.options.linker), None) Command::new(&sess.target.target.options.linker), vec![])
} }
} }
#[cfg(windows)]
pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
use gcc::windows_registry;
let target = &sess.opts.target_triple;
let tool = windows_registry::find_tool(target, "link.exe");
if let Some(tool) = tool {
let envs = tool.env().to_vec();
(tool.to_command(), envs)
} else {
debug!("Failed to locate linker.");
(Command::new("link.exe"), vec![])
}
}
#[cfg(not(windows))]
pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
(Command::new("link.exe"), vec![])
}
pub fn get_ar_prog(sess: &Session) -> String { pub fn get_ar_prog(sess: &Session) -> String {
sess.opts.cg.ar.clone().unwrap_or_else(|| { sess.opts.cg.ar.clone().unwrap_or_else(|| {
sess.target.target.options.ar.clone() sess.target.target.options.ar.clone()
@ -706,8 +726,9 @@ fn link_natively(sess: &Session,
let flavor = sess.linker_flavor(); let flavor = sess.linker_flavor();
// The invocations of cc share some flags across platforms // The invocations of cc share some flags across platforms
let (pname, mut cmd, extra) = get_linker(sess); let (pname, mut cmd, envs) = get_linker(sess);
cmd.env("PATH", command_path(sess, extra)); // This will set PATH on MSVC
cmd.envs(envs);
let root = sess.target_filesearch(PathKind::Native).get_lib_path(); let root = sess.target_filesearch(PathKind::Native).get_lib_path();
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {

View File

@ -1,56 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_camel_case_types, non_snake_case)]
use libc::c_void;
use std::mem;
type DWORD = u32;
type WORD = u16;
type LPVOID = *mut c_void;
type DWORD_PTR = usize;
const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0;
const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9;
#[repr(C)]
struct SYSTEM_INFO {
wProcessorArchitecture: WORD,
_wReserved: WORD,
_dwPageSize: DWORD,
_lpMinimumApplicationAddress: LPVOID,
_lpMaximumApplicationAddress: LPVOID,
_dwActiveProcessorMask: DWORD_PTR,
_dwNumberOfProcessors: DWORD,
_dwProcessorType: DWORD,
_dwAllocationGranularity: DWORD,
_wProcessorLevel: WORD,
_wProcessorRevision: WORD,
}
extern "system" {
fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
}
pub enum Arch {
X86,
Amd64,
}
pub fn host_arch() -> Option<Arch> {
let mut info = unsafe { mem::zeroed() };
unsafe { GetNativeSystemInfo(&mut info) };
match info.wProcessorArchitecture {
PROCESSOR_ARCHITECTURE_INTEL => Some(Arch::X86),
PROCESSOR_ARCHITECTURE_AMD64 => Some(Arch::Amd64),
_ => None,
}
}

View File

@ -1,305 +0,0 @@
// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! MSVC-specific logic for linkers and such.
//!
//! This module contains a cross-platform interface but has a blank unix
//! implementation. The Windows implementation builds on top of Windows native
//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
//!
//! Note that we don't have much special logic for finding the system linker on
//! any other platforms, so it may seem a little odd to single out MSVC to have
//! a good deal of code just to find the linker. Unlike Unix systems, however,
//! the MSVC linker is not in the system PATH by default. It also additionally
//! needs a few environment variables or command line flags to be able to link
//! against system libraries.
//!
//! In order to have a nice smooth experience on Windows, the logic in this file
//! is here to find the MSVC linker and set it up in the default configuration
//! one would need to set up anyway. This means that the Rust compiler can be
//! run not only in the developer shells of MSVC but also the standard cmd.exe
//! shell or MSYS shells.
//!
//! As a high-level note, all logic in this module for looking up various
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
//! comments can also be found below leading through the various code paths.
// A simple macro to make this option mess easier to read
#[cfg(windows)]
macro_rules! otry {
($expr:expr) => (match $expr {
Some(val) => val,
None => return None,
})
}
#[cfg(windows)]
mod registry;
#[cfg(windows)]
mod arch;
#[cfg(windows)]
mod platform {
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use rustc::session::Session;
use super::arch::{host_arch, Arch};
use super::registry::LOCAL_MACHINE;
// First we need to figure out whether the environment is already correctly
// configured by vcvars. We do this by looking at the environment variable
// `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
// otherwise. If it is defined, then we find `link.exe` in `PATH and trust
// that everything else is configured correctly.
//
// If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where
// it claimed it should be), then we resort to finding everything
// ourselves. First we find where the latest version of MSVC is installed
// and what version it is. Then based on the version we find the
// appropriate SDKs.
//
// If despite our best efforts we are still unable to find MSVC then we
// just blindly call `link.exe` and hope for the best.
//
// This code only supports VC 11 through 15. For versions older than that
// the user will need to manually execute the appropriate vcvars bat file
// and it should hopefully work.
//
// The second member of the tuple we return is the directory for the host
// linker toolchain, which is necessary when using the cross linkers.
pub fn link_exe_cmd(sess: &Session) -> (Command, Option<PathBuf>) {
let arch = &sess.target.target.arch;
env::var_os("VCINSTALLDIR").and_then(|_| {
debug!("Detected that vcvars was already run.");
let path = otry!(env::var_os("PATH"));
// Mingw has its own link which is not the link we want so we
// look for `cl.exe` too as a precaution.
env::split_paths(&path).find(|path| {
path.join("cl.exe").is_file()
&& path.join("link.exe").is_file()
}).map(|path| {
(Command::new(path.join("link.exe")), None)
})
}).or_else(|| {
None.or_else(|| {
find_msvc_latest(arch, "15.0")
}).or_else(|| {
find_msvc_latest(arch, "14.0")
}).or_else(|| {
find_msvc_12(arch)
}).or_else(|| {
find_msvc_11(arch)
}).map(|(cmd, path)| (cmd, Some(path)))
}).unwrap_or_else(|| {
debug!("Failed to locate linker.");
(Command::new("link.exe"), None)
})
}
// For MSVC 14 or newer we need to find the Universal CRT as well as either
// the Windows 10 SDK or Windows 8.1 SDK.
fn find_msvc_latest(arch: &str, ver: &str) -> Option<(Command, PathBuf)> {
let vcdir = otry!(get_vc_dir(ver));
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
let sub = otry!(lib_subdir(arch));
let ucrt = otry!(get_ucrt_dir());
debug!("Found Universal CRT {:?}", ucrt);
add_lib(&mut cmd, &ucrt.join("ucrt").join(sub));
if let Some(dir) = get_sdk10_dir() {
debug!("Found Win10 SDK {:?}", dir);
add_lib(&mut cmd, &dir.join("um").join(sub));
} else if let Some(dir) = get_sdk81_dir() {
debug!("Found Win8.1 SDK {:?}", dir);
add_lib(&mut cmd, &dir.join("um").join(sub));
} else {
return None
}
Some((cmd, host))
}
// For MSVC 12 we need to find the Windows 8.1 SDK.
fn find_msvc_12(arch: &str) -> Option<(Command, PathBuf)> {
let vcdir = otry!(get_vc_dir("12.0"));
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
let sub = otry!(lib_subdir(arch));
let sdk81 = otry!(get_sdk81_dir());
debug!("Found Win8.1 SDK {:?}", sdk81);
add_lib(&mut cmd, &sdk81.join("um").join(sub));
Some((cmd, host))
}
// For MSVC 11 we need to find the Windows 8 SDK.
fn find_msvc_11(arch: &str) -> Option<(Command, PathBuf)> {
let vcdir = otry!(get_vc_dir("11.0"));
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
let sub = otry!(lib_subdir(arch));
let sdk8 = otry!(get_sdk8_dir());
debug!("Found Win8 SDK {:?}", sdk8);
add_lib(&mut cmd, &sdk8.join("um").join(sub));
Some((cmd, host))
}
// A convenience function to append library paths.
fn add_lib(cmd: &mut Command, lib: &Path) {
let mut arg: OsString = "/LIBPATH:".into();
arg.push(lib);
cmd.arg(arg);
}
// Given a possible MSVC installation directory, we look for the linker and
// then add the MSVC library path.
fn get_linker(path: &Path, arch: &str) -> Option<(Command, PathBuf)> {
debug!("Looking for linker in {:?}", path);
bin_subdir(arch).into_iter().map(|(sub, host)| {
(path.join("bin").join(sub).join("link.exe"),
path.join("bin").join(host))
}).filter(|&(ref path, _)| {
path.is_file()
}).map(|(path, host)| {
(Command::new(path), host)
}).filter_map(|(mut cmd, host)| {
let sub = otry!(vc_lib_subdir(arch));
add_lib(&mut cmd, &path.join("lib").join(sub));
Some((cmd, host))
}).next()
}
// To find MSVC we look in a specific registry key for the version we are
// trying to find.
fn get_vc_dir(ver: &str) -> Option<PathBuf> {
let key = otry!(LOCAL_MACHINE
.open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref()).ok());
let path = otry!(key.query_str(ver).ok());
Some(path.into())
}
// To find the Universal CRT we look in a specific registry key for where
// all the Universal CRTs are located and then sort them asciibetically to
// find the newest version. While this sort of sorting isn't ideal, it is
// what vcvars does so that's good enough for us.
fn get_ucrt_dir() -> Option<PathBuf> {
let key = otry!(LOCAL_MACHINE
.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref()).ok());
let root = otry!(key.query_str("KitsRoot10").ok());
let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
readdir.filter_map(|dir| {
dir.ok()
}).map(|dir| {
dir.path()
}).filter(|dir| {
dir.components().last().and_then(|c| {
c.as_os_str().to_str()
}).map(|c| {
c.starts_with("10.") && dir.join("ucrt").is_dir()
}).unwrap_or(false)
}).max()
}
// Vcvars finds the correct version of the Windows 10 SDK by looking
// for the include `um\Windows.h` because sometimes a given version will
// only have UCRT bits without the rest of the SDK. Since we only care about
// libraries and not includes, we instead look for `um\x64\kernel32.lib`.
// Since the 32-bit and 64-bit libraries are always installed together we
// only need to bother checking x64, making this code a tiny bit simpler.
// Like we do for the Universal CRT, we sort the possibilities
// asciibetically to find the newest one as that is what vcvars does.
fn get_sdk10_dir() -> Option<PathBuf> {
let key = otry!(LOCAL_MACHINE
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref()).ok());
let root = otry!(key.query_str("InstallationFolder").ok());
let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
.map(|dir| dir.path()).collect();
dirs.sort();
dirs.into_iter().rev().filter(|dir| {
dir.join("um").join("x64").join("kernel32.lib").is_file()
}).next()
}
// Interestingly there are several subdirectories, `win7` `win8` and
// `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
// applies to us. Note that if we were targetting kernel mode drivers
// instead of user mode applications, we would care.
fn get_sdk81_dir() -> Option<PathBuf> {
let key = otry!(LOCAL_MACHINE
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref()).ok());
let root = otry!(key.query_str("InstallationFolder").ok());
Some(Path::new(&root).join("lib").join("winv6.3"))
}
fn get_sdk8_dir() -> Option<PathBuf> {
let key = otry!(LOCAL_MACHINE
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref()).ok());
let root = otry!(key.query_str("InstallationFolder").ok());
Some(Path::new(&root).join("lib").join("win8"))
}
// When choosing the linker toolchain to use, we have to choose the one
// which matches the host architecture. Otherwise we end up in situations
// where someone on 32-bit Windows is trying to cross compile to 64-bit and
// it tries to invoke the native 64-bit linker which won't work.
//
// For the return value of this function, the first member of the tuple is
// the folder of the linker we will be invoking, while the second member
// is the folder of the host toolchain for that linker which is essential
// when using a cross linker. We return a Vec since on x64 there are often
// two linkers that can target the architecture we desire. The 64-bit host
// linker is preferred, and hence first, due to 64-bit allowing it more
// address space to work with and potentially being faster.
//
// FIXME - Figure out what happens when the host architecture is arm.
fn bin_subdir(arch: &str) -> Vec<(&'static str, &'static str)> {
match (arch, host_arch()) {
("x86", Some(Arch::X86)) => vec![("", "")],
("x86", Some(Arch::Amd64)) => vec![("amd64_x86", "amd64"), ("", "")],
("x86_64", Some(Arch::X86)) => vec![("x86_amd64", "")],
("x86_64", Some(Arch::Amd64)) => vec![("amd64", "amd64"), ("x86_amd64", "")],
("arm", Some(Arch::X86)) => vec![("x86_arm", "")],
("arm", Some(Arch::Amd64)) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
_ => vec![],
}
}
fn lib_subdir(arch: &str) -> Option<&'static str> {
match arch {
"x86" => Some("x86"),
"x86_64" => Some("x64"),
"arm" => Some("arm"),
_ => None,
}
}
// MSVC's x86 libraries are not in a subfolder
fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
match arch {
"x86" => Some(""),
"x86_64" => Some("amd64"),
"arm" => Some("arm"),
_ => None,
}
}
}
// If we're not on Windows, then there's no registry to search through and MSVC
// wouldn't be able to run, so we just call `link.exe` and hope for the best.
#[cfg(not(windows))]
mod platform {
use std::path::PathBuf;
use std::process::Command;
use rustc::session::Session;
pub fn link_exe_cmd(_sess: &Session) -> (Command, Option<PathBuf>) {
(Command::new("link.exe"), None)
}
}
pub use self::platform::*;

View File

@ -1,136 +0,0 @@
// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::io;
use std::ffi::{OsString, OsStr};
use std::os::windows::prelude::*;
use std::ptr;
use libc::c_long;
pub type DWORD = u32;
type LPCWSTR = *const u16;
type LONG = c_long;
type LPDWORD = *mut DWORD;
type LPBYTE = *mut u8;
const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
const KEY_WOW64_32KEY: REGSAM = 0x0200;
const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE |
KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE;
const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL;
const READ_CONTROL: REGSAM = 0x00020000;
const KEY_QUERY_VALUE: REGSAM = 0x0001;
const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008;
const KEY_NOTIFY: REGSAM = 0x0010;
const SYNCHRONIZE: REGSAM = 0x00100000;
const REG_SZ: DWORD = 1;
const ERROR_SUCCESS: i32 = 0;
pub enum __HKEY__ {}
pub type HKEY = *mut __HKEY__;
pub type PHKEY = *mut HKEY;
pub type REGSAM = DWORD;
#[link(name = "advapi32")]
extern "system" {
fn RegOpenKeyExW(hKey: HKEY,
lpSubKey: LPCWSTR,
ulOptions: DWORD,
samDesired: REGSAM,
phkResult: PHKEY) -> LONG;
fn RegQueryValueExW(hKey: HKEY,
lpValueName: LPCWSTR,
lpReserved: LPDWORD,
lpType: LPDWORD,
lpData: LPBYTE,
lpcbData: LPDWORD) -> LONG;
fn RegCloseKey(hKey: HKEY) -> LONG;
}
pub struct RegistryKey(Repr);
struct OwnedKey(HKEY);
enum Repr {
Const(HKEY),
Owned(OwnedKey),
}
unsafe impl Sync for RegistryKey {}
unsafe impl Send for RegistryKey {}
pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
impl RegistryKey {
fn raw(&self) -> HKEY {
match self.0 {
Repr::Const(val) => val,
Repr::Owned(ref val) => val.0,
}
}
pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut ret = ptr::null_mut();
let err = unsafe {
RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
KEY_READ | KEY_WOW64_32KEY, &mut ret)
};
if err == ERROR_SUCCESS {
Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
} else {
Err(io::Error::from_raw_os_error(err as i32))
}
}
pub fn query_str(&self, name: &str) -> io::Result<OsString> {
let name: &OsStr = name.as_ref();
let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut len = 0;
let mut kind = 0;
unsafe {
let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
&mut kind, ptr::null_mut(), &mut len);
if err != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(err as i32))
}
if kind != REG_SZ {
return Err(io::Error::new(io::ErrorKind::Other,
"registry key wasn't a string"))
}
// The length here is the length in bytes, but we're using wide
// characters so we need to be sure to halve it for the capacity
// passed in.
let mut v = Vec::with_capacity(len as usize / 2);
let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
ptr::null_mut(), v.as_mut_ptr() as *mut _,
&mut len);
if err != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(err as i32))
}
v.set_len(len as usize / 2);
// Some registry keys may have a terminating nul character, but
// we're not interested in that, so chop it off if it's there.
if v[v.len() - 1] == 0 {
v.pop();
}
Ok(OsString::from_wide(&v))
}
}
}
impl Drop for OwnedKey {
fn drop(&mut self) {
unsafe { RegCloseKey(self.0); }
}
}

View File

@ -35,6 +35,7 @@
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(unicode)] #![feature(unicode)]
#![feature(conservative_impl_trait)] #![feature(conservative_impl_trait)]
#![feature(command_envs)]
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))] #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(rustc_private))] #![cfg_attr(stage0, feature(rustc_private))]
@ -62,6 +63,8 @@ extern crate rustc_bitflags;
extern crate syntax_pos; extern crate syntax_pos;
extern crate rustc_errors as errors; extern crate rustc_errors as errors;
extern crate serialize; extern crate serialize;
#[cfg(windows)]
extern crate gcc; // Used to locate MSVC, not gcc :)
pub use base::trans_crate; pub use base::trans_crate;
pub use back::symbol_names::provide; pub use back::symbol_names::provide;
@ -77,8 +80,7 @@ pub mod back {
pub(crate) mod symbol_export; pub(crate) mod symbol_export;
pub(crate) mod symbol_names; pub(crate) mod symbol_names;
pub mod write; pub mod write;
mod msvc; pub mod rpath;
mod rpath;
} }
mod diagnostics; mod diagnostics;

View File

@ -30,4 +30,4 @@ pulldown-cmark = { version = "0.0.14", default-features = false }
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"

View File

@ -35,7 +35,7 @@ rustc_tsan = { path = "../librustc_tsan" }
[build-dependencies] [build-dependencies]
build_helper = { path = "../build_helper" } build_helper = { path = "../build_helper" }
gcc = "0.3.27" gcc = "0.3.50"
[features] [features]
backtrace = [] backtrace = []