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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! Object files providing support for basic runtime facilities and added to the produced binaries
//! at the start and at the end of linking.
//!
//! Table of CRT objects for popular toolchains.
//! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
//! See <https://dev.gentoo.org/~vapier/crt.txt> for some more details.
//!
//! | Pre-link CRT objects | glibc                  | musl                   | bionic           | mingw             | wasi         |
//! |----------------------|------------------------|------------------------|------------------|-------------------|--------------|
//! | dynamic-nopic-exe    | crt1, crti, crtbegin   | crt1, crti, crtbegin   | crtbegin_dynamic | crt2, crtbegin    | crt1         |
//! | dynamic-pic-exe      | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1         |
//! | static-nopic-exe     | crt1, crti, crtbeginT  | crt1, crti, crtbegin   | crtbegin_static  | crt2, crtbegin    | crt1         |
//! | static-pic-exe       | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1         |
//! | dynamic-dylib        | crti, crtbeginS        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -            |
//! | static-dylib (gcc)   | crti, crtbeginT        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -            |
//! | static-dylib (clang) | crti, crtbeginT        | N/A                    | crtbegin_static  | dllcrt2, crtbegin | -            |
//! | wasi-reactor-exe     | N/A                    | N/A                    | N/A              | N/A               | crt1-reactor |
//!
//! | Post-link CRT objects | glibc         | musl          | bionic         | mingw  | wasi |
//! |-----------------------|---------------|---------------|----------------|--------|------|
//! | dynamic-nopic-exe     | crtend, crtn  | crtend, crtn  | crtend_android | crtend | -    |
//! | dynamic-pic-exe       | crtendS, crtn | crtendS, crtn | crtend_android | crtend | -    |
//! | static-nopic-exe      | crtend, crtn  | crtend, crtn  | crtend_android | crtend | -    |
//! | static-pic-exe        | crtendS, crtn | crtendS, crtn | crtend_android | crtend | -    |
//! | dynamic-dylib         | crtendS, crtn | crtendS, crtn | crtend_so      | crtend | -    |
//! | static-dylib (gcc)    | crtend, crtn  | crtendS, crtn | crtend_so      | crtend | -    |
//! | static-dylib (clang)  | crtendS, crtn | N/A           | crtend_so      | crtend | -    |
//!
//! Use cases for rustc linking the CRT objects explicitly:
//!     - rustc needs to add its own Rust-specific objects (mingw is the example)
//!     - gcc wrapper cannot be used for some reason and linker like ld or lld is used directly.
//!     - gcc wrapper pulls wrong CRT objects (e.g. from glibc when we are targeting musl).
//!
//! In general it is preferable to rely on the target's native toolchain to pull the objects.
//! However, for some targets (musl, mingw) rustc historically provides a more self-contained
//! installation not requiring users to install the native target's toolchain.
//! In that case rustc distributes the objects as a part of the target's Rust toolchain
//! and falls back to linking with them manually.
//! Unlike native toolchains, rustc only currently adds the libc's objects during linking,
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
//! when linking in self-contained mode.

use crate::json::{Json, ToJson};
use crate::spec::LinkOutputKind;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::str::FromStr;

pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<Cow<'static, str>>>;

pub(super) fn new(obj_table: &[(LinkOutputKind, &[&'static str])]) -> CrtObjects {
    obj_table.iter().map(|(z, k)| (*z, k.iter().map(|b| (*b).into()).collect())).collect()
}

pub(super) fn all(obj: &'static str) -> CrtObjects {
    new(&[
        (LinkOutputKind::DynamicNoPicExe, &[obj]),
        (LinkOutputKind::DynamicPicExe, &[obj]),
        (LinkOutputKind::StaticNoPicExe, &[obj]),
        (LinkOutputKind::StaticPicExe, &[obj]),
        (LinkOutputKind::DynamicDylib, &[obj]),
        (LinkOutputKind::StaticDylib, &[obj]),
    ])
}

pub(super) fn pre_musl_self_contained() -> CrtObjects {
    new(&[
        (LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]),
        (LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]),
        (LinkOutputKind::StaticNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]),
        (LinkOutputKind::StaticPicExe, &["rcrt1.o", "crti.o", "crtbeginS.o"]),
        (LinkOutputKind::DynamicDylib, &["crti.o", "crtbeginS.o"]),
        (LinkOutputKind::StaticDylib, &["crti.o", "crtbeginS.o"]),
    ])
}

pub(super) fn post_musl_self_contained() -> CrtObjects {
    new(&[
        (LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]),
        (LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]),
        (LinkOutputKind::StaticNoPicExe, &["crtend.o", "crtn.o"]),
        (LinkOutputKind::StaticPicExe, &["crtendS.o", "crtn.o"]),
        (LinkOutputKind::DynamicDylib, &["crtendS.o", "crtn.o"]),
        (LinkOutputKind::StaticDylib, &["crtendS.o", "crtn.o"]),
    ])
}

pub(super) fn pre_mingw_self_contained() -> CrtObjects {
    new(&[
        (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
        (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
        (LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]),
        (LinkOutputKind::StaticPicExe, &["crt2.o", "rsbegin.o"]),
        (LinkOutputKind::DynamicDylib, &["dllcrt2.o", "rsbegin.o"]),
        (LinkOutputKind::StaticDylib, &["dllcrt2.o", "rsbegin.o"]),
    ])
}

pub(super) fn post_mingw_self_contained() -> CrtObjects {
    all("rsend.o")
}

pub(super) fn pre_mingw() -> CrtObjects {
    all("rsbegin.o")
}

pub(super) fn post_mingw() -> CrtObjects {
    all("rsend.o")
}

pub(super) fn pre_wasi_self_contained() -> CrtObjects {
    // Use crt1-command.o instead of crt1.o to enable support for new-style
    // commands. See https://reviews.llvm.org/D81689 for more info.
    new(&[
        (LinkOutputKind::DynamicNoPicExe, &["crt1-command.o"]),
        (LinkOutputKind::DynamicPicExe, &["crt1-command.o"]),
        (LinkOutputKind::StaticNoPicExe, &["crt1-command.o"]),
        (LinkOutputKind::StaticPicExe, &["crt1-command.o"]),
        (LinkOutputKind::WasiReactorExe, &["crt1-reactor.o"]),
    ])
}

pub(super) fn post_wasi_self_contained() -> CrtObjects {
    new(&[])
}

/// Which logic to use to determine whether to use self-contained linking mode
/// if `-Clink-self-contained` is not specified explicitly.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum LinkSelfContainedDefault {
    False,
    True,
    Musl,
    Mingw,
}

impl FromStr for LinkSelfContainedDefault {
    type Err = ();

    fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> {
        Ok(match s {
            "false" => LinkSelfContainedDefault::False,
            "true" | "wasm" => LinkSelfContainedDefault::True,
            "musl" => LinkSelfContainedDefault::Musl,
            "mingw" => LinkSelfContainedDefault::Mingw,
            _ => return Err(()),
        })
    }
}

impl ToJson for LinkSelfContainedDefault {
    fn to_json(&self) -> Json {
        match *self {
            LinkSelfContainedDefault::False => "false",
            LinkSelfContainedDefault::True => "true",
            LinkSelfContainedDefault::Musl => "musl",
            LinkSelfContainedDefault::Mingw => "mingw",
        }
        .to_json()
    }
}