|
1 | 1 | //! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it.
|
2 | 2 |
|
| 3 | +use crate::legacy_target_specs::write_legacy_target_specs; |
3 | 4 | use crate::spirv_source::{
|
4 | 5 | get_channel_from_rustc_codegen_spirv_build_script, query_metadata, FindPackage as _,
|
5 | 6 | };
|
6 |
| -use crate::{cache_dir, spirv_source::SpirvSource, target_spec_dir}; |
| 7 | +use crate::{cache_dir, spirv_source::SpirvSource}; |
7 | 8 | use anyhow::Context as _;
|
8 |
| -use log::trace; |
9 |
| -use spirv_builder::{SpirvBuilder, TARGET_SPECS}; |
10 |
| -use std::io::Write as _; |
| 9 | +use cargo_metadata::Metadata; |
| 10 | +use log::{info, trace}; |
| 11 | +use spirv_builder::SpirvBuilder; |
11 | 12 | use std::path::{Path, PathBuf};
|
12 | 13 |
|
13 | 14 | /// Args for an install
|
@@ -83,14 +84,16 @@ pub struct InstalledBackend {
|
83 | 84 | pub rustc_codegen_spirv_location: PathBuf,
|
84 | 85 | /// toolchain channel name
|
85 | 86 | pub toolchain_channel: String,
|
| 87 | + /// directory with target-specs json files |
| 88 | + pub target_spec_dir: PathBuf, |
86 | 89 | }
|
87 | 90 |
|
88 | 91 | impl InstalledBackend {
|
89 | 92 | /// Configures the supplied [`SpirvBuilder`]. `SpirvBuilder.target` must be set and must not change after calling this function.
|
90 | 93 | pub fn configure_spirv_builder(&self, builder: &mut SpirvBuilder) -> anyhow::Result<()> {
|
91 | 94 | builder.rustc_codegen_spirv_location = Some(self.rustc_codegen_spirv_location.clone());
|
92 | 95 | builder.toolchain_overwrite = Some(self.toolchain_channel.clone());
|
93 |
| - builder.path_to_target_spec = Some(target_spec_dir()?.join(format!( |
| 96 | + builder.path_to_target_spec = Some(self.target_spec_dir.join(format!( |
94 | 97 | "{}.json",
|
95 | 98 | builder.target.as_ref().context("expect target to be set")?
|
96 | 99 | )));
|
@@ -169,22 +172,72 @@ package = "rustc_codegen_spirv"
|
169 | 172 | Ok(())
|
170 | 173 | }
|
171 | 174 |
|
172 |
| - /// Add the target spec files to the crate. |
173 |
| - fn write_target_spec_files(&self) -> anyhow::Result<()> { |
174 |
| - for (filename, contents) in TARGET_SPECS { |
175 |
| - let path = target_spec_dir() |
176 |
| - .context("creating target spec dir")? |
177 |
| - .join(filename); |
178 |
| - if !path.is_file() || self.rebuild_codegen { |
179 |
| - let mut file = std::fs::File::create(&path) |
180 |
| - .with_context(|| format!("creating file at [{}]", path.display()))?; |
181 |
| - file.write_all(contents.as_bytes()) |
182 |
| - .context("writing to file")?; |
| 175 | + /// Copy spec files from one dir to another, assuming no subdirectories |
| 176 | + fn copy_spec_files(src: &Path, dst: &Path) -> anyhow::Result<()> { |
| 177 | + info!( |
| 178 | + "Copy target specs from {:?} to {:?}", |
| 179 | + src.display(), |
| 180 | + dst.display() |
| 181 | + ); |
| 182 | + std::fs::create_dir_all(dst)?; |
| 183 | + let dir = std::fs::read_dir(src)?; |
| 184 | + for dir_entry in dir { |
| 185 | + let file = dir_entry?; |
| 186 | + let file_path = file.path(); |
| 187 | + if file_path.is_file() { |
| 188 | + std::fs::copy(file_path, dst.join(file.file_name()))?; |
183 | 189 | }
|
184 | 190 | }
|
185 | 191 | Ok(())
|
186 | 192 | }
|
187 | 193 |
|
| 194 | + /// Add the target spec files to the crate. |
| 195 | + fn update_spec_files( |
| 196 | + &self, |
| 197 | + source: &SpirvSource, |
| 198 | + install_dir: &Path, |
| 199 | + dummy_metadata: &Metadata, |
| 200 | + skip_rebuild: bool, |
| 201 | + ) -> anyhow::Result<PathBuf> { |
| 202 | + let mut target_specs_dst = install_dir.join("target-specs"); |
| 203 | + if !skip_rebuild { |
| 204 | + if let Ok(target_specs) = |
| 205 | + dummy_metadata.find_package("rustc_codegen_spirv_target_specs") |
| 206 | + { |
| 207 | + let target_specs_src = target_specs |
| 208 | + .manifest_path |
| 209 | + .as_std_path() |
| 210 | + .parent() |
| 211 | + .and_then(|p| { |
| 212 | + let src = p.join("target-specs"); |
| 213 | + src.is_dir().then_some(src) |
| 214 | + }) |
| 215 | + .context("Could not find `target-specs` directory within `rustc_codegen_spirv_target_specs` dependency")?; |
| 216 | + if source.is_path() { |
| 217 | + // skip copy |
| 218 | + target_specs_dst = target_specs_src; |
| 219 | + } else { |
| 220 | + // copy over the target-specs |
| 221 | + Self::copy_spec_files(&target_specs_src, &target_specs_dst) |
| 222 | + .context("copying target-specs json files")?; |
| 223 | + } |
| 224 | + } else { |
| 225 | + // use legacy target specs bundled with cargo gpu |
| 226 | + if source.is_path() { |
| 227 | + // This is a stupid situation: |
| 228 | + // * We can't be certain that there are `target-specs` in the local checkout (there may be some in `spirv-builder`) |
| 229 | + // * We can't dump our legacy ones into the `install_dir`, as that would modify the local rust-gpu checkout |
| 230 | + // -> do what the old cargo gpu did, one global dir for all target specs |
| 231 | + // and hope parallel runs don't shred each other |
| 232 | + target_specs_dst = cache_dir()?.join("legacy-target-specs-for-local-checkout"); |
| 233 | + } |
| 234 | + write_legacy_target_specs(&target_specs_dst, self.rebuild_codegen)?; |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + Ok(target_specs_dst) |
| 239 | + } |
| 240 | + |
188 | 241 | /// Install the binary pair and return the `(dylib_path, toolchain_channel)`.
|
189 | 242 | #[expect(clippy::too_many_lines, reason = "it's fine")]
|
190 | 243 | pub fn run(&self) -> anyhow::Result<InstalledBackend> {
|
@@ -245,6 +298,11 @@ package = "rustc_codegen_spirv"
|
245 | 298 | )?;
|
246 | 299 | log::info!("selected toolchain channel `{toolchain_channel:?}`");
|
247 | 300 |
|
| 301 | + log::debug!("update_spec_files"); |
| 302 | + let target_spec_dir = self |
| 303 | + .update_spec_files(&source, &install_dir, &dummy_metadata, skip_rebuild) |
| 304 | + .context("writing target spec files")?; |
| 305 | + |
248 | 306 | if !skip_rebuild {
|
249 | 307 | log::debug!("ensure_toolchain_and_components_exist");
|
250 | 308 | crate::install_toolchain::ensure_toolchain_and_components_exist(
|
@@ -304,15 +362,12 @@ package = "rustc_codegen_spirv"
|
304 | 362 | log::error!("could not find {}", dylib_path.display());
|
305 | 363 | anyhow::bail!("`rustc_codegen_spirv` build failed");
|
306 | 364 | }
|
307 |
| - |
308 |
| - log::debug!("write_target_spec_files"); |
309 |
| - self.write_target_spec_files() |
310 |
| - .context("writing target spec files")?; |
311 | 365 | }
|
312 | 366 |
|
313 | 367 | Ok(InstalledBackend {
|
314 | 368 | rustc_codegen_spirv_location: dest_dylib_path,
|
315 | 369 | toolchain_channel,
|
| 370 | + target_spec_dir, |
316 | 371 | })
|
317 | 372 | }
|
318 | 373 | }
|
0 commit comments