diff --git a/mk/cfg/x86_64-pc-windows-msvc.mk b/mk/cfg/x86_64-pc-windows-msvc.mk index 3235dcece6d..4a77b658d46 100644 --- a/mk/cfg/x86_64-pc-windows-msvc.mk +++ b/mk/cfg/x86_64-pc-windows-msvc.mk @@ -1,29 +1,24 @@ # x86_64-pc-windows-msvc configuration -CROSS_PREFIX_x86_64-pc-windows-msvc= CC_x86_64-pc-windows-msvc=cl LINK_x86_64-pc-windows-msvc=link -CXX_x86_64-pc-windows-msvc=g++ -CPP_x86_64-pc-windows-msvc=gcc -E +CXX_x86_64-pc-windows-msvc=cl +CPP_x86_64-pc-windows-msvc=cl AR_x86_64-pc-windows-msvc=llvm-ar CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.dll CFG_LIB_DSYM_GLOB_x86_64-pc-windows-msvc=$(1)-*.dylib.dSYM -CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-msvc := $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-pc-windows-msvc := $(CFLAGS) -CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-msvc := -fno-rtti $(CXXFLAGS) -CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-msvc := -shared -g -m64 +CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-msvc := +CFG_GCCISH_CFLAGS_x86_64-pc-windows-msvc := +CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-msvc := +CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-msvc := CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-msvc := -CFG_GCCISH_PRE_LIB_FLAGS_x86_64-pc-windows-msvc := -CFG_GCCISH_POST_LIB_FLAGS_x86_64-pc-windows-msvc := -CFG_DEF_SUFFIX_x86_64-pc-windows-msvc := .windows.def CFG_LLC_FLAGS_x86_64-pc-windows-msvc := CFG_INSTALL_NAME_x86_64-pc-windows-msvc = CFG_EXE_SUFFIX_x86_64-pc-windows-msvc := .exe CFG_WINDOWSY_x86_64-pc-windows-msvc := 1 CFG_UNIXY_x86_64-pc-windows-msvc := -CFG_PATH_MUNGE_x86_64-pc-windows-msvc := CFG_LDPATH_x86_64-pc-windows-msvc := CFG_RUN_x86_64-pc-windows-msvc=$(2) CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2)) -CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-w64-mingw32 +CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-windows-msvc diff --git a/mk/platform.mk b/mk/platform.mk index 01865319b3f..f66e451f236 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -145,15 +145,15 @@ FIND_COMPILER = $(word 1,$(1:ccache=)) define CFG_MAKE_TOOLCHAIN # Prepend the tools with their prefix if cross compiling ifneq ($(CFG_BUILD),$(1)) - CC_$(1)=$(CROSS_PREFIX_$(1))$(CC_$(1)) - CXX_$(1)=$(CROSS_PREFIX_$(1))$(CXX_$(1)) - CPP_$(1)=$(CROSS_PREFIX_$(1))$(CPP_$(1)) - AR_$(1)=$(CROSS_PREFIX_$(1))$(AR_$(1)) - LINK_$(1)=$(CROSS_PREFIX_$(1))$(LINK_$(1)) - RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(LINK_$(1))) \ - -C ar=$$(call FIND_COMPILER,$$(AR_$(1))) $(RUSTC_CROSS_FLAGS_$(1)) + CC_$(1)=$(CROSS_PREFIX_$(1))$(CC_$(1)) + CXX_$(1)=$(CROSS_PREFIX_$(1))$(CXX_$(1)) + CPP_$(1)=$(CROSS_PREFIX_$(1))$(CPP_$(1)) + AR_$(1)=$(CROSS_PREFIX_$(1))$(AR_$(1)) + LINK_$(1)=$(CROSS_PREFIX_$(1))$(LINK_$(1)) + RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(LINK_$(1))) \ + -C ar=$$(call FIND_COMPILER,$$(AR_$(1))) $(RUSTC_CROSS_FLAGS_$(1)) - RUSTC_FLAGS_$(1)=$$(RUSTC_CROSS_FLAGS_$(1)) $(RUSTC_FLAGS_$(1)) + RUSTC_FLAGS_$(1)=$$(RUSTC_CROSS_FLAGS_$(1)) $(RUSTC_FLAGS_$(1)) endif CFG_COMPILE_C_$(1) = $$(CC_$(1)) \ diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4154ee29388..b999929c4af 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -632,7 +632,6 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let mut ret = vec![ // Target bindings. attr::mk_word_item(fam.clone()), mk(InternedString::new("target_os"), intern(os)), - mk(InternedString::new("target_abi"), intern(abi)), mk(InternedString::new("target_family"), fam), mk(InternedString::new("target_arch"), intern(arch)), mk(InternedString::new("target_endian"), intern(end)), diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 796aa3b08ca..18e67d066d0 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -22,7 +22,6 @@ pub fn target() -> Target { target_env: "gnu".to_string(), arch: "aarch64".to_string(), target_os: "linux".to_string(), - target_abi: "".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index 425077e9738..21094ad905e 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -22,11 +22,7 @@ pub fn target() -> Target { target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "linux".to_string(), -<<<<<<< HEAD target_env: "gnu".to_string(), -======= - target_abi: "".to_string(), ->>>>>>> 9f1453c... Very hacky MSVC hacks. options: base, } } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index de8086bec4f..a3cb357dc05 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -59,6 +59,7 @@ mod freebsd_base; mod linux_base; mod openbsd_base; mod windows_base; +mod windows_msvc_base; /// Everything `rustc` knows about how to compile for a specific target. /// diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index f53f0df0e63..f4f25ea8569 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -13,8 +13,7 @@ use std::default::Default; pub fn opts() -> TargetOptions { TargetOptions { - // FIXME(#13846) this should be enabled for windows - function_sections: false, + function_sections: true, linker: "link".to_string(), dynamic_linking: true, executables: true, diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index 1cbf7aabeef..aac1afbb97c 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "windows".to_string(), - target_abi: "msvc".to_string(), + target_env: "msvc".to_string(), options: base, } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 74d7dc95b24..2a2aa2bf4cf 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -55,7 +55,6 @@ pub use self::CallConv::*; pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -pub use self::DLLStorageClass::*; use std::ffi::CString; use std::cell::RefCell; @@ -115,13 +114,6 @@ pub enum Linkage { CommonLinkage = 14, } -#[derive(Copy)] -pub enum DLLStorageClass { - DefaultStorageClass = 0, - DLLImportStorageClass = 1, - DLLExportStorageClass = 2, -} - #[repr(C)] #[derive(Copy, Clone, Debug)] pub enum DiagnosticSeverity { @@ -2133,12 +2125,6 @@ pub fn SetLinkage(global: ValueRef, link: Linkage) { } } -pub fn SetDLLStorageClass(global: ValueRef, storage_class: DLLStorageClass) { - unsafe { - LLVMRustSetDLLStorageClass(global, storage_class as c_uint); - } -} - pub fn SetUnnamedAddr(global: ValueRef, unnamed: bool) { unsafe { LLVMSetUnnamedAddr(global, unnamed as Bool); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index aa51afac1a4..38ad909dd01 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -8,21 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::archive::{ArchiveBuilder, ArchiveConfig, METADATA_FILENAME}; +use super::archive::{Archive, ArchiveBuilder, ArchiveConfig, METADATA_FILENAME}; +use super::archive; +use super::rpath; +use super::rpath::RPathConfig; use super::svh::Svh; - -use super::link_gnu; -use super::link_msvc; - use session::config; +use session::config::NoDebugInfo; use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; use session::search_paths::PathKind; use session::Session; use metadata::common::LinkMeta; -use metadata::{encoder, cstore, csearch, creader}; +use metadata::{encoder, cstore, filesearch, csearch, creader}; use metadata::filesearch::FileDoesntMatch; use trans::{CrateContext, CrateTranslation, gensym_name}; use middle::ty::{self, Ty}; +use util::common::time; use util::ppaux; use util::sha2::{Digest, Sha256}; use util::fs::fix_windows_verbatim_for_gcc; diff --git a/src/librustc_trans/back/link_gnu.rs b/src/librustc_trans/back/link_gnu.rs deleted file mode 100644 index b1582a1a3c5..00000000000 --- a/src/librustc_trans/back/link_gnu.rs +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::archive::{Archive, ArchiveConfig}; -use super::archive; -use super::rpath; -use super::rpath::RPathConfig; - -use session::config; -use session::config::NoDebugInfo; -use session::search_paths::PathKind; -use session::Session; -use metadata::{cstore, filesearch, csearch}; -use metadata::filesearch::FileDoesntMatch; -use trans::{CrateTranslation}; -use util::common::time; - -use std::str; -use std::old_io::{fs, TempDir, Command}; -use std::old_io; - -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. -pub fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, - obj_filename: &Path, out_filename: &Path) { - let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); - - // The invocations of cc share some flags across platforms - let pname = super::link::get_cc_prog(sess); - let mut cmd = Command::new(&pname[..]); - - cmd.args(&sess.target.target.options.pre_link_args[]); - link_args(&mut cmd, sess, dylib, tmpdir.path(), - trans, obj_filename, out_filename); - cmd.args(&sess.target.target.options.post_link_args[]); - if !sess.target.target.options.no_compiler_rt { - cmd.arg("-lcompiler-rt"); - } - - if sess.opts.debugging_opts.print_link_args { - println!("{:?}", &cmd); - } - - // May have not found libraries in the right formats. - sess.abort_if_errors(); - - // Invoke the system linker - debug!("{:?}", &cmd); - let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output()); - match prog { - Ok(prog) => { - if !prog.status.success() { - sess.err(&format!("linking with `{}` failed: {}", - pname, - prog.status)[]); - sess.note(&format!("{:?}", &cmd)[]); - let mut output = prog.error.clone(); - output.push_all(&prog.output[]); - sess.note(str::from_utf8(&output[..]).unwrap()); - sess.abort_if_errors(); - } - debug!("linker stderr:\n{}", String::from_utf8(prog.error).unwrap()); - debug!("linker stdout:\n{}", String::from_utf8(prog.output).unwrap()); - }, - Err(e) => { - sess.err(&format!("could not exec the linker `{}`: {}", - pname, - e)[]); - sess.abort_if_errors(); - } - } - - - // On OSX, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { - match Command::new("dsymutil").arg(out_filename).output() { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to run dsymutil: {}", e)[]); - sess.abort_if_errors(); - } - } - } -} - -fn link_args(cmd: &mut Command, - sess: &Session, - dylib: bool, - tmpdir: &Path, - trans: &CrateTranslation, - obj_filename: &Path, - out_filename: &Path) { - - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); - - // target descriptor - let t = &sess.target.target; - - cmd.arg("-L").arg(&lib_path); - - cmd.arg("-o").arg(out_filename).arg(obj_filename); - - - // Stack growth requires statically linking a __morestack function. Note - // that this is listed *before* all other libraries. Due to the usage of the - // --as-needed flag below, the standard library may only be useful for its - // rust_stack_exhausted function. In this case, we must ensure that the - // libmorestack.a file appears *before* the standard library (so we put it - // at the very front). - // - // Most of the time this is sufficient, except for when LLVM gets super - // clever. If, for example, we have a main function `fn main() {}`, LLVM - // will optimize out calls to `__morestack` entirely because the function - // doesn't need any stack at all! - // - // To get around this snag, we specially tell the linker to always include - // all contents of this library. This way we're guaranteed that the linker - // will include the __morestack symbol 100% of the time, always resolving - // references to it even if the object above didn't use it. - if t.options.morestack { - if t.options.is_like_osx { - let morestack = lib_path.join("libmorestack.a"); - - let mut v = b"-Wl,-force_load,".to_vec(); - v.push_all(morestack.as_vec()); - cmd.arg(&v[..]); - } else { - cmd.args(&["-Wl,--whole-archive", "-lmorestack", "-Wl,--no-whole-archive"]); - } - } - - // When linking a dynamic library, we put the metadata into a section of the - // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if dylib { - cmd.arg(obj_filename.with_extension("metadata.o")); - } - - if t.options.is_like_osx { - // The dead_strip option to the linker specifies that functions and data - // unreachable by the entry point will be removed. This is quite useful - // with Rust's compilation model of compiling libraries at a time into - // one object file. For example, this brings hello world from 1.7MB to - // 458K. - // - // Note that this is done for both executables and dynamic libraries. We - // won't get much benefit from dylibs because LLVM will have already - // stripped away as much as it could. This has not been seen to impact - // link times negatively. - // - // -dead_strip can't be part of the pre_link_args because it's also used for partial - // linking when using multiple codegen units (-r). So we insert it here. - cmd.arg("-Wl,-dead_strip"); - } - - // If we're building a dylib, we don't use --gc-sections because LLVM has - // already done the best it can do, and we also don't want to eliminate the - // metadata. If we're building an executable, however, --gc-sections drops - // the size of hello world from 1.8MB to 597K, a 67% reduction. - if !dylib && !t.options.is_like_osx { - cmd.arg("-Wl,--gc-sections"); - } - - let used_link_args = sess.cstore.get_used_link_args().borrow(); - - if t.options.position_independent_executables { - let empty_vec = Vec::new(); - let empty_str = String::new(); - let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); - let mut args = args.iter().chain(used_link_args.iter()); - if !dylib - && (t.options.relocation_model == "pic" - || *sess.opts.cg.relocation_model.as_ref() - .unwrap_or(&empty_str) == "pic") - && !args.any(|x| *x == "-static") { - cmd.arg("-pie"); - } - } - - if t.options.linker_is_gnu { - // GNU-style linkers support optimization with -O. GNU ld doesn't need a - // numeric argument, but other linkers do. - if sess.opts.optimize == config::Default || - sess.opts.optimize == config::Aggressive { - cmd.arg("-Wl,-O1"); - } - } - - // We want to prevent the compiler from accidentally leaking in any system - // libraries, so we explicitly ask gcc to not link to any libraries by - // default. Note that this does not happen for windows because windows pulls - // in some large number of libraries and I couldn't quite figure out which - // subset we wanted. - if !t.options.is_like_windows { - cmd.arg("-nodefaultlibs"); - } - - // Mark all dynamic libraries and executables as compatible with ASLR - // FIXME #17098: ASLR breaks gdb - if t.options.is_like_windows && sess.opts.debuginfo == NoDebugInfo { - // cmd.arg("-Wl,--dynamicbase"); - } - - // Take careful note of the ordering of the arguments we pass to the linker - // here. Linkers will assume that things on the left depend on things to the - // right. Things on the right cannot depend on things on the left. This is - // all formally implemented in terms of resolving symbols (libs on the right - // resolve unknown symbols of libs on the left, but not vice versa). - // - // For this reason, we have organized the arguments we pass to the linker as - // such: - // - // 1. The local object that LLVM just generated - // 2. Upstream rust libraries - // 3. Local native libraries - // 4. Upstream native libraries - // - // This is generally fairly natural, but some may expect 2 and 3 to be - // swapped. The reason that all native libraries are put last is that it's - // not recommended for a native library to depend on a symbol from a rust - // crate. If this is the case then a staticlib crate is recommended, solving - // the problem. - // - // Additionally, it is occasionally the case that upstream rust libraries - // depend on a local native library. In the case of libraries such as - // lua/glfw/etc the name of the library isn't the same across all platforms, - // so only the consumer crate of a library knows the actual name. This means - // that downstream crates will provide the #[link] attribute which upstream - // crates will depend on. Hence local native libraries are after out - // upstream rust crates. - // - // In theory this means that a symbol in an upstream native library will be - // shadowed by a local native library when it wouldn't have been before, but - // this kind of behavior is pretty platform specific and generally not - // recommended anyway, so I don't think we're shooting ourself in the foot - // much with that. - add_upstream_rust_crates(cmd, sess, dylib, tmpdir, trans); - add_local_native_libraries(cmd, sess); - add_upstream_native_libraries(cmd, sess); - - // # Telling the linker what we're doing - - if dylib { - // On mac we need to tell the linker to let this library be rpathed - if sess.target.target.options.is_like_osx { - cmd.args(&["-dynamiclib", "-Wl,-dylib"]); - - if sess.opts.cg.rpath { - let mut v = "-Wl,-install_name,@rpath/".as_bytes().to_vec(); - v.push_all(out_filename.filename().unwrap()); - cmd.arg(&v[..]); - } - } else { - cmd.arg("-shared"); - } - } - - // FIXME (#2397): At some point we want to rpath our guesses as to - // where extern libraries might live, based on the - // addl_lib_search_paths - if sess.opts.cg.rpath { - let sysroot = sess.sysroot(); - let target_triple = &sess.opts.target_triple[]; - let get_install_prefix_lib_path = || { - let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); - let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); - let mut path = Path::new(install_prefix); - path.push(&tlib); - - path - }; - let rpath_config = RPathConfig { - used_crates: sess.cstore.get_used_crates(cstore::RequireDynamic), - out_filename: out_filename.clone(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - get_install_prefix_lib_path: get_install_prefix_lib_path, - realpath: ::util::fs::realpath - }; - cmd.args(&rpath::get_rpath_flags(rpath_config)[]); - } - - // Finally add all the linker arguments provided on the command line along - // with any #[link_args] attributes found inside the crate - let empty = Vec::new(); - cmd.args(&sess.opts.cg.link_args.as_ref().unwrap_or(&empty)[]); - cmd.args(&used_link_args[..]); -} - -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut Command, sess: &Session) { - sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { - match k { - PathKind::Framework => { cmd.arg("-F").arg(path); } - _ => { cmd.arg("-L").arg(path); } - } - FileDoesntMatch - }); - - // Some platforms take hints about whether a library is static or dynamic. - // For those that support this, we ensure we pass the option if the library - // was flagged "static" (most defaults are dynamic) to ensure that if - // libfoo.a and libfoo.so both exist that the right one is chosen. - let takes_hints = !sess.target.target.options.is_like_osx; - - let libs = sess.cstore.get_used_libraries(); - let libs = libs.borrow(); - - let staticlibs = libs.iter().filter_map(|&(ref l, kind)| { - if kind == cstore::NativeStatic {Some(l)} else {None} - }); - let others = libs.iter().filter(|&&(_, kind)| { - kind != cstore::NativeStatic - }); - - // Platforms that take hints generally also support the --whole-archive - // flag. We need to pass this flag when linking static native libraries to - // ensure the entire library is included. - // - // For more details see #15460, but the gist is that the linker will strip - // away any unused objects in the archive if we don't otherwise explicitly - // reference them. This can occur for libraries which are just providing - // bindings, libraries with generic functions, etc. - if takes_hints { - cmd.arg("-Wl,--whole-archive").arg("-Wl,-Bstatic"); - } - let search_path = super::link::archive_search_paths(sess); - for l in staticlibs { - if takes_hints { - cmd.arg(format!("-l{}", l)); - } else { - // -force_load is the OSX equivalent of --whole-archive, but it - // involves passing the full path to the library to link. - let lib = archive::find_library(&l[..], - &sess.target.target.options.staticlib_prefix, - &sess.target.target.options.staticlib_suffix, - &search_path[..], - &sess.diagnostic().handler); - let mut v = b"-Wl,-force_load,".to_vec(); - v.push_all(lib.as_vec()); - cmd.arg(&v[..]); - } - } - if takes_hints { - cmd.arg("-Wl,--no-whole-archive").arg("-Wl,-Bdynamic"); - } - - for &(ref l, kind) in others { - match kind { - cstore::NativeUnknown => { - cmd.arg(format!("-l{}", l)); - } - cstore::NativeFramework => { - cmd.arg("-framework").arg(&l[..]); - } - cstore::NativeStatic => unreachable!(), - } - } -} - -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, - dylib: bool, tmpdir: &Path, - trans: &CrateTranslation) { - // All of the heavy lifting has previously been accomplished by the - // dependency_format module of the compiler. This is just crawling the - // output of that module, adding crates as necessary. - // - // Linking to a rlib involves just passing it to the linker (the linker - // will slurp up the object files inside), and linking to a dynamic library - // involves just passing the right -l flag. - - let data = if dylib { - &trans.crate_formats[config::CrateTypeDylib] - } else { - &trans.crate_formats[config::CrateTypeExecutable] - }; - - // Invoke get_used_crates to ensure that we get a topological sorting of - // crates. - let deps = sess.cstore.get_used_crates(cstore::RequireDynamic); - - for &(cnum, _) in &deps { - // We may not pass all crates through to the linker. Some crates may - // appear statically in an existing dylib, meaning we'll pick up all the - // symbols from the dylib. - let kind = match data[cnum as uint - 1] { - Some(t) => t, - None => continue - }; - let src = sess.cstore.get_used_crate_source(cnum).unwrap(); - match kind { - cstore::RequireDynamic => { - add_dynamic_crate(cmd, sess, src.dylib.unwrap().0) - } - cstore::RequireStatic => { - add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap().0) - } - } - - } - - // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] { - if stem.starts_with("lib".as_bytes()) && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } - } - - // Adds the static "rlib" versions of all crates to the command line. - fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path, - cratepath: Path) { - // When performing LTO on an executable output, all of the - // bytecode from the upstream libraries has already been - // included in our object file output. We need to modify all of - // the upstream archives to remove their corresponding object - // file to make sure we don't pull the same code in twice. - // - // We must continue to link to the upstream archives to be sure - // to pull in native static dependencies. As the final caveat, - // on Linux it is apparently illegal to link to a blank archive, - // so if an archive no longer has any object files in it after - // we remove `lib.o`, then don't link against it at all. - // - // If we're not doing LTO, then our job is simply to just link - // against the archive. - if sess.lto() { - let name = cratepath.filename_str().unwrap(); - let name = &name[3..name.len() - 5]; // chop off lib/.rlib - time(sess.time_passes(), - &format!("altering {}.rlib", name)[], - (), |()| { - let dst = tmpdir.join(cratepath.filename().unwrap()); - match fs::copy(&cratepath, &dst) { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to copy {} to {}: {}", - cratepath.display(), - dst.display(), - e)[]); - sess.abort_if_errors(); - } - } - // Fix up permissions of the copy, as fs::copy() preserves - // permissions, but the original file may have been installed - // by a package manager and may be read-only. - match fs::chmod(&dst, old_io::USER_READ | old_io::USER_WRITE) { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to chmod {} when preparing \ - for LTO: {}", dst.display(), - e)[]); - sess.abort_if_errors(); - } - } - let handler = &sess.diagnostic().handler; - let config = ArchiveConfig { - handler: handler, - dst: dst.clone(), - lib_search_paths: super::link::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() - }; - let mut archive = Archive::open(config); - archive.remove_file(&format!("{}.o", name)[]); - let files = archive.files(); - if files.iter().any(|s| s[].ends_with(".o")) { - cmd.arg(dst); - } - }); - } else { - cmd.arg(cratepath); - } - } - - // Same thing as above, but for dynamic crates instead of static crates. - fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!sess.lto()); - - // Just need to tell the linker about where the library lives and - // what its name is - let dir = cratepath.dirname(); - if !dir.is_empty() { cmd.arg("-L").arg(dir); } - - let mut v = "-l".as_bytes().to_vec(); - v.push_all(unlib(&sess.target, cratepath.filestem().unwrap())); - cmd.arg(&v[..]); - } -} - -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) { - // Be sure to use a topological sorting of crates because there may be - // interdependencies between native libraries. When passing -nodefaultlibs, - // for example, almost all native libraries depend on libc, so we have to - // make sure that's all the way at the right (liblibc is near the base of - // the dependency chain). - // - // This passes RequireStatic, but the actual requirement doesn't matter, - // we're just getting an ordering of crate numbers, we're not worried about - // the paths. - let crates = sess.cstore.get_used_crates(cstore::RequireStatic); - for (cnum, _) in crates { - let libs = csearch::get_native_libraries(&sess.cstore, cnum); - for &(kind, ref lib) in &libs { - match kind { - cstore::NativeUnknown => { - cmd.arg(format!("-l{}", *lib)); - } - cstore::NativeFramework => { - cmd.arg("-framework"); - cmd.arg(&lib[..]); - } - cstore::NativeStatic => { - sess.bug("statics shouldn't be propagated"); - } - } - } - } -} diff --git a/src/librustc_trans/back/link_msvc.rs b/src/librustc_trans/back/link_msvc.rs deleted file mode 100644 index 0237ac1231c..00000000000 --- a/src/librustc_trans/back/link_msvc.rs +++ /dev/null @@ -1,460 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::archive::{Archive, ArchiveConfig}; -use super::archive; -use super::rpath; -use super::rpath::RPathConfig; - -use session::config; -use session::config::NoDebugInfo; -use session::search_paths::PathKind; -use session::Session; -use metadata::{cstore, filesearch, csearch}; -use metadata::filesearch::FileDoesntMatch; -use trans::CrateTranslation; -use util::common::time; - -use std::str; -use std::old_io::{fs, TempDir, Command}; -use std::old_io; - -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. -pub fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, - obj_filename: &Path, out_filename: &Path) { - let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); - - // The invocations of cc share some flags across platforms - let pname = super::link::get_cc_prog(sess); - let mut cmd = Command::new(&pname[..]); - - cmd.args(&sess.target.target.options.pre_link_args[]); - link_args(&mut cmd, sess, dylib, tmpdir.path(), - trans, obj_filename, out_filename); - cmd.args(&sess.target.target.options.post_link_args[]); - if !sess.target.target.options.no_compiler_rt { - cmd.arg("msvcrt.lib"); - cmd.arg("compiler-rt.lib"); - } - - if sess.opts.debugging_opts.print_link_args { - println!("{:?}", &cmd); - } - - // May have not found libraries in the right formats. - sess.abort_if_errors(); - - // Invoke the system linker - debug!("{:?}", &cmd); - let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output()); - match prog { - Ok(prog) => { - if !prog.status.success() { - sess.err(&format!("linking with `{}` failed: {}", - pname, - prog.status)[]); - sess.note(&format!("{:?}", &cmd)[]); - let mut output = prog.error.clone(); - output.push_all(&prog.output[]); - sess.note(str::from_utf8(&output[..]).unwrap()); - sess.abort_if_errors(); - } - debug!("linker stderr:\n{}", String::from_utf8(prog.error).unwrap()); - debug!("linker stdout:\n{}", String::from_utf8(prog.output).unwrap()); - }, - Err(e) => { - sess.err(&format!("could not exec the linker `{}`: {}", - pname, - e)[]); - sess.abort_if_errors(); - } - } - - - // On OSX, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { - match Command::new("dsymutil").arg(out_filename).output() { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to run dsymutil: {}", e)[]); - sess.abort_if_errors(); - } - } - } -} - -fn link_args(cmd: &mut Command, - sess: &Session, - dylib: bool, - tmpdir: &Path, - trans: &CrateTranslation, - obj_filename: &Path, - out_filename: &Path) { - - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); - - // target descriptor - let t = &sess.target.target; - - lib_path.as_str().map(|lp| cmd.arg(format!("/LIBPATH:{}", lp))); - out_filename.as_str().map(|out| cmd.arg(format!("/OUT:{}", out))); - - cmd.arg(obj_filename); - - // Stack growth requires statically linking a __morestack function. Note - // that this is listed *before* all other libraries. Due to the usage of the - // --as-needed flag below, the standard library may only be useful for its - // rust_stack_exhausted function. In this case, we must ensure that the - // libmorestack.a file appears *before* the standard library (so we put it - // at the very front). - // - // Most of the time this is sufficient, except for when LLVM gets super - // clever. If, for example, we have a main function `fn main() {}`, LLVM - // will optimize out calls to `__morestack` entirely because the function - // doesn't need any stack at all! - // - // To get around this snag, we specially tell the linker to always include - // all contents of this library. This way we're guaranteed that the linker - // will include the __morestack symbol 100% of the time, always resolving - // references to it even if the object above didn't use it. - if t.options.morestack { - cmd.arg("morestack.lib"); - } - - // When linking a dynamic library, we put the metadata into a section of the - // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if dylib { - cmd.arg(obj_filename.with_extension("metadata.o")); - } - - let used_link_args = sess.cstore.get_used_link_args().borrow(); - - // We want to prevent the compiler from accidentally leaking in any system - // libraries, so we explicitly ask gcc to not link to any libraries by - // default. Note that this does not happen for windows because windows pulls - // in some large number of libraries and I couldn't quite figure out which - // subset we wanted. - - // We have to keep this in for now - since we need to link to the MSVCRT for - // things such as jemalloc. - //cmd.arg("/nodefaultlib"); - - // Take careful note of the ordering of the arguments we pass to the linker - // here. Linkers will assume that things on the left depend on things to the - // right. Things on the right cannot depend on things on the left. This is - // all formally implemented in terms of resolving symbols (libs on the right - // resolve unknown symbols of libs on the left, but not vice versa). - // - // For this reason, we have organized the arguments we pass to the linker as - // such: - // - // 1. The local object that LLVM just generated - // 2. Upstream rust libraries - // 3. Local native libraries - // 4. Upstream native libraries - // - // This is generally fairly natural, but some may expect 2 and 3 to be - // swapped. The reason that all native libraries are put last is that it's - // not recommended for a native library to depend on a symbol from a rust - // crate. If this is the case then a staticlib crate is recommended, solving - // the problem. - // - // Additionally, it is occasionally the case that upstream rust libraries - // depend on a local native library. In the case of libraries such as - // lua/glfw/etc the name of the library isn't the same across all platforms, - // so only the consumer crate of a library knows the actual name. This means - // that downstream crates will provide the #[link] attribute which upstream - // crates will depend on. Hence local native libraries are after out - // upstream rust crates. - // - // In theory this means that a symbol in an upstream native library will be - // shadowed by a local native library when it wouldn't have been before, but - // this kind of behavior is pretty platform specific and generally not - // recommended anyway, so I don't think we're shooting ourself in the foot - // much with that. - add_upstream_rust_crates(cmd, sess, dylib, tmpdir, trans); - add_local_native_libraries(cmd, sess); - add_upstream_native_libraries(cmd, sess); - - // # Telling the linker what we're doing - - if dylib { - cmd.arg("/DLL"); - } - - // FIXME (#2397): At some point we want to rpath our guesses as to - // where extern libraries might live, based on the - // addl_lib_search_paths - if sess.opts.cg.rpath { - let sysroot = sess.sysroot(); - let target_triple = &sess.opts.target_triple[]; - let get_install_prefix_lib_path = || { - let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); - let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); - let mut path = Path::new(install_prefix); - path.push(&tlib); - - path - }; - let rpath_config = RPathConfig { - used_crates: sess.cstore.get_used_crates(cstore::RequireDynamic), - out_filename: out_filename.clone(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - get_install_prefix_lib_path: get_install_prefix_lib_path, - realpath: ::util::fs::realpath - }; - cmd.args(&rpath::get_rpath_flags(rpath_config)[]); - } - - // Finally add all the linker arguments provided on the command line along - // with any #[link_args] attributes found inside the crate - let empty = Vec::new(); - cmd.args(&sess.opts.cg.link_args.as_ref().unwrap_or(&empty)[]); - cmd.args(&used_link_args[..]); -} - -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut Command, sess: &Session) { - sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, _k| { - path.as_str().map(|s| cmd.arg(format!("/LIBPATH:{}", s))); - FileDoesntMatch - }); - - let libs = sess.cstore.get_used_libraries(); - let libs = libs.borrow(); - - let staticlibs = libs.iter().filter_map(|&(ref l, kind)| { - if kind == cstore::NativeStatic {Some(l)} else {None} - }); - let others = libs.iter().filter(|&&(_, kind)| { - kind != cstore::NativeStatic - }); - - let search_path = super::link::archive_search_paths(sess); - for l in staticlibs { - let lib = archive::find_library(&l[..], - &sess.target.target.options.staticlib_prefix, - &sess.target.target.options.staticlib_suffix, - &search_path[..], - &sess.diagnostic().handler); - let mut v = Vec::new(); - v.push_all(lib.as_vec()); - cmd.arg(&v[..]); - } - - for &(ref l, kind) in others { - match kind { - cstore::NativeUnknown => { - cmd.arg(format!("{}.lib", l)); - } - cstore::NativeFramework => {} - cstore::NativeStatic => unreachable!(), - } - } -} - -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, - dylib: bool, tmpdir: &Path, - trans: &CrateTranslation) { - // All of the heavy lifting has previously been accomplished by the - // dependency_format module of the compiler. This is just crawling the - // output of that module, adding crates as necessary. - // - // Linking to a rlib involves just passing it to the linker (the linker - // will slurp up the object files inside), and linking to a dynamic library - // involves just passing the right -l flag. - - let data = if dylib { - &trans.crate_formats[config::CrateTypeDylib] - } else { - &trans.crate_formats[config::CrateTypeExecutable] - }; - - // Invoke get_used_crates to ensure that we get a topological sorting of - // crates. - let deps = sess.cstore.get_used_crates(cstore::RequireDynamic); - - for &(cnum, _) in &deps { - // We may not pass all crates through to the linker. Some crates may - // appear statically in an existing dylib, meaning we'll pick up all the - // symbols from the dylib. - let kind = match data[cnum as uint - 1] { - Some(t) => t, - None => continue - }; - let src = sess.cstore.get_used_crate_source(cnum).unwrap(); - match kind { - cstore::RequireDynamic => { - add_dynamic_crate(cmd, sess, src.dylib.unwrap().0) - } - cstore::RequireStatic => { - add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap().0) - } - } - - } - - // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] { - if stem.starts_with("lib".as_bytes()) && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } - } - - // Adds the static "rlib" versions of all crates to the command line. - fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path, - cratepath: Path) { - // When performing LTO on an executable output, all of the - // bytecode from the upstream libraries has already been - // included in our object file output. We need to modify all of - // the upstream archives to remove their corresponding object - // file to make sure we don't pull the same code in twice. - // - // We must continue to link to the upstream archives to be sure - // to pull in native static dependencies. As the final caveat, - // on Linux it is apparently illegal to link to a blank archive, - // so if an archive no longer has any object files in it after - // we remove `lib.o`, then don't link against it at all. - // - // If we're not doing LTO, then our job is simply to just link - // against the archive. - if sess.lto() { - let name = cratepath.filename_str().unwrap(); - let name = &name[3..name.len() - 5]; // chop off lib/.rlib - time(sess.time_passes(), - &format!("altering {}.rlib", name)[], - (), |()| { - let dst = tmpdir.join(cratepath.filename().unwrap()); - match fs::copy(&cratepath, &dst) { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to copy {} to {}: {}", - cratepath.display(), - dst.display(), - e)[]); - sess.abort_if_errors(); - } - } - // Fix up permissions of the copy, as fs::copy() preserves - // permissions, but the original file may have been installed - // by a package manager and may be read-only. - match fs::chmod(&dst, old_io::USER_READ | old_io::USER_WRITE) { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to chmod {} when preparing \ - for LTO: {}", dst.display(), - e)[]); - sess.abort_if_errors(); - } - } - let handler = &sess.diagnostic().handler; - let config = ArchiveConfig { - handler: handler, - dst: dst.clone(), - lib_search_paths: super::link::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() - }; - let mut archive = Archive::open(config); - archive.remove_file(&format!("{}.o", name)[]); - let files = archive.files(); - if files.iter().any(|s| s[].ends_with(".o")) { - cmd.arg(dst); - } - }); - } else { - cmd.arg(cratepath); - } - } - - // Same thing as above, but for dynamic crates instead of static crates. - fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!sess.lto()); - - cratepath.as_str().map(|s| { - let libname = s.replace(".dll", ".lib"); - cmd.arg(&libname[]); - }); - } -} - -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) { - // Be sure to use a topological sorting of crates because there may be - // interdependencies between native libraries. When passing -nodefaultlibs, - // for example, almost all native libraries depend on libc, so we have to - // make sure that's all the way at the right (liblibc is near the base of - // the dependency chain). - // - // This passes RequireStatic, but the actual requirement doesn't matter, - // we're just getting an ordering of crate numbers, we're not worried about - // the paths. - let crates = sess.cstore.get_used_crates(cstore::RequireStatic); - for (cnum, _) in crates { - let libs = csearch::get_native_libraries(&sess.cstore, cnum); - for &(kind, ref lib) in &libs { - match kind { - cstore::NativeUnknown => { - cmd.arg(format!("{}.lib", lib)); - } - cstore::NativeFramework => { - } - cstore::NativeStatic => { - sess.bug("statics shouldn't be propagated"); - } - } - } - } -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 97c672df148..3e2db80a9c5 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -75,9 +75,6 @@ pub mod back { pub use rustc_back::x86_64; pub mod link; - mod link_gnu; - mod link_msvc; - pub mod lto; pub mod write; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 413e5e1f49f..4879975dde6 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1907,16 +1907,6 @@ pub fn update_linkage(ccx: &CrateContext, llval: ValueRef, id: Option, llval_origin: ValueOrigin) { - - // TODO: This should be conditionaly set based on whether we're producing a - // dynamic library or not to follow the conventions on Windows. (ricky26) - - if ccx.sess().target.target.options.is_like_msvc { - llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass); - llvm::SetLinkage(llval, llvm::ExternalLinkage); - return; - } - match llval_origin { InlinedCopy => { // `llval` is a translation of an item defined in a separate @@ -2181,7 +2171,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, // FIXME: #16581: Marking a symbol in the executable with `dllexport` // linkage forces MinGW's linker to output a `.reloc` section for ASLR if ccx.sess().target.target.options.is_like_windows { - llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass); + unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) } } let llbb = unsafe { diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 989ef8d8bf4..503bdf8dadb 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -863,14 +863,6 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> }; llvm::LLVMSetInitializer(g, v); - // TODO: This should be conditionaly set based on whether we're producing a - // dynamic library or not to follow the conventions on Windows. (ricky26) - - if ccx.sess().target.target.options.is_like_msvc { - llvm::SetDLLStorageClass(g, llvm::DLLExportStorageClass); - llvm::SetLinkage(g, llvm::ExternalLinkage); - } - // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if m != ast::MutMutable { diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 934cf056ec1..e31d97b3240 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -31,10 +31,7 @@ pub use core::f32::consts; #[allow(dead_code)] mod cmath { use libc::{c_float, c_int}; - #[cfg(windows)] - use libc::c_double; - #[link_name = "m"] extern { pub fn acosf(n: c_float) -> c_float; pub fn asinf(n: c_float) -> c_float; @@ -59,35 +56,28 @@ mod cmath { pub fn tanhf(n: c_float) -> c_float; pub fn tgammaf(n: c_float) -> c_float; - #[cfg(unix)] + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")] pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; - #[cfg(unix)] + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")] pub fn hypotf(x: c_float, y: c_float) -> c_float; - #[cfg(unix)] + + #[cfg(any(unix, all(windows, not(target_env = "msvc"))))] pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - #[cfg(unix)] + #[cfg(any(unix, all(windows, not(target_env = "msvc"))))] pub fn ldexpf(x: c_float, n: c_int) -> c_float; - - #[cfg(windows)] - #[link_name="__lgammaf_r"] - pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; - - #[cfg(windows)] - #[link_name="_hypotf"] - pub fn hypotf(x: c_float, y: c_float) -> c_float; - - #[cfg(windows)] - fn frexp(n: c_double, value: &mut c_int) -> c_double; - - #[cfg(windows)] - fn ldexp(x: c_double, n: c_int) -> c_double; } - #[cfg(windows)] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { return ldexp(x as c_double, n) as c_float; } + #[cfg(all(windows, target_env = "msvc"))] + pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { + f64::ldexp(x as f64, n as isize) as c_float + } - #[cfg(windows)] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { return frexp(x as c_double, value) as c_float; } + #[cfg(all(windows, target_env = "msvc"))] + pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { + let (a, b) = f64::frexp(x as f64); + *value = b as c_int; + a as c_float + } } #[cfg(not(test))] diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index a09a82b8552..e87855ffd4e 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -68,17 +68,10 @@ mod cmath { pub fn y1(n: c_double) -> c_double; pub fn yn(i: c_int, n: c_double) -> c_double; - #[cfg(unix)] - pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; - #[cfg(windows)] - #[link_name="__lgamma_r"] + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgamma_r")] pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; - #[cfg(unix)] - pub fn hypot(x: c_double, y: c_double) -> c_double; - - #[cfg(windows)] - #[link_name="_hypot"] + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypot")] pub fn hypot(x: c_double, y: c_double) -> c_double; } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index d7eede6e953..0d26206f26b 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -39,17 +39,10 @@ mod macros; // These should be refactored/moved/made private over time pub mod util; +pub mod unwind; pub mod args; -#[cfg(not(all(target_os = "windows", target_abi = "msvc")))] -pub mod unwind; -#[cfg(all(target_os = "windows", target_abi = "msvc"))] -#[path = "unwind_msvc.rs"] -pub mod unwind; - mod at_exit_imp; - -#[cfg(not(all(target_os = "windows", target_abi = "msvc")))] mod libunwind; /// The default error code of the rust runtime if the main thread panics instead diff --git a/src/libstd/rt/unwind_msvc.rs b/src/libstd/rt/unwind_msvc.rs deleted file mode 100644 index b71db510c00..00000000000 --- a/src/libstd/rt/unwind_msvc.rs +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2013 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. - -//! Implementation of Rust stack unwinding -//! -//! For background on exception handling and stack unwinding please see -//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and -//! documents linked from it. -//! These are also good reads: -//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/ -//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/ -//! http://www.airs.com/blog/index.php?s=exception+frames -//! -//! ## A brief summary -//! -//! Exception handling happens in two phases: a search phase and a cleanup phase. -//! -//! In both phases the unwinder walks stack frames from top to bottom using -//! information from the stack frame unwind sections of the current process's -//! modules ("module" here refers to an OS module, i.e. an executable or a -//! dynamic library). -//! -//! For each stack frame, it invokes the associated "personality routine", whose -//! address is also stored in the unwind info section. -//! -//! In the search phase, the job of a personality routine is to examine exception -//! object being thrown, and to decide whether it should be caught at that stack -//! frame. Once the handler frame has been identified, cleanup phase begins. -//! -//! In the cleanup phase, personality routines invoke cleanup code associated -//! with their stack frames (i.e. destructors). Once stack has been unwound down -//! to the handler frame level, unwinding stops and the last personality routine -//! transfers control to its catch block. -//! -//! ## Frame unwind info registration -//! -//! Each module has its own frame unwind info section (usually ".eh_frame"), and -//! unwinder needs to know about all of them in order for unwinding to be able to -//! cross module boundaries. -//! -//! On some platforms, like Linux, this is achieved by dynamically enumerating -//! currently loaded modules via the dl_iterate_phdr() API and finding all -//! .eh_frame sections. -//! -//! Others, like Windows, require modules to actively register their unwind info -//! sections by calling __register_frame_info() API at startup. In the latter -//! case it is essential that there is only one copy of the unwinder runtime in -//! the process. This is usually achieved by linking to the dynamic version of -//! the unwind runtime. -//! -//! Currently Rust uses unwind runtime provided by libgcc. - -use prelude::v1::*; - -use any::Any; -use cell::Cell; -use cmp; -use panicking; -use fmt; -use intrinsics; -use mem; -use sync::atomic::{self, Ordering}; -use sync::{Once, ONCE_INIT}; - -pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: uint); - -// Variables used for invoking callbacks when a thread starts to unwind. -// -// For more information, see below. -const MAX_CALLBACKS: uint = 16; -static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] = - [atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT, - atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT]; -static CALLBACK_CNT: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT; - -thread_local! { static PANICKING: Cell = Cell::new(false) } - -/// Invoke a closure, capturing the cause of panic if one occurs. -/// -/// This function will return `Ok(())` if the closure did not panic, and will -/// return `Err(cause)` if the closure panics. The `cause` returned is the -/// object with which panic was originally invoked. -/// -/// This function also is unsafe for a variety of reasons: -/// -/// * This is not safe to call in a nested fashion. The unwinding -/// interface for Rust is designed to have at most one try/catch block per -/// thread, not multiple. No runtime checking is currently performed to uphold -/// this invariant, so this function is not safe. A nested try/catch block -/// may result in corruption of the outer try/catch block's state, especially -/// if this is used within a thread itself. -/// -/// * It is not sound to trigger unwinding while already unwinding. Rust threads -/// have runtime checks in place to ensure this invariant, but it is not -/// guaranteed that a rust thread is in place when invoking this function. -/// Unwinding twice can lead to resource leaks where some destructors are not -/// run. -pub unsafe fn try(f: F) -> Result<(), Box> { - f(); - Ok(()) -} - -/// Determines whether the current thread is unwinding because of panic. -pub fn panicking() -> bool { - PANICKING.with(|s| s.get()) -} - -// An uninlined, unmangled function upon which to slap yer breakpoints -#[inline(never)] -#[no_mangle] -#[allow(private_no_mangle_fns)] -fn rust_panic(_cause: Box) -> ! { - loop {} -} - -// See also: rt/rust_try.ll -#[cfg(all(not(test)))] -#[doc(hidden)] -#[allow(non_camel_case_types, non_snake_case)] -pub mod eabi { - pub use self::EXCEPTION_DISPOSITION::*; - use libc::c_void; - - #[repr(C)] - pub struct EXCEPTION_RECORD; - #[repr(C)] - pub struct CONTEXT; - #[repr(C)] - pub struct DISPATCHER_CONTEXT; - - #[repr(C)] - #[derive(Copy)] - pub enum EXCEPTION_DISPOSITION { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind - } - - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( - _exceptionRecord: *mut EXCEPTION_RECORD, - _establisherFrame: *mut c_void, - _contextRecord: *mut CONTEXT, - _dispatcherContext: *mut DISPATCHER_CONTEXT - ) -> EXCEPTION_DISPOSITION - { - EXCEPTION_DISPOSITION::ExceptionContinueSearch - } - - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( - _exceptionRecord: *mut EXCEPTION_RECORD, - _establisherFrame: *mut c_void, - _contextRecord: *mut CONTEXT, - _dispatcherContext: *mut DISPATCHER_CONTEXT - ) -> EXCEPTION_DISPOSITION - { - EXCEPTION_DISPOSITION::ExceptionContinueSearch - } -} - -#[cfg(not(test))] -/// Entry point of panic from the libcore crate. -#[lang = "panic_fmt"] -pub extern fn rust_begin_unwind(msg: fmt::Arguments, - file: &'static str, line: uint) -> ! { - begin_unwind_fmt(msg, &(file, line)) -} - -/// The entry point for unwinding with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[inline(never)] #[cold] -#[stable(since = "1.0.0", feature = "rust1")] -pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! { - use fmt::Write; - - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_unwind - // below). - - let mut s = String::new(); - let _ = write!(&mut s, "{}", msg); - begin_unwind_inner(box s, file_line) -} - -/// This is the entry point of unwinding for panic!() and assert!(). -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -#[stable(since = "1.0.0", feature = "rust1")] -pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> ! { - // Note that this should be the only allocation performed in this code path. - // Currently this means that panic!() on OOM will invoke this code path, - // but then again we're not really ready for panic on OOM anyway. If - // we do start doing this, then we should propagate this allocation to - // be performed in the parent of this thread instead of the thread that's - // panicking. - - // see below for why we do the `Any` coercion here. - begin_unwind_inner(box msg, file_line) -} - -/// The core of the unwinding. -/// -/// This is non-generic to avoid instantiation bloat in other crates -/// (which makes compilation of small crates noticeably slower). (Note: -/// we need the `Any` object anyway, we're not just creating it to -/// avoid being generic.) -/// -/// Doing this split took the LLVM IR line counts of `fn main() { panic!() -/// }` from ~1900/3700 (-O/no opts) to 180/590. -#[inline(never)] #[cold] // this is the slow path, please never inline this -fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> ! { - // Make sure the default panic handler is registered before we look at the - // callbacks. - static INIT: Once = ONCE_INIT; - INIT.call_once(|| unsafe { register(panicking::on_panic); }); - - // First, invoke call the user-defined callbacks triggered on thread panic. - // - // By the time that we see a callback has been registered (by reading - // MAX_CALLBACKS), the actual callback itself may have not been stored yet, - // so we just chalk it up to a race condition and move on to the next - // callback. Additionally, CALLBACK_CNT may briefly be higher than - // MAX_CALLBACKS, so we're sure to clamp it as necessary. - let callbacks = { - let amt = CALLBACK_CNT.load(Ordering::SeqCst); - &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)] - }; - for cb in callbacks { - match cb.load(Ordering::SeqCst) { - 0 => {} - n => { - let f: Callback = unsafe { mem::transmute(n) }; - let (file, line) = *file_line; - f(&*msg, file, line); - } - } - }; - - // Now that we've run all the necessary unwind callbacks, we actually - // perform the unwinding. - if panicking() { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - rterrln!("thread panicked while panicking. aborting."); - unsafe { intrinsics::abort() } - } - PANICKING.with(|s| s.set(true)); - rust_panic(msg); -} - -/// Register a callback to be invoked when a thread unwinds. -/// -/// This is an unsafe and experimental API which allows for an arbitrary -/// callback to be invoked when a thread panics. This callback is invoked on both -/// the initial unwinding and a double unwinding if one occurs. Additionally, -/// the local `Task` will be in place for the duration of the callback, and -/// the callback must ensure that it remains in place once the callback returns. -/// -/// Only a limited number of callbacks can be registered, and this function -/// returns whether the callback was successfully registered or not. It is not -/// currently possible to unregister a callback once it has been registered. -#[unstable(feature = "std_misc")] -pub unsafe fn register(f: Callback) -> bool { - match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) { - // The invocation code has knowledge of this window where the count has - // been incremented, but the callback has not been stored. We're - // guaranteed that the slot we're storing into is 0. - n if n < MAX_CALLBACKS => { - let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst); - rtassert!(prev == 0); - true - } - // If we accidentally bumped the count too high, pull it back. - _ => { - CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst); - false - } - } -}