dinghy_lib/platform/
regular_platform.rs

1use crate::config::PlatformConfiguration;
2use crate::overlay::Overlayer;
3use crate::platform;
4use crate::project::Project;
5use crate::toolchain::ToolchainConfig;
6use crate::Build;
7use crate::Device;
8use crate::Platform;
9use crate::Result;
10use crate::SetupArgs;
11use dinghy_build::build_env::set_all_env;
12use std::fmt::{Debug, Display, Formatter};
13use std::path::Path;
14use std::path::PathBuf;
15use std::process::Command;
16
17use anyhow::anyhow;
18use fs_err::read_dir;
19use log::trace;
20
21pub struct RegularPlatform {
22    pub configuration: PlatformConfiguration,
23    pub id: String,
24    pub toolchain: ToolchainConfig,
25}
26
27impl Debug for RegularPlatform {
28    fn fmt(&self, fmt: &mut Formatter) -> ::std::fmt::Result {
29        write!(fmt, "{}", self.id)
30    }
31}
32
33impl RegularPlatform {
34    pub fn new<P: AsRef<Path>>(
35        configuration: PlatformConfiguration,
36        id: String,
37        rustc_triple: String,
38        toolchain_path: P,
39    ) -> Result<Box<dyn Platform>> {
40        if let Some(prefix) = configuration.deb_multiarch.clone() {
41            return Ok(Box::new(RegularPlatform {
42                configuration,
43                id,
44                toolchain: ToolchainConfig {
45                    bin_dir: "/usr/bin".into(),
46                    rustc_triple,
47                    root: "/".into(),
48                    sysroot: Some("/".into()),
49                    cc: "gcc".to_string(),
50                    cxx: "c++".to_string(),
51                    binutils_prefix: prefix.clone(),
52                    cc_prefix: prefix.clone(),
53                },
54            }));
55        }
56        let toolchain_path = toolchain_path.as_ref();
57        let toolchain_bin_path = toolchain_path.join("bin");
58
59        let mut bin: Option<PathBuf> = None;
60        let mut prefix: Option<String> = None;
61        for file in read_dir(&toolchain_bin_path)? {
62            let file = file?;
63            if file.file_name().to_string_lossy().ends_with("-gcc")
64                || file.file_name().to_string_lossy().ends_with("-gcc.exe")
65            {
66                bin = Some(toolchain_bin_path);
67                prefix = Some(
68                    file.file_name()
69                        .to_string_lossy()
70                        .replace(".exe", "")
71                        .replace("-gcc", ""),
72                );
73                break;
74            }
75        }
76        let bin_dir = bin.ok_or_else(|| anyhow!("no bin/*-gcc found in toolchain"))?;
77        let tc_triple = prefix
78            .ok_or_else(|| anyhow!("no gcc in toolchain"))?
79            .to_string();
80        let sysroot = find_sysroot(&toolchain_path)?;
81
82        let toolchain = ToolchainConfig {
83            bin_dir,
84            rustc_triple,
85            root: toolchain_path.into(),
86            sysroot,
87            cc: "gcc".to_string(),
88            cxx: "c++".to_string(),
89            binutils_prefix: tc_triple.clone(),
90            cc_prefix: tc_triple,
91        };
92        Self::new_with_tc(configuration, id, toolchain)
93    }
94
95    pub fn new_with_tc(
96        configuration: PlatformConfiguration,
97        id: String,
98        toolchain: ToolchainConfig,
99    ) -> Result<Box<dyn Platform>> {
100        Ok(Box::new(RegularPlatform {
101            configuration,
102            id,
103            toolchain,
104        }))
105    }
106}
107
108impl Display for RegularPlatform {
109    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
110        write!(f, "{:?}", self.toolchain.root)
111    }
112}
113
114impl Platform for RegularPlatform {
115    fn setup_env(&self, project: &Project, setup_args: &SetupArgs) -> Result<()> {
116        // Cleanup environment
117        set_all_env(&[("LIBRARY_PATH", ""), ("LD_LIBRARY_PATH", "")]);
118        // Set custom env variables specific to the platform
119        set_all_env(&self.configuration.env());
120
121        if let Some(sr) = &self.toolchain.sysroot {
122            Overlayer::overlay(&self.configuration, self, project, &sr)?;
123        }
124
125        self.toolchain
126            .setup_cc(&self.id, &self.toolchain.cc_executable(&self.toolchain.cc))?;
127
128        if Path::new(&self.toolchain.binutils_executable("ar")).exists() {
129            self.toolchain
130                .setup_tool("AR", &self.toolchain.binutils_executable("ar"))?;
131        }
132        if Path::new(&self.toolchain.binutils_executable("as")).exists() {
133            self.toolchain
134                .setup_tool("AS", &self.toolchain.binutils_executable("as"))?;
135        }
136        if Path::new(&self.toolchain.cc_executable(&self.toolchain.cxx)).exists() {
137            self.toolchain
138                .setup_tool("CXX", &self.toolchain.cc_executable(&self.toolchain.cxx))?;
139        }
140        if Path::new(&self.toolchain.cc_executable("cpp")).exists() {
141            self.toolchain
142                .setup_tool("CPP", &self.toolchain.cc_executable("cpp"))?;
143        }
144        if Path::new(&self.toolchain.binutils_executable("gfortran")).exists() {
145            self.toolchain
146                .setup_tool("FC", &self.toolchain.binutils_executable("gfortran"))?;
147        }
148        trace!("Setup linker...");
149        self.toolchain.setup_linker(
150            &self.id,
151            &self.toolchain.generate_linker_command(&setup_args),
152            &project.metadata.workspace_root,
153        )?;
154
155        trace!("Setup pkg-config");
156        self.toolchain.setup_pkg_config()?;
157        trace!("Setup sysroot...");
158        self.toolchain.setup_sysroot();
159        trace!("Setup shims...");
160        self.toolchain
161            .shim_executables(&self.id, &project.metadata.workspace_root)?;
162        trace!("Setup runner...");
163        self.toolchain.setup_runner(&self.id, setup_args)?;
164        trace!("Setup target...");
165        self.toolchain.setup_target()?;
166        Ok(())
167    }
168
169    fn id(&self) -> String {
170        self.id.clone()
171    }
172
173    fn is_compatible_with(&self, device: &dyn Device) -> bool {
174        device.is_compatible_with_regular_platform(self)
175    }
176
177    fn is_host(&self) -> bool {
178        false
179    }
180
181    fn rustc_triple(&self) -> &str {
182        &self.toolchain.rustc_triple
183    }
184
185    fn strip(&self, build: &mut Build) -> Result<()> {
186        build.runnable = platform::strip_runnable(
187            &build.runnable,
188            Command::new(self.toolchain.binutils_executable("strip")),
189        )?;
190
191        Ok(())
192    }
193
194    fn sysroot(&self) -> Result<Option<std::path::PathBuf>> {
195        Ok(self.toolchain.sysroot.clone())
196    }
197}
198
199fn find_sysroot<P: AsRef<Path>>(toolchain_path: P) -> Result<Option<PathBuf>> {
200    let toolchain = toolchain_path.as_ref();
201    let immediate = toolchain.join("sysroot");
202    if immediate.is_dir() {
203        let sysroot = immediate
204            .to_str()
205            .ok_or_else(|| anyhow!("sysroot is not utf-8"))?;
206        return Ok(Some(sysroot.into()));
207    }
208    for subdir in toolchain.read_dir()? {
209        let subdir = subdir?;
210        let maybe = subdir.path().join("sysroot");
211        if maybe.is_dir() {
212            let sysroot = maybe
213                .to_str()
214                .ok_or_else(|| anyhow!("sysroot is not utf-8"))?;
215            return Ok(Some(sysroot.into()));
216        }
217    }
218    Ok(None)
219}