summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_gcc/build_system/src/config.rs
blob: 64d9bd73e01a3649cc4dbfc2dac4b3c26b0854ea (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
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
use crate::utils::{get_gcc_path, get_os_name, get_rustc_host_triple};
use std::collections::HashMap;
use std::env as std_env;

pub struct ConfigInfo {
    pub target: String,
    pub target_triple: String,
    pub rustc_command: Vec<String>,
}

// Returns the beginning for the command line of rustc.
pub fn set_config(
    env: &mut HashMap<String, String>,
    test_flags: &[String],
    gcc_path: Option<&str>,
) -> Result<ConfigInfo, String> {
    env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());

    let gcc_path = match gcc_path {
        Some(path) => path.to_string(),
        None => get_gcc_path()?,
    };
    env.insert("GCC_PATH".to_string(), gcc_path.clone());

    let os_name = get_os_name()?;
    let dylib_ext = match os_name.as_str() {
        "Linux" => "so",
        "Darwin" => "dylib",
        os => return Err(format!("unsupported OS `{}`", os)),
    };
    let host_triple = get_rustc_host_triple()?;
    let mut linker = None;
    let mut target_triple = host_triple.clone();
    let mut target = target_triple.clone();

    // We skip binary name and the command.
    let mut args = std::env::args().skip(2);

    let mut set_target_triple = false;
    let mut set_target = false;
    while let Some(arg) = args.next() {
        match arg.as_str() {
            "--target-triple" => {
                if let Some(arg) = args.next() {
                    target_triple = arg;
                    set_target_triple = true;
                } else {
                    return Err(
                        "Expected a value after `--target-triple`, found nothing".to_string()
                    );
                }
            },
            "--target" => {
                if let Some(arg) = args.next() {
                    target = arg;
                    set_target = true;
                } else {
                    return Err(
                        "Expected a value after `--target`, found nothing".to_string()
                    );
                }
            },
            _ => (),
        }
    }

    if set_target_triple && !set_target {
        target = target_triple.clone();
    }

    if host_triple != target_triple {
        linker = Some(format!("-Clinker={}-gcc", target_triple));
    }
    let current_dir =
        std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
    let channel = if let Some(channel) = env.get("CHANNEL") {
        channel.as_str()
    } else {
        "debug"
    };
    let cg_backend_path = current_dir
        .join("target")
        .join(channel)
        .join(&format!("librustc_codegen_gcc.{}", dylib_ext));
    let sysroot_path = current_dir.join("build_sysroot/sysroot");
    let mut rustflags = Vec::new();
    if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
        rustflags.push(cg_rustflags.clone());
    }
    if let Some(linker) = linker {
        rustflags.push(linker.to_string());
    }
    rustflags.extend_from_slice(&[
        "-Csymbol-mangling-version=v0".to_string(),
        "-Cdebuginfo=2".to_string(),
        format!("-Zcodegen-backend={}", cg_backend_path.display()),
        "--sysroot".to_string(),
        sysroot_path.display().to_string(),
    ]);

    // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
    // TODO(antoyo): remove when we can handle ThinLTO.
    if !env.contains_key(&"FAT_LTO".to_string()) {
        rustflags.push("-Clto=off".to_string());
    }
    rustflags.extend_from_slice(test_flags);
    // FIXME(antoyo): remove once the atomic shim is gone
    if os_name == "Darwin" {
        rustflags.extend_from_slice(&[
            "-Clink-arg=-undefined".to_string(),
            "-Clink-arg=dynamic_lookup".to_string(),
        ]);
    }
    env.insert("RUSTFLAGS".to_string(), rustflags.join(" "));
    // display metadata load errors
    env.insert("RUSTC_LOG".to_string(), "warn".to_string());

    let sysroot = current_dir.join(&format!(
        "build_sysroot/sysroot/lib/rustlib/{}/lib",
        target_triple
    ));
    let ld_library_path = format!(
        "{target}:{sysroot}:{gcc_path}",
        target = current_dir.join("target/out").display(),
        sysroot = sysroot.display(),
    );
    env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
    env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path);

    // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
    // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
    // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
    let path = std::env::var("PATH").unwrap_or_default();
    env.insert("PATH".to_string(), format!("/opt/gcc/bin:{}", path));

    let mut rustc_command = vec!["rustc".to_string()];
    rustc_command.extend_from_slice(&rustflags);
    rustc_command.extend_from_slice(&[
        "-L".to_string(),
        "crate=target/out".to_string(),
        "--out-dir".to_string(),
        "target/out".to_string(),
    ]);
    Ok(ConfigInfo {
        target,
        target_triple,
        rustc_command,
    })
}