Skip to content

Commit af8fdc7

Browse files
committed
target-spec: add Target type
1 parent 60eddf8 commit af8fdc7

File tree

7 files changed

+93
-43
lines changed

7 files changed

+93
-43
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rustc_codegen_spirv-types/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ rspirv = "0.12"
1313
serde = { version = "1.0", features = ["derive"] }
1414
serde_json = "1.0"
1515
semver = { version = "1.0.24", features = ["serde"] }
16+
thiserror = "2.0.12"

crates/rustc_codegen_spirv-types/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ pub use rspirv::spirv::Capability;
44

55
mod compile_result;
66
mod rustc_version;
7+
mod target;
78
mod target_spec;
89
pub use compile_result::*;
910
pub use rustc_version::*;
11+
pub use target::*;
1012
pub use target_spec::*;
1113

1214
// HACK(eddyb) allows downstream crates to access the correct version directly.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use std::fmt::{Debug, Formatter};
2+
use thiserror::Error;
3+
4+
pub const SPIRV_TARGET_PREFIX: &str = "spirv-unknown-";
5+
6+
/// A well-known rust-gpu target.
7+
///
8+
/// Even if [`Self::new`] accepted the target, it can still fail to compile if the specific rust-gpu compiler in use
9+
/// offers no support for it.
10+
///
11+
/// While the current implementation is just a validated string, that may change in the future.
12+
#[derive(Clone)]
13+
pub struct Target {
14+
target: String,
15+
}
16+
17+
impl Target {
18+
pub fn from_target(target: &str) -> Result<Self, TargetError> {
19+
let target_env = target.strip_prefix(SPIRV_TARGET_PREFIX).ok_or_else(|| {
20+
TargetError::NonSpirvTarget {
21+
target: target.to_string(),
22+
}
23+
})?;
24+
25+
// used only to split the full list into groups.
26+
#[allow(clippy::match_same_arms)]
27+
match target_env {
28+
// HACK(firestar99) this hardcoded list should be replaced with patterns (eg. `vulkan{}.{}`),
29+
// which would allow us to support new target versions without updating this list.
30+
"spv1.0" | "spv1.1" | "spv1.2" | "spv1.3" | "spv1.4" | "spv1.5" | "spv1.6" => {}
31+
"opengl4.0" | "opengl4.1" | "opengl4.2" | "opengl4.3" | "opengl4.5" => {}
32+
"vulkan1.0" | "vulkan1.1" | "vulkan1.1spv1.4" | "vulkan1.2" | "vulkan1.3"
33+
| "vulkan1.4" => {}
34+
35+
_ => {
36+
return Err(TargetError::UnsupportedSpirvTargetEnv {
37+
target_env: target_env.into(),
38+
});
39+
}
40+
}
41+
42+
Ok(Self {
43+
target: target.to_string(),
44+
})
45+
}
46+
47+
pub fn from_env(target_env: &str) -> Result<Self, TargetError> {
48+
Self::from_target(&format!("{SPIRV_TARGET_PREFIX}{target_env}"))
49+
}
50+
51+
pub fn target(&self) -> &str {
52+
&self.target
53+
}
54+
55+
pub fn target_env(&self) -> &str {
56+
&self.target[SPIRV_TARGET_PREFIX.len()..]
57+
}
58+
}
59+
60+
impl Debug for Target {
61+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62+
f.debug_tuple("Target").field(&self.target).finish()
63+
}
64+
}
65+
66+
#[derive(Debug, Error)]
67+
#[non_exhaustive]
68+
pub enum TargetError {
69+
#[error("SPIR-V target must start with `{SPIRV_TARGET_PREFIX}...`, was `{target}`")]
70+
NonSpirvTarget { target: String },
71+
#[error("SPIR-V target `{SPIRV_TARGET_PREFIX}-{target_env}` is not supported")]
72+
UnsupportedSpirvTargetEnv { target_env: String },
73+
}

