about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs75
-rw-r--r--tests/run-make/staticlib-dylib-linkage/Makefile25
2 files changed, 76 insertions, 24 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 02e21e74fad..5144319752a 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -544,12 +544,38 @@ fn link_staticlib<'a>(
 
     ab.build(out_filename);
 
-    if !all_native_libs.is_empty() {
-        if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
-            print_native_static_libs(sess, &all_native_libs);
+    let crates = codegen_results.crate_info.used_crates.iter();
+
+    let fmts = codegen_results
+        .crate_info
+        .dependency_formats
+        .iter()
+        .find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None })
+        .expect("no dependency formats for staticlib");
+
+    let mut all_rust_dylibs = vec![];
+    for &cnum in crates {
+        match fmts.get(cnum.as_usize() - 1) {
+            Some(&Linkage::Dynamic) => {}
+            _ => continue,
+        }
+        let crate_name = codegen_results.crate_info.crate_name[&cnum];
+        let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum];
+        if let Some((path, _)) = &used_crate_source.dylib {
+            all_rust_dylibs.push(&**path);
+        } else {
+            if used_crate_source.rmeta.is_some() {
+                sess.emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
+            } else {
+                sess.emit_fatal(errors::LinkRlibError::NotFound { crate_name });
+            }
         }
     }
 
+    if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
+        print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs);
+    }
+
     Ok(())
 }
 
@@ -1291,8 +1317,12 @@ enum RlibFlavor {
     StaticlibBase,
 }
 
-fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
-    let lib_args: Vec<_> = all_native_libs
+fn print_native_static_libs(
+    sess: &Session,
+    all_native_libs: &[NativeLib],
+    all_rust_dylibs: &[&Path],
+) {
+    let mut lib_args: Vec<_> = all_native_libs
         .iter()
         .filter(|l| relevant_lib(sess, l))
         .filter_map(|lib| {
@@ -1322,6 +1352,41 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
             }
         })
         .collect();
+    for path in all_rust_dylibs {
+        // FIXME deduplicate with add_dynamic_crate
+
+        // Just need to tell the linker about where the library lives and
+        // what its name is
+        let parent = path.parent();
+        if let Some(dir) = parent {
+            let dir = fix_windows_verbatim_for_gcc(dir);
+            if sess.target.is_like_msvc {
+                let mut arg = String::from("/LIBPATH:");
+                arg.push_str(&dir.display().to_string());
+                lib_args.push(arg);
+            } else {
+                lib_args.push("-L".to_owned());
+                lib_args.push(dir.display().to_string());
+            }
+        }
+        let stem = path.file_stem().unwrap().to_str().unwrap();
+        // Convert library file-stem into a cc -l argument.
+        let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
+        let lib = &stem[prefix..];
+        let path = parent.unwrap_or_else(|| Path::new(""));
+        if sess.target.is_like_msvc {
+            // When producing a dll, the MSVC linker may not actually emit a
+            // `foo.lib` file if the dll doesn't actually export any symbols, so we
+            // check to see if the file is there and just omit linking to it if it's
+            // not present.
+            let name = format!("{}.dll.lib", lib);
+            if path.join(&name).exists() {
+                lib_args.push(name);
+            }
+        } else {
+            lib_args.push(format!("-l{}", lib));
+        }
+    }
     if !lib_args.is_empty() {
         sess.emit_note(errors::StaticLibraryNativeArtifacts);
         // Prefix for greppability
diff --git a/tests/run-make/staticlib-dylib-linkage/Makefile b/tests/run-make/staticlib-dylib-linkage/Makefile
index bf811395981..faa45243104 100644
--- a/tests/run-make/staticlib-dylib-linkage/Makefile
+++ b/tests/run-make/staticlib-dylib-linkage/Makefile
@@ -1,27 +1,14 @@
 include ../tools.mk
 
-TARGET_SYSROOT := $(shell $(RUSTC) --print sysroot)/lib/rustlib/$(TARGET)/lib
+all:
+	$(RUSTC) -C prefer-dynamic bar.rs
+	$(RUSTC) foo.rs --crate-type staticlib --print native-static-libs 2>&1 | grep 'note: native-static-libs: ' | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt
+	cat $(TMPDIR)/libs.txt
 
 ifdef IS_MSVC
-LIBSTD := $(wildcard $(TARGET_SYSROOT)/libstd-*.dll.lib)
+	$(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.lib $$(cat $(TMPDIR)/libs.txt) $(call OUT_EXE,foo)
 else
-LIBSTD := $(wildcard $(TARGET_SYSROOT)/$(call DYLIB_GLOB,std))
-STD := $(basename $(patsubst lib%,%, $(notdir $(LIBSTD))))
+	$(CC) $(CFLAGS) foo.c -L $(TMPDIR) -lfoo $$(cat $(TMPDIR)/libs.txt) -o $(call RUN_BINFILE,foo)
 endif
 
-all: $(call RUN_BINFILE,foo)
 	$(call RUN,foo)
-
-ifdef IS_MSVC
-CLIBS := $(TMPDIR)/foo.lib $(TMPDIR)/bar.dll.lib $(LIBSTD)
-$(call RUN_BINFILE,foo): $(call STATICLIB,foo)
-	$(CC) $(CFLAGS) foo.c $(CLIBS) $(call OUT_EXE,foo)
-else
-CLIBS := $(TMPDIR)/libfoo.a -lbar -l$(STD) -L $(TMPDIR) -L $(TARGET_SYSROOT)
-$(call RUN_BINFILE,foo): $(call STATICLIB,foo)
-	$(CC) $(CFLAGS) foo.c $(CLIBS) -o $(call RUN_BINFILE,foo)
-endif
-
-$(call STATICLIB,foo):
-	$(RUSTC) -C prefer-dynamic bar.rs
-	$(RUSTC) foo.rs