From 1f33785ed4a4774c5d68c78a13a24f9faf0dac55 Mon Sep 17 00:00:00 2001
From: Daniel Paoliello <danpao@microsoft.com>
Date: Fri, 1 Jul 2022 13:01:41 -0700
Subject: [PATCH] Enable raw-dylib for binaries

---
 .../rustc_codegen_cranelift/src/archive.rs    | 14 +++---
 compiler/rustc_codegen_gcc/src/archive.rs     | 12 ++++-
 .../rustc_codegen_llvm/src/back/archive.rs    | 44 +++++++++----------
 .../rustc_codegen_ssa/src/back/archive.rs     | 29 +++++++++++-
 compiler/rustc_codegen_ssa/src/back/link.rs   | 27 +++++++++---
 src/test/run-make-fulldeps/tools.mk           |  2 +-
 .../raw-dylib-alt-calling-convention/Makefile |  6 +--
 src/test/run-make/raw-dylib-c/Makefile        | 11 +++--
 src/test/run-make/raw-dylib-c/lib.rs          |  4 ++
 .../run-make/raw-dylib-link-ordinal/Makefile  |  6 +--
 .../raw-dylib-stdcall-ordinal/Makefile        |  6 +--
 11 files changed, 108 insertions(+), 53 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 0812f930b5dea..f3f3628fceeac 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -204,12 +204,16 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
         any_members
     }
 
-    fn inject_dll_import_lib(
-        &mut self,
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn create_dll_import_lib(
+        _sess: &Session,
         _lib_name: &str,
         _dll_imports: &[rustc_session::cstore::DllImport],
-        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
-    ) {
-        bug!("injecting dll imports is not supported");
+        _tmpdir: &Path,
+    ) -> PathBuf {
+        bug!("creating dll imports is not supported");
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index 411ec27139e42..21f62a6b0096a 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -4,7 +4,6 @@ use std::path::{Path, PathBuf};
 use rustc_codegen_ssa::back::archive::ArchiveBuilder;
 use rustc_session::Session;
 
-use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_session::cstore::DllImport;
 
 struct ArchiveConfig<'a> {
@@ -177,7 +176,16 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
         any_members
     }
 
-    fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+    fn sess(&self) -> &Session {
+        self.config.sess
+    }
+
+    fn create_dll_import_lib(
+        _sess: &Session,
+        _lib_name: &str,
+        _dll_imports: &[DllImport],
+        _tmpdir: &Path,
+    ) -> PathBuf {
         unimplemented!();
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index bccc2a995a30c..baa858709a0c6 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -11,7 +11,6 @@ use std::str;
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::ArchiveBuilder;
-use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_session::cstore::{DllCallingConvention, DllImport};
 use rustc_session::Session;
 
@@ -96,19 +95,23 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
         }
     }
 
-    fn inject_dll_import_lib(
-        &mut self,
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn create_dll_import_lib(
+        sess: &Session,
         lib_name: &str,
         dll_imports: &[DllImport],
-        tmpdir: &MaybeTempDir,
-    ) {
+        tmpdir: &Path,
+    ) -> PathBuf {
         let output_path = {
-            let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+            let mut output_path: PathBuf = tmpdir.to_path_buf();
             output_path.push(format!("{}_imports", lib_name));
             output_path.with_extension("lib")
         };
 
-        let target = &self.sess.target;
+        let target = &sess.target;
         let mingw_gnu_toolchain = target.vendor == "pc"
             && target.os == "windows"
             && target.env == "gnu"
@@ -117,7 +120,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
         let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
-                if self.sess.target.arch == "x86" {
+                if sess.target.arch == "x86" {
                     (
                         LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
                         import.ordinal,
@@ -134,8 +137,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
             // that loaded but crashed with an AV upon calling one of the imported
             // functions.  Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
-            let def_file_path =
-                tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
+            let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
 
             let def_file_content = format!(
                 "EXPORTS\n{}",
@@ -154,11 +156,11 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    self.sess.fatal(&format!("Error writing .DEF file: {}", e));
+                    sess.fatal(&format!("Error writing .DEF file: {}", e));
                 }
             };
 
-            let dlltool = find_binutils_dlltool(self.sess);
+            let dlltool = find_binutils_dlltool(sess);
             let result = std::process::Command::new(dlltool)
                 .args([
                     "-d",
@@ -172,9 +174,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
 
             match result {
                 Err(e) => {
-                    self.sess.fatal(&format!("Error calling dlltool: {}", e));
+                    sess.fatal(&format!("Error calling dlltool: {}", e));
                 }
-                Ok(output) if !output.status.success() => self.sess.fatal(&format!(
+                Ok(output) if !output.status.success() => sess.fatal(&format!(
                     "Dlltool could not create import library: {}\n{}",
                     String::from_utf8_lossy(&output.stdout),
                     String::from_utf8_lossy(&output.stderr)
@@ -220,13 +222,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
                     output_path_z.as_ptr(),
                     ffi_exports.as_ptr(),
                     ffi_exports.len(),
-                    llvm_machine_type(&self.sess.target.arch) as u16,
-                    !self.sess.target.is_like_msvc,
+                    llvm_machine_type(&sess.target.arch) as u16,
+                    !sess.target.is_like_msvc,
                 )
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                self.sess.fatal(&format!(
+                sess.fatal(&format!(
                     "Error creating import library for {}: {}",
                     lib_name,
                     llvm::last_error().unwrap_or("unknown LLVM error".to_string())
@@ -234,13 +236,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
             }
         };
 
-        self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
-            self.sess.fatal(&format!(
-                "failed to add native library {}: {}",
-                output_path.display(),
-                e
-            ));
-        });
+        output_path
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 1cb8d34238129..53550b049db09 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -51,10 +51,37 @@ pub trait ArchiveBuilder<'a> {
 
     fn build(self) -> bool;
 
+    fn sess(&self) -> &Session;
+
+    /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
+    /// and returns the path on disk to that import library.
+    /// This functions doesn't take `self` so that it can be called from
+    /// `linker_with_args`, which is specialized on `ArchiveBuilder` but
+    /// doesn't take or create an instance of that type.
+    fn create_dll_import_lib(
+        sess: &Session,
+        lib_name: &str,
+        dll_imports: &[DllImport],
+        tmpdir: &Path,
+    ) -> PathBuf;
+
+    /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>
+    /// and adds it to the current compilation's set of archives.
     fn inject_dll_import_lib(
         &mut self,
         lib_name: &str,
         dll_imports: &[DllImport],
         tmpdir: &MaybeTempDir,
-    );
+    ) {
+        let output_path =
+            Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref());
+
+        self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+            self.sess().fatal(&format!(
+                "failed to add native library {}: {}",
+                output_path.display(),
+                e
+            ));
+        });
+    }
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 878a670cba3ef..a8513a426c6cd 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -120,7 +120,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
                         &out_filename,
                         codegen_results,
                         path.as_ref(),
-                    );
+                    )?;
                 }
             }
             if sess.opts.json_artifact_notifications {
@@ -650,7 +650,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-) {
+) -> Result<(), ErrorGuaranteed> {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker_path, flavor) = linker_and_flavor(sess);
     let mut cmd = linker_with_args::<B>(
@@ -661,7 +661,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         tmpdir,
         out_filename,
         codegen_results,
-    );
+    )?;
 
     linker::disable_localization(&mut cmd);
 
@@ -1000,6 +1000,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             (Strip::None, _) => {}
         }
     }