crates/rustc_codegen_spirv-types/src/target_spec.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::Target;
12
use semver::Version;
23
use std::ffi::OsString;
34
use std::path::Path;
@@ -19,16 +20,16 @@ impl TargetSpecVersion {
1920
/// the absolute path to it, on older rustc versions may return the target name.
2021
pub fn target_arg(
2122
rustc_version: Version,
22-
target_env: &str,
23+
target: &Target,
2324
target_spec_folder: &Path,
2425
) -> std::io::Result<OsString> {
2526
if let Some(target_spec) = Self::from_rustc_version(rustc_version) {
2627
std::fs::create_dir_all(&target_spec_folder)?;
27-
let spec_file = target_spec_folder.join(format!("spirv-unknown-{target_env}.json"));
28-
std::fs::write(&spec_file, target_spec.format_spec(target_env))?;
28+
let spec_file = target_spec_folder.join(format!("{}.json", target.target()));
29+
std::fs::write(&spec_file, target_spec.format_spec(target))?;
2930
Ok(std::fs::canonicalize(spec_file)?.into_os_string())
3031
} else {
31-
Ok(OsString::from(target_env))
32+
Ok(OsString::from(target.target()))
3233
}
3334
}
3435

@@ -43,7 +44,8 @@ impl TargetSpecVersion {
4344
}
4445

4546
/// format the target spec json
46-
pub fn format_spec(&self, target_env: &str) -> String {
47+
pub fn format_spec(&self, target: &Target) -> String {
48+
let target_env = target.target_env();
4749
match self {
4850
TargetSpecVersion::Rustc_1_76_0 => {
4951
format!(

crates/spirv-builder/src/lib.rs

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -85,24 +85,20 @@ use std::env;
8585
use std::fs::File;
8686
use std::io::BufReader;
8787
use std::path::{Path, PathBuf};
88-
use std::process::{Command, Stdio};
88+
use std::process::Stdio;
8989
use thiserror::Error;
9090

9191
#[cfg(feature = "watch")]
9292
pub use self::watch::{SpirvWatcher, SpirvWatcherError};
93-
pub use rustc_codegen_spirv_types::Capability;
94-
use rustc_codegen_spirv_types::query_rustc_version;
95-
pub use rustc_codegen_spirv_types::{CompileResult, ModuleResult, TargetSpecVersion};
93+
pub use rustc_codegen_spirv_types::*;
9694

9795
#[derive(Debug, Error)]
9896
#[non_exhaustive]
9997
pub enum SpirvBuilderError {
10098
#[error("`target` must be set, for example `spirv-unknown-vulkan1.2`")]
10199
MissingTarget,
102-
#[error("expected `{SPIRV_TARGET_PREFIX}...` target, found `{target}`")]
103-
NonSpirvTarget { target: String },
104-
#[error("SPIR-V target `{SPIRV_TARGET_PREFIX}-{target_env}` is not supported")]
105-
UnsupportedSpirvTargetEnv { target_env: String },
100+
#[error("TargetError: {0}")]
101+
TargetError(#[from] TargetError),
106102
#[error("`path_to_crate` must be set")]
107103
MissingCratePath,
108104
#[error("crate path '{0}' does not exist")]
@@ -128,8 +124,6 @@ pub enum SpirvBuilderError {
128124
WatchFailed(#[from] SpirvWatcherError),
129125
}
130126

131-
const SPIRV_TARGET_PREFIX: &str = "spirv-unknown-";
132-
133127
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, serde::Deserialize, serde::Serialize)]
134128
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
135129
#[non_exhaustive]
@@ -784,36 +778,13 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
784778
.path_to_crate
785779
.as_ref()
786780
.ok_or(SpirvBuilderError::MissingCratePath)?;
787-
let target_env;
781+
let target;
788782
{
789-
let target = builder
783+
let target_str = builder
790784
.target
791785
.as_ref()
792786
.ok_or(SpirvBuilderError::MissingTarget)?;
793-
target_env = target.strip_prefix(SPIRV_TARGET_PREFIX).ok_or_else(|| {
794-
SpirvBuilderError::NonSpirvTarget {
795-
target: target.clone(),
796-
}
797-
})?;
798-
// HACK(eddyb) used only to split the full list into groups.
799-
#[allow(clippy::match_same_arms)]
800-
match target_env {
801-
// HACK(eddyb) hardcoded list to avoid checking if the JSON file
802-
// for a particular target exists (and sanitizing strings for paths).
803-
//
804-
// FIXME(eddyb) consider moving this list, or even `target-specs`,
805-
// into `rustc_codegen_spirv_types`'s code/source.
806-
"spv1.0" | "spv1.1" | "spv1.2" | "spv1.3" | "spv1.4" | "spv1.5" | "spv1.6" => {}
807-
"opengl4.0" | "opengl4.1" | "opengl4.2" | "opengl4.3" | "opengl4.5" => {}
808-
"vulkan1.0" | "vulkan1.1" | "vulkan1.1spv1.4" | "vulkan1.2" | "vulkan1.3"
809-
| "vulkan1.4" => {}
810-
811-
_ => {
812-
return Err(SpirvBuilderError::UnsupportedSpirvTargetEnv {
813-
target_env: target_env.into(),
814-
});
815-
}
816-
}
787+
target = Target::from_target(target_str)?;
817788

818789
if (builder.print_metadata == MetadataPrintout::Full) && builder.multimodule {
819790
return Err(SpirvBuilderError::MultiModuleWithPrintMetadata);
@@ -1012,8 +983,7 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
1012983
}
1013984

1014985
let target_spec_dir = target_dir.join("target-specs");
1015-
let target =
1016-
TargetSpecVersion::target_arg(toolchain_rustc_version, target_env, &target_spec_dir)?;
986+
let target = TargetSpecVersion::target_arg(toolchain_rustc_version, &target, &target_spec_dir)?;
1017987
cargo.arg("--target").arg(target);
1018988

1019989
if !builder.shader_crate_features.default_features {

tests/difftests/tests/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)