]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/back/link.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / librustc / back / link.rs
index e2264088b4a84ab2f986470ff9ffb3f498498b62..0cf884eccbcb322676a0f4d2161a4bb7bf17000e 100644 (file)
@@ -8,16 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use back::archive::{Archive, METADATA_FILENAME};
-use back::rpath;
-use back::svh::Svh;
+use super::archive::{Archive, ArchiveBuilder, ArchiveConfig, METADATA_FILENAME};
+use super::rpath;
+use super::rpath::RPathConfig;
+use super::svh::Svh;
 use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput};
 use driver::config::NoDebugInfo;
 use driver::session::Session;
 use driver::config;
-use lib::llvm::llvm;
-use lib::llvm::ModuleRef;
-use lib;
+use llvm;
+use llvm::ModuleRef;
 use metadata::common::LinkMeta;
 use metadata::{encoder, cstore, filesearch, csearch, loader, creader};
 use middle::trans::context::CrateContext;
@@ -29,6 +29,7 @@
 
 use std::c_str::{ToCStr, CString};
 use std::char;
+use std::collections::HashSet;
 use std::io::{fs, TempDir, Command};
 use std::io;
 use std::ptr;
@@ -60,7 +61,7 @@ pub fn llvm_err(sess: &Session, msg: String) -> ! {
             sess.fatal(msg.as_slice());
         } else {
             let err = CString::new(cstr, true);
-            let err = str::from_utf8_lossy(err.as_bytes());
+            let err = String::from_utf8_lossy(err.as_bytes());
             sess.fatal(format!("{}: {}",
                                msg.as_slice(),
                                err.as_slice()).as_slice());
@@ -70,11 +71,11 @@ pub fn llvm_err(sess: &Session, msg: String) -> ! {
 
 pub fn write_output_file(
         sess: &Session,
-        target: lib::llvm::TargetMachineRef,
-        pm: lib::llvm::PassManagerRef,
+        target: llvm::TargetMachineRef,
+        pm: llvm::PassManagerRef,
         m: ModuleRef,
         output: &Path,
-        file_type: lib::llvm::FileType) {
+        file_type: llvm::FileType) {
     unsafe {
         output.with_c_str(|output| {
             let result = llvm::LLVMRustWriteOutputFile(
@@ -88,18 +89,17 @@ pub fn write_output_file(
 
 pub mod write {
 
-    use back::lto;
-    use back::link::{write_output_file, OutputType};
-    use back::link::{OutputTypeAssembly, OutputTypeBitcode};
-    use back::link::{OutputTypeExe, OutputTypeLlvmAssembly};
-    use back::link::{OutputTypeObject};
+    use super::super::lto;
+    use super::{write_output_file, OutputType};
+    use super::{OutputTypeAssembly, OutputTypeBitcode};
+    use super::{OutputTypeExe, OutputTypeLlvmAssembly};
+    use super::{OutputTypeObject};
     use driver::driver::{CrateTranslation, OutputFilenames};
     use driver::config::NoDebugInfo;
     use driver::session::Session;
     use driver::config;
-    use lib::llvm::llvm;
-    use lib::llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
-    use lib;
+    use llvm;
+    use llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
     use util::common::time;
     use syntax::abi;
 
@@ -152,10 +152,10 @@ pub fn run_passes(sess: &Session,
             }
 
             let opt_level = match sess.opts.optimize {
-              config::No => lib::llvm::CodeGenLevelNone,
-              config::Less => lib::llvm::CodeGenLevelLess,
-              config::Default => lib::llvm::CodeGenLevelDefault,
-              config::Aggressive => lib::llvm::CodeGenLevelAggressive,
+              config::No => llvm::CodeGenLevelNone,
+              config::Less => llvm::CodeGenLevelLess,
+              config::Default => llvm::CodeGenLevelDefault,
+              config::Aggressive => llvm::CodeGenLevelAggressive,
             };
             let use_softfp = sess.opts.cg.soft_float;
 
@@ -172,10 +172,10 @@ pub fn run_passes(sess: &Session,
             let fdata_sections = ffunction_sections;
 
             let reloc_model = match sess.opts.cg.relocation_model.as_slice() {
-                "pic" => lib::llvm::RelocPIC,
-                "static" => lib::llvm::RelocStatic,
-                "default" => lib::llvm::RelocDefault,
-                "dynamic-no-pic" => lib::llvm::RelocDynamicNoPic,
+                "pic" => llvm::RelocPIC,
+                "static" => llvm::RelocStatic,
+                "default" => llvm::RelocDefault,
+                "dynamic-no-pic" => llvm::RelocDynamicNoPic,
                 _ => {
                     sess.err(format!("{} is not a valid relocation mode",
                                      sess.opts
@@ -186,6 +186,22 @@ pub fn run_passes(sess: &Session,
                 }
             };
 
+            let code_model = match sess.opts.cg.code_model.as_slice() {
+                "default" => llvm::CodeModelDefault,
+                "small" => llvm::CodeModelSmall,
+                "kernel" => llvm::CodeModelKernel,
+                "medium" => llvm::CodeModelMedium,
+                "large" => llvm::CodeModelLarge,
+                _ => {
+                    sess.err(format!("{} is not a valid code model",
+                                     sess.opts
+                                         .cg
+                                         .code_model).as_slice());
+                    sess.abort_if_errors();
+                    return;
+                }
+            };
+
             let tm = sess.targ_cfg
                          .target_strs
                          .target_triple
@@ -195,7 +211,7 @@ pub fn run_passes(sess: &Session,
                     target_feature(sess).with_c_str(|features| {
                         llvm::LLVMRustCreateTargetMachine(
                             t, cpu, features,
-                            lib::llvm::CodeModelDefault,
+                            code_model,
                             reloc_model,
                             opt_level,
                             true /* EnableSegstk */,
@@ -320,7 +336,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                         };
                         with_codegen(tm, llmod, trans.no_builtins, |cpm| {
                             write_output_file(sess, tm, cpm, llmod, &path,
-                                            lib::llvm::AssemblyFile);
+                                            llvm::AssemblyFile);
                         });
                     }
                     OutputTypeObject => {
@@ -338,7 +354,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                     Some(ref path) => {
                         with_codegen(tm, llmod, trans.no_builtins, |cpm| {
                             write_output_file(sess, tm, cpm, llmod, path,
-                                            lib::llvm::ObjectFile);
+                                            llvm::ObjectFile);
                         });
                     }
                     None => {}
@@ -350,7 +366,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                                         .with_extension("metadata.o");
                         write_output_file(sess, tm, cpm,
                                         trans.metadata_module, &out,
-                                        lib::llvm::ObjectFile);
+                                        llvm::ObjectFile);
                     })
                 }
             });
@@ -380,8 +396,7 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
                     sess.note(format!("{}", &cmd).as_slice());
                     let mut note = prog.error.clone();
                     note.push_all(prog.output.as_slice());
-                    sess.note(str::from_utf8(note.as_slice()).unwrap()
-                                                             .as_slice());
+                    sess.note(str::from_utf8(note.as_slice()).unwrap());
                     sess.abort_if_errors();
                 }
             },
@@ -455,29 +470,29 @@ unsafe fn configure_llvm(sess: &Session) {
         });
     }
 
-    unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
-                                   mpm: lib::llvm::PassManagerRef,
+    unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
+                                   mpm: llvm::PassManagerRef,
                                    llmod: ModuleRef,
-                                   opt: lib::llvm::CodeGenOptLevel,
+                                   opt: llvm::CodeGenOptLevel,
                                    no_builtins: bool) {
         // Create the PassManagerBuilder for LLVM. We configure it with
         // reasonable defaults and prepare it to actually populate the pass
         // manager.
         let builder = llvm::LLVMPassManagerBuilderCreate();
         match opt {
-            lib::llvm::CodeGenLevelNone => {
+            llvm::CodeGenLevelNone => {
                 // Don't add lifetime intrinsics at O0
                 llvm::LLVMRustAddAlwaysInlinePass(builder, false);
             }
-            lib::llvm::CodeGenLevelLess => {
+            llvm::CodeGenLevelLess => {
                 llvm::LLVMRustAddAlwaysInlinePass(builder, true);
             }
             // numeric values copied from clang
-            lib::llvm::CodeGenLevelDefault => {
+            llvm::CodeGenLevelDefault => {
                 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
                                                                     225);
             }
-            lib::llvm::CodeGenLevelAggressive => {
+            llvm::CodeGenLevelAggressive => {
                 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
                                                                     275);
             }
@@ -555,19 +570,35 @@ pub fn find_crate_name(sess: Option<&Session>,
         s
     };
 
+    // Look in attributes 100% of the time to make sure the attribute is marked
+    // as used. After doing this, however, we still prioritize a crate name from
+    // the command line over one found in the #[crate_name] attribute. If we
+    // find both we ensure that they're the same later on as well.
+    let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
+                               .and_then(|at| at.value_str().map(|s| (at, s)));
+
     match sess {
         Some(sess) => {
             match sess.opts.crate_name {
-                Some(ref s) => return validate(s.clone(), None),
+                Some(ref s) => {
+                    match attr_crate_name {
+                        Some((attr, ref name)) if s.as_slice() != name.get() => {
+                            let msg = format!("--crate-name and #[crate_name] \
+                                               are required to match, but `{}` \
+                                               != `{}`", s, name);
+                            sess.span_err(attr.span, msg.as_slice());
+                        }
+                        _ => {},
+                    }
+                    return validate(s.clone(), None);
+                }
                 None => {}
             }
         }
         None => {}
     }
 
-    let crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
-                          .and_then(|at| at.value_str().map(|s| (at, s)));
-    match crate_name {
+    match attr_crate_name {
         Some((attr, s)) => return validate(s.get().to_string(), Some(attr.span)),
         None => {}
     }
@@ -607,7 +638,7 @@ pub fn build_link_meta(sess: &Session, krate: &ast::Crate,
                        name: String) -> LinkMeta {
     let r = LinkMeta {
         crate_name: name,
-        crate_hash: Svh::calculate(sess, krate),
+        crate_hash: Svh::calculate(&sess.opts.cg.metadata, krate),
     };
     info!("{}", r);
     return r;
@@ -896,6 +927,7 @@ pub fn filename_for_input(sess: &Session,
                 abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX),
                 abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX),
                 abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX),
+                abi::OsDragonfly => (loader::DRAGONFLY_DLL_PREFIX, loader::DRAGONFLY_DLL_SUFFIX),
                 abi::OsiOS => unreachable!(),
             };
             out_filename.with_filename(format!("{}{}{}",
@@ -906,7 +938,17 @@ pub fn filename_for_input(sess: &Session,
         config::CrateTypeStaticlib => {
             out_filename.with_filename(format!("lib{}.a", libname))
         }
-        config::CrateTypeExecutable => out_filename.clone(),
+        config::CrateTypeExecutable => {
+            match sess.targ_cfg.os {
+                abi::OsWin32 => out_filename.with_extension("exe"),
+                abi::OsMacos |
+                abi::OsLinux |
+                abi::OsAndroid |
+                abi::OsFreebsd |
+                abi::OsDragonfly |
+                abi::OsiOS => out_filename.clone(),
+            }
+        }
     }
 }
 
@@ -943,7 +985,7 @@ fn link_binary_output(sess: &Session,
 
     match crate_type {
         config::CrateTypeRlib => {
-            link_rlib(sess, Some(trans), &obj_filename, &out_filename);
+            link_rlib(sess, Some(trans), &obj_filename, &out_filename).build();
         }
         config::CrateTypeStaticlib => {
             link_staticlib(sess, &obj_filename, &out_filename);
@@ -959,6 +1001,17 @@ fn link_binary_output(sess: &Session,
     out_filename
 }
 
+fn archive_search_paths(sess: &Session) -> Vec<Path> {
+    let mut rustpath = filesearch::rust_path();
+    rustpath.push(sess.target_filesearch().get_lib_path());
+    // FIXME: Addl lib search paths are an unordered HashSet?
+    // Shouldn't this search be done in some order?
+    let addl_lib_paths: HashSet<Path> = sess.opts.addl_lib_search_paths.borrow().clone();
+    let mut search: Vec<Path> = addl_lib_paths.move_iter().collect();
+    search.push_all(rustpath.as_slice());
+    return search;
+}
+
 // Create an 'rlib'
 //
 // An rlib in its current incarnation is essentially a renamed .a file. The
@@ -968,18 +1021,39 @@ fn link_binary_output(sess: &Session,
 fn link_rlib<'a>(sess: &'a Session,
                  trans: Option<&CrateTranslation>, // None == no metadata/bytecode
                  obj_filename: &Path,
-                 out_filename: &Path) -> Archive<'a> {
-    let mut a = Archive::create(sess, out_filename, obj_filename);
+                 out_filename: &Path) -> ArchiveBuilder<'a> {
+    let handler = &sess.diagnostic().handler;
+    let config = ArchiveConfig {
+        handler: handler,
+        dst: out_filename.clone(),
+        lib_search_paths: archive_search_paths(sess),
+        os: sess.targ_cfg.os,
+        maybe_ar_prog: sess.opts.cg.ar.clone()
+    };
+    let mut ab = ArchiveBuilder::create(config);
+    ab.add_file(obj_filename).unwrap();
 
     for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
         match kind {
             cstore::NativeStatic => {
-                a.add_native_library(l.as_slice()).unwrap();
+                ab.add_native_library(l.as_slice()).unwrap();
             }
             cstore::NativeFramework | cstore::NativeUnknown => {}
         }
     }
 
+    // After adding all files to the archive, we need to update the
+    // symbol table of the archive.
+    ab.update_symbols();
+
+    let mut ab = match sess.targ_cfg.os {
+        // For OSX/iOS, we must be careful to update symbols only when adding
+        // object files.  We're about to start adding non-object files, so run
+        // `ar` now to process the object files.
+        abi::OsMacos | abi::OsiOS => ab.build().extend(),
+        _ => ab,
+    };
+
     // Note that it is important that we add all of our non-object "magical
     // files" *after* all of the object files in the archive. The reason for
     // this is as follows:
@@ -1019,7 +1093,7 @@ fn link_rlib<'a>(sess: &'a Session,
                     sess.abort_if_errors();
                 }
             }
-            a.add_file(&metadata, false);
+            ab.add_file(&metadata).unwrap();
             remove(sess, &metadata);
 
             // For LTO purposes, the bytecode of this library is also inserted
@@ -1046,25 +1120,18 @@ fn link_rlib<'a>(sess: &'a Session,
                     sess.abort_if_errors()
                 }
             }
-            a.add_file(&bc_deflated, false);
+            ab.add_file(&bc_deflated).unwrap();
             remove(sess, &bc_deflated);
             if !sess.opts.cg.save_temps &&
                !sess.opts.output_types.contains(&OutputTypeBitcode) {
                 remove(sess, &bc);
             }
-
-            // After adding all files to the archive, we need to update the
-            // symbol table of the archive. This currently dies on OSX (see
-            // #11162), and isn't necessary there anyway
-            match sess.targ_cfg.os {
-                abi::OsMacos | abi::OsiOS => {}
-                _ => { a.update_symbols(); }
-            }
         }
 
         None => {}
     }
-    return a;
+
+    ab
 }
 
 // Create a static archive
@@ -1080,9 +1147,13 @@ fn link_rlib<'a>(sess: &'a Session,
 // link in the metadata object file (and also don't prepare the archive with a
 // metadata file).
 fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
-    let mut a = link_rlib(sess, None, obj_filename, out_filename);
-    a.add_native_library("morestack").unwrap();
-    a.add_native_library("compiler-rt").unwrap();
+    let ab = link_rlib(sess, None, obj_filename, out_filename);
+    let mut ab = match sess.targ_cfg.os {
+        abi::OsMacos | abi::OsiOS => ab.build().extend(),
+        _ => ab,
+    };
+    ab.add_native_library("morestack").unwrap();
+    ab.add_native_library("compiler-rt").unwrap();
 
     let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
     let mut all_native_libs = vec![];
@@ -1096,12 +1167,15 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
                 continue
             }
         };
-        a.add_rlib(&p, name.as_slice(), sess.lto()).unwrap();
+        ab.add_rlib(&p, name.as_slice(), sess.lto()).unwrap();
 
         let native_libs = csearch::get_native_libraries(&sess.cstore, cnum);
         all_native_libs.extend(native_libs.move_iter());
     }
 
+    ab.update_symbols();
+    let _ = ab.build();
+
     if !all_native_libs.is_empty() {
         sess.warn("link against the following native artifacts when linking against \
                   this static library");
@@ -1154,8 +1228,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
                 sess.note(format!("{}", &cmd).as_slice());
                 let mut output = prog.error.clone();
                 output.push_all(prog.output.as_slice());
-                sess.note(str::from_utf8(output.as_slice()).unwrap()
-                                                           .as_slice());
+                sess.note(str::from_utf8(output.as_slice()).unwrap());
                 sess.abort_if_errors();
             }
         },
@@ -1172,7 +1245,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
     // the symbols
     if (sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS)
         && (sess.opts.debuginfo != NoDebugInfo) {
-            match Command::new("dsymutil").arg(out_filename).status() {
+            match Command::new("dsymutil").arg(out_filename).output() {
                 Ok(..) => {}
                 Err(e) => {
                     sess.err(format!("failed to run dsymutil: {}", e).as_slice());
@@ -1217,7 +1290,7 @@ fn link_args(cmd: &mut Command,
         abi::OsMacos | abi::OsiOS => {
             let morestack = lib_path.join("libmorestack.a");
 
-            let mut v = "-Wl,-force_load,".as_bytes().to_owned();
+            let mut v = b"-Wl,-force_load,".to_vec();
             v.push_all(morestack.as_vec());
             cmd.arg(v.as_slice());
         }
@@ -1253,7 +1326,7 @@ fn link_args(cmd: &mut Command,
         cmd.arg("-Wl,--gc-sections");
     }
 
-    if sess.targ_cfg.os == abi::OsLinux {
+    if sess.targ_cfg.os == abi::OsLinux || sess.targ_cfg.os == abi::OsDragonfly {
         // GNU-style linkers will use this to omit linking to libraries which
         // don't actually fulfill any relocations, but only for libraries which
         // follow this flag. Thus, use it before specifying libraries to link to.
@@ -1378,12 +1451,35 @@ fn link_args(cmd: &mut Command,
                   "-L/usr/local/lib/gcc46",
                   "-L/usr/local/lib/gcc44"]);
     }
+    else if sess.targ_cfg.os == abi::OsDragonfly {
+        cmd.args(["-L/usr/local/lib",
+                  "-L/usr/lib/gcc47",
+                  "-L/usr/lib/gcc44"]);
+    }
+
 
     // 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 {
-        cmd.args(rpath::get_rpath_flags(sess, out_filename).as_slice());
+        let sysroot = sess.sysroot();
+        let target_triple = sess.opts.target_triple.as_slice();
+        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 {
+            os: sess.targ_cfg.os,
+            used_crates: sess.cstore.get_used_crates(cstore::RequireDynamic),
+            out_filename: out_filename.clone(),
+            get_install_prefix_lib_path: get_install_prefix_lib_path,
+            realpath: ::util::fs::realpath
+        };
+        cmd.args(rpath::get_rpath_flags(rpath_config).as_slice());
     }
 
     // compiler-rt contains implementations of low-level LLVM helpers. This is
@@ -1493,7 +1589,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
                 add_dynamic_crate(cmd, sess, src.dylib.unwrap())
             }
             cstore::RequireStatic => {
-                add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap())
+                add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap())
             }
         }
 
@@ -1510,7 +1606,7 @@ fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] {
 
     // Adds the static "rlib" versions of all crates to the command line.
     fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
-                        cnum: ast::CrateNum, cratepath: 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
@@ -1526,7 +1622,8 @@ fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
         // If we're not doing LTO, then our job is simply to just link
         // against the archive.
         if sess.lto() {
-            let name = sess.cstore.get_crate_data(cnum).name.clone();
+            let name = cratepath.filename_str().unwrap();
+            let name = name.slice(3, name.len() - 5); // chop off lib/.rlib
             time(sess.time_passes(),
                  format!("altering {}.rlib", name).as_slice(),
                  (), |()| {
@@ -1541,7 +1638,15 @@ fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
                         sess.abort_if_errors();
                     }
                 }
-                let mut archive = Archive::open(sess, dst.clone());
+                let handler = &sess.diagnostic().handler;
+                let config = ArchiveConfig {
+                    handler: handler,
+                    dst: dst.clone(),
+                    lib_search_paths: archive_search_paths(sess),
+                    os: sess.targ_cfg.os,
+                    maybe_ar_prog: sess.opts.cg.ar.clone()
+                };
+                let mut archive = Archive::open(config);
                 archive.remove_file(format!("{}.o", name).as_slice());
                 let files = archive.files();
                 if files.iter().any(|s| s.as_slice().ends_with(".o")) {