bootstrap/core/config/toml/
target.rs

1//! This module defines the structures and logic for handling target-specific configuration
2//! within the `bootstrap.toml` file. This allows you to customize build settings, tools,
3//! and flags for individual compilation targets.
4//!
5//! It includes:
6//!
7//! * [`TomlTarget`]: This struct directly mirrors the `[target.<triple>]` sections in your
8//!   `bootstrap.toml`. It's used for deserializing raw TOML data for a specific target.
9//! * [`Target`]: This struct represents the processed and validated configuration for a
10//!   build target, which is is stored in the main [`Config`] structure.
11//! * [`Config::apply_target_config`]: This method processes the `TomlTarget` data and
12//!   applies it to the global [`Config`], ensuring proper path resolution, validation,
13//!   and integration with other build settings.
14
15use std::collections::HashMap;
16
17use serde::{Deserialize, Deserializer};
18
19use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
20use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool};
21use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit};
22
23define_config! {
24    /// TOML representation of how each build target is configured.
25    struct TomlTarget {
26        cc: Option<String> = "cc",
27        cxx: Option<String> = "cxx",
28        ar: Option<String> = "ar",
29        ranlib: Option<String> = "ranlib",
30        default_linker: Option<PathBuf> = "default-linker",
31        linker: Option<String> = "linker",
32        split_debuginfo: Option<String> = "split-debuginfo",
33        llvm_config: Option<String> = "llvm-config",
34        llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
35        llvm_filecheck: Option<String> = "llvm-filecheck",
36        llvm_libunwind: Option<String> = "llvm-libunwind",
37        sanitizers: Option<bool> = "sanitizers",
38        profiler: Option<StringOrBool> = "profiler",
39        rpath: Option<bool> = "rpath",
40        crt_static: Option<bool> = "crt-static",
41        musl_root: Option<String> = "musl-root",
42        musl_libdir: Option<String> = "musl-libdir",
43        wasi_root: Option<String> = "wasi-root",
44        qemu_rootfs: Option<String> = "qemu-rootfs",
45        no_std: Option<bool> = "no-std",
46        codegen_backends: Option<Vec<String>> = "codegen-backends",
47        runner: Option<String> = "runner",
48        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
49        jemalloc: Option<bool> = "jemalloc",
50    }
51}
52
53/// Per-target configuration stored in the global configuration structure.
54#[derive(Debug, Default, Clone, PartialEq, Eq)]
55pub struct Target {
56    /// Some(path to llvm-config) if using an external LLVM.
57    pub llvm_config: Option<PathBuf>,
58    pub llvm_has_rust_patches: Option<bool>,
59    /// Some(path to FileCheck) if one was specified.
60    pub llvm_filecheck: Option<PathBuf>,
61    pub llvm_libunwind: Option<LlvmLibunwind>,
62    pub cc: Option<PathBuf>,
63    pub cxx: Option<PathBuf>,
64    pub ar: Option<PathBuf>,
65    pub ranlib: Option<PathBuf>,
66    pub default_linker: Option<PathBuf>,
67    pub linker: Option<PathBuf>,
68    pub split_debuginfo: Option<SplitDebuginfo>,
69    pub sanitizers: Option<bool>,
70    pub profiler: Option<StringOrBool>,
71    pub rpath: Option<bool>,
72    pub crt_static: Option<bool>,
73    pub musl_root: Option<PathBuf>,
74    pub musl_libdir: Option<PathBuf>,
75    pub wasi_root: Option<PathBuf>,
76    pub qemu_rootfs: Option<PathBuf>,
77    pub runner: Option<String>,
78    pub no_std: bool,
79    pub codegen_backends: Option<Vec<String>>,
80    pub optimized_compiler_builtins: Option<bool>,
81    pub jemalloc: Option<bool>,
82}
83
84impl Target {
85    pub fn from_triple(triple: &str) -> Self {
86        let mut target: Self = Default::default();
87        if !build_helper::targets::target_supports_std(triple) {
88            target.no_std = true;
89        }
90        if triple.contains("emscripten") {
91            target.runner = Some("node".into());
92        }
93        target
94    }
95}
96
97impl Config {
98    pub fn apply_target_config(&mut self, toml_target: Option<HashMap<String, TomlTarget>>) {
99        if let Some(t) = toml_target {
100            for (triple, cfg) in t {
101                let mut target = Target::from_triple(&triple);
102
103                if let Some(ref s) = cfg.llvm_config {
104                    if self.download_rustc_commit.is_some() && triple == *self.host_target.triple {
105                        panic!(
106                            "setting llvm_config for the host is incompatible with download-rustc"
107                        );
108                    }
109                    target.llvm_config = Some(self.src.join(s));
110                }
111                if let Some(patches) = cfg.llvm_has_rust_patches {
112                    assert!(
113                        self.submodules == Some(false) || cfg.llvm_config.is_some(),
114                        "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided"
115                    );
116                    target.llvm_has_rust_patches = Some(patches);
117                }
118                if let Some(ref s) = cfg.llvm_filecheck {
119                    target.llvm_filecheck = Some(self.src.join(s));
120                }
121                target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| {
122                    v.parse().unwrap_or_else(|_| {
123                        panic!("failed to parse target.{triple}.llvm-libunwind")
124                    })
125                });
126                if let Some(s) = cfg.no_std {
127                    target.no_std = s;
128                }
129                target.cc = cfg.cc.map(PathBuf::from);
130                target.cxx = cfg.cxx.map(PathBuf::from);
131                target.ar = cfg.ar.map(PathBuf::from);
132                target.ranlib = cfg.ranlib.map(PathBuf::from);
133                target.linker = cfg.linker.map(PathBuf::from);
134                target.crt_static = cfg.crt_static;
135                target.musl_root = cfg.musl_root.map(PathBuf::from);
136                target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
137                target.wasi_root = cfg.wasi_root.map(PathBuf::from);
138                target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
139                target.runner = cfg.runner;
140                target.sanitizers = cfg.sanitizers;
141                target.profiler = cfg.profiler;
142                target.rpath = cfg.rpath;
143                target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
144                target.jemalloc = cfg.jemalloc;
145
146                if let Some(ref backends) = cfg.codegen_backends {
147                    let available_backends = ["llvm", "cranelift", "gcc"];
148
149                    target.codegen_backends = Some(backends.iter().map(|s| {
150                        if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
151                            if available_backends.contains(&backend) {
152                                panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
153                            } else {
154                                println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
155                                    Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
156                                    In this case, it would be referred to as '{backend}'.");
157                            }
158                        }
159
160                        s.clone()
161                    }).collect());
162                }
163
164                target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| {
165                    v.parse().unwrap_or_else(|_| {
166                        panic!("invalid value for target.{triple}.split-debuginfo")
167                    })
168                });
169
170                self.target_config.insert(TargetSelection::from_user(&triple), target);
171            }
172        }
173    }
174}