dinghy_lib/platform/
regular_platform.rs1use 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 set_all_env(&[("LIBRARY_PATH", ""), ("LD_LIBRARY_PATH", "")]);
118 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}