+
+    Ok(())
 }
 
 // Temporarily support both -Z strip and -C strip
@@ -1848,7 +1850,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     tmpdir: &Path,
     out_filename: &Path,
     codegen_results: &CodegenResults,
-) -> Command {
+) -> Result<Command, ErrorGuaranteed> {
     let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
     let cmd = &mut *super::linker::get_linker(
         sess,
@@ -1955,6 +1957,18 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         add_upstream_native_libraries(cmd, sess, codegen_results);
     }
 
+    // Link with the import library generated for any raw-dylib functions.
+    for (raw_dylib_name, raw_dylib_imports) in
+        collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
+    {
+        cmd.add_object(&B::create_dll_import_lib(
+            sess,
+            &raw_dylib_name,
+            &raw_dylib_imports,
+            tmpdir,
+        ));
+    }
+
     // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
     // command line shorter, reset it to default here before adding more libraries.
     cmd.reset_per_library_state();
@@ -1998,7 +2012,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // to it and remove the option.
     add_post_link_args(cmd, sess, flavor);
 
-    cmd.take_cmd()
+    Ok(cmd.take_cmd())
 }
 
 fn add_order_independent_options(
@@ -2222,8 +2236,7 @@ fn add_local_native_libraries(
                 }
             }
             NativeLibKind::RawDylib => {
-                // FIXME(#58713): Proper handling for raw dylibs.
-                bug!("raw_dylib feature not yet implemented");
+                // Ignore RawDylib here, they are handled separately in linker_with_args().
             }
         }
     }
diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk
index a14f6e3ab95a5..33bf95ac1657e 100644
--- a/src/test/run-make-fulldeps/tools.mk
+++ b/src/test/run-make-fulldeps/tools.mk
@@ -90,7 +90,7 @@ NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
 OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
 	-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
 else
-COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ = $(CC) -v -c -o $(1) $(2)
 COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
 NATIVE_STATICLIB_FILE = lib$(1).a
 NATIVE_STATICLIB = $(call STATICLIB,$(1))
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
index 4af8b43ea848d..1badde541128d 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
@@ -6,14 +6,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
 ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
 else
 	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
 endif
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
 ifdef RUSTC_BLESS_TEST
diff --git a/src/test/run-make/raw-dylib-c/Makefile b/src/test/run-make/raw-dylib-c/Makefile
index 166305672e6f2..713f665078e57 100644
--- a/src/test/run-make/raw-dylib-c/Makefile
+++ b/src/test/run-make/raw-dylib-c/Makefile
@@ -5,21 +5,24 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+	$(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
 ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
-	$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+	$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
+	$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
 else
 	$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
 	$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
 endif
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+	"$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
 
 ifdef RUSTC_BLESS_TEST
 	cp "$(TMPDIR)"/output.txt output.txt
 else
 	$(DIFF) output.txt "$(TMPDIR)"/output.txt
+	$(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
 endif
diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs
index e185c4aec12b0..58f7ccb38ce4a 100644
--- a/src/test/run-make/raw-dylib-c/lib.rs
+++ b/src/test/run-make/raw-dylib-c/lib.rs
@@ -20,3 +20,7 @@ pub fn library_function() {
         extern_fn_3();
     }
 }
+
+fn main() {
+    library_function();
+}
diff --git a/src/test/run-make/raw-dylib-link-ordinal/Makefile b/src/test/run-make/raw-dylib-link-ordinal/Makefile
index 0e84a749b0578..c9baa3c1ec9ac 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/Makefile
+++ b/src/test/run-make/raw-dylib-link-ordinal/Makefile
@@ -5,14 +5,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
 ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
 else
 	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
 ifdef RUSTC_BLESS_TEST
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
index 69f62669d6291..3360a97b5ff0e 100644
--- a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
@@ -6,14 +6,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
 ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+	$(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
 else
 	$(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
 
 ifdef RUSTC_BLESS_TEST