about summary refs log tree commit diff
path: root/compiler/rustc_codegen_cranelift/src/archive.rs
blob: 5eedab4f2cbaa0717c8a19d833abb36185afacc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use std::borrow::Borrow;
use std::fs;
use std::path::Path;

use ar_archive_writer::{COFFShortExport, MachineTypes};
use rustc_codegen_ssa::back::archive::{
    create_mingw_dll_import_lib, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
    DEFAULT_OBJECT_READER,
};
use rustc_codegen_ssa::common::is_mingw_gnu_toolchain;
use rustc_session::Session;

pub(crate) struct ArArchiveBuilderBuilder;

impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
    }

    fn create_dll_import_lib(
        &self,
        sess: &Session,
        lib_name: &str,
        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
        output_path: &Path,
    ) {
        if is_mingw_gnu_toolchain(&sess.target) {
            // The binutils linker used on -windows-gnu targets cannot read the import
            // libraries generated by LLVM: in our attempts, the linker produced an .EXE
            // 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.
            create_mingw_dll_import_lib(
                sess,
                lib_name,
                import_name_and_ordinal_vector,
                output_path,
            );
        } else {
            let mut file =
                match fs::OpenOptions::new().write(true).create_new(true).open(&output_path) {
                    Ok(file) => file,
                    Err(error) => {
                        sess.dcx().fatal(format!(
                            "failed to create import library file `{path}`: {error}",
                            path = output_path.display(),
                        ));
                    }
                };

            let machine = match sess.target.arch.borrow() {
                "x86" => MachineTypes::I386,
                "x86_64" => MachineTypes::AMD64,
                "arm" => MachineTypes::ARMNT,
                "aarch64" => MachineTypes::ARM64,
                _ => {
                    sess.dcx().fatal(format!(
                        "unsupported target architecture `{arch}`",
                        arch = sess.target.arch,
                    ));
                }
            };

            let exports = import_name_and_ordinal_vector
                .iter()
                .map(|(name, ordinal)| COFFShortExport {
                    name: name.to_string(),
                    ext_name: None,
                    symbol_name: None,
                    alias_target: None,
                    ordinal: ordinal.unwrap_or(0),
                    noname: ordinal.is_some(),
                    data: false,
                    private: false,
                    constant: false,
                })
                .collect::<Vec<_>>();

            if let Err(error) = ar_archive_writer::write_import_library(
                &mut file,
                lib_name,
                &exports,
                machine,
                !sess.target.is_like_msvc,
            ) {
                sess.dcx().fatal(format!(
                    "failed to create import library `{path}`: `{error}`",
                    path = output_path.display(),
                ));
            }
        }
    }
}