Skip to content

Commit 6fb35ff

Browse files
committed
outputs: ⋯.spv⋯.spv.json, ⋯.spv.dir/⋯⋯.spvs/⋯.spv (or ⋯.spv).
1 parent 3fca36e commit 6fb35ff

File tree

3 files changed

+77
-46
lines changed

3 files changed

+77
-46
lines changed

crates/rustc_codegen_spirv/src/link.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,40 +137,34 @@ fn link_exe(
137137

138138
let cg_args = CodegenArgs::from_session(sess);
139139

140-
let spv_binary = do_link(sess, &cg_args, &objects, &rlibs);
141-
142-
let mut root_file_name = out_filename.file_name().unwrap().to_owned();
143-
root_file_name.push(".dir");
144-
let out_dir = out_filename.with_file_name(root_file_name);
145-
if !out_dir.is_dir() {
146-
std::fs::create_dir_all(&out_dir).unwrap();
147-
}
148-
149-
let compile_result = match spv_binary {
150-
linker::LinkResult::SingleModule(spv_binary) => {
151-
let mut module_filename = out_dir;
152-
module_filename.push("module");
153-
post_link_single_module(sess, &cg_args, spv_binary.assemble(), &module_filename);
154-
cg_args.do_disassemble(&spv_binary);
140+
// HACK(eddyb) this removes the `.json` in `.spv.json`, from `out_filename`.
141+
let out_path_spv = out_filename.with_extension("");
142+
143+
let compile_result = match do_link(sess, &cg_args, &objects, &rlibs) {
144+
linker::LinkResult::SingleModule(module) => {
145+
let module_filename = out_path_spv;
146+
post_link_single_module(sess, &cg_args, module.assemble(), &module_filename);
147+
cg_args.do_disassemble(&module);
155148
let module_result = ModuleResult::SingleModule(module_filename);
156149
CompileResult {
157150
module: module_result,
158-
entry_points: entry_points(&spv_binary),
151+
entry_points: entry_points(&module),
159152
}
160153
}
161154
linker::LinkResult::MultipleModules(map) => {
155+
let out_dir = out_path_spv.with_extension("spvs");
156+
if !out_dir.is_dir() {
157+
std::fs::create_dir_all(&out_dir).unwrap();
158+
}
159+
162160
let entry_points = map.keys().cloned().collect();
163161
let map = map
164162
.into_iter()
165-
.map(|(name, spv_binary)| {
163+
.map(|(name, module)| {
166164
let mut module_filename = out_dir.clone();
167165
module_filename.push(sanitize_filename::sanitize(&name));
168-
post_link_single_module(
169-
sess,
170-
&cg_args,
171-
spv_binary.assemble(),
172-
&module_filename,
173-
);
166+
module_filename.set_extension("spv");
167+
post_link_single_module(sess, &cg_args, module.assemble(), &module_filename);
174168
(name, module_filename)
175169
})
176170
.collect();

crates/rustc_codegen_spirv/src/target.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl SpirvTarget {
8181
o.allows_weak_linkage = false;
8282
o.crt_static_allows_dylibs = true;
8383
o.dll_prefix = "".into();
84-
o.dll_suffix = ".spv".into();
84+
o.dll_suffix = ".spv.json".into();
8585
o.dynamic_linking = true;
8686
o.emit_debug_gdb_scripts = false;
8787
o.linker_flavor = LinkerFlavor::Unix(Cc::No);

crates/spirv-builder/src/lib.rs

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,15 @@ impl SpirvBuilder {
345345
match &metadata.module {
346346
ModuleResult::SingleModule(spirv_module) => {
347347
assert!(!self.multimodule);
348-
let env_var = at.file_name().unwrap().to_str().unwrap();
348+
let env_var = format!(
349+
"{}.spv",
350+
at.file_name()
351+
.unwrap()
352+
.to_str()
353+
.unwrap()
354+
.strip_suffix(".spv.json")
355+
.unwrap()
356+
);
349357
if self.print_metadata == MetadataPrintout::Full {
350358
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
351359
}
@@ -511,23 +519,41 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
511519

512520
// If we're nested in `cargo` invocation, use a different `--target-dir`,
513521
// to avoid waiting on the same lock (which effectively dead-locks us).
514-
// This also helps with e.g. RLS, which uses `--target target/rls`,
515-
// so we'll have a separate `target/rls/spirv-builder` for it.
516-
if let (Ok(profile), Some(mut dir)) = (
517-
env::var("PROFILE"),
518-
env::var_os("OUT_DIR").map(PathBuf::from),
519-
) {
520-
// Strip `$profile/build/*/out`.
521-
if dir.ends_with("out")
522-
&& dir.pop()
523-
&& dir.pop()
524-
&& dir.ends_with("build")
525-
&& dir.pop()
526-
&& dir.ends_with(profile)
527-
&& dir.pop()
528-
{
529-
cargo.arg("--target-dir").arg(dir.join("spirv-builder"));
522+
let outer_target_dir = match (env::var("PROFILE"), env::var_os("OUT_DIR")) {
523+
(Ok(profile), Some(dir)) => {
524+
// Strip `$profile/build/*/out`.
525+
[&profile, "build", "*", "out"].iter().rev().try_fold(
526+
PathBuf::from(dir),
527+
|mut dir, &filter| {
528+
if (filter == "*" || dir.ends_with(filter)) && dir.pop() {
529+
Some(dir)
530+
} else {
531+
None
532+
}
533+
},
534+
)
535+
}
536+
_ => None,
537+
};
538+
// FIXME(eddyb) use `crate metadata` to always be able to get the "outer"
539+
// (or "default") `--target-dir`, to append `/spirv-builder` to it.
540+
let target_dir = outer_target_dir.map(|outer| outer.join("spirv-builder"));
541+
if let Some(target_dir) = target_dir {
542+
// HACK(eddyb) Cargo caches some information it got from `rustc` in
543+
// `.rustc_info.json`, and assumes it only depends on the `rustc`
544+
// binary, but in our case, `rustc_codegen_spirv` changes are also
545+
// relevant - so we remove the cache file if it may be out of date.
546+
let mtime = |path| std::fs::metadata(path)?.modified();
547+
let rustc_info = target_dir.join(".rustc_info.json");
548+
if let Ok(rustc_info_mtime) = mtime(&rustc_info) {
549+
if let Ok(rustc_codegen_spirv_mtime) = mtime(&rustc_codegen_spirv) {
550+
if rustc_codegen_spirv_mtime > rustc_info_mtime {
551+
let _ = std::fs::remove_file(rustc_info);
552+
}
553+
}
530554
}
555+
556+
cargo.arg("--target-dir").arg(target_dir);
531557
}
532558

533559
for (key, _) in env::vars_os() {
@@ -552,9 +578,14 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
552578
// we do that even in case of an error, to let through any useful messages
553579
// that ended up on stdout instead of stderr.
554580
let stdout = String::from_utf8(build.stdout).unwrap();
555-
let artifact = get_last_artifact(&stdout);
556581
if build.status.success() {
557-
Ok(artifact.expect("Artifact created when compilation succeeded"))
582+
get_sole_artifact(&stdout).ok_or_else(|| {
583+
eprintln!("--- build output ---\n{stdout}");
584+
panic!(
585+
"`{}` artifact not found in (supposedly successful) build output (see above)",
586+
ARTIFACT_SUFFIX
587+
);
588+
})
558589
} else {
559590
Err(SpirvBuilderError::BuildFailed)
560591
}
@@ -566,7 +597,9 @@ struct RustcOutput {
566597
filenames: Option<Vec<String>>,
567598
}
568599

569-
fn get_last_artifact(out: &str) -> Option<PathBuf> {
600+
const ARTIFACT_SUFFIX: &str = ".spv.json";
601+
602+
fn get_sole_artifact(out: &str) -> Option<PathBuf> {
570603
let last = out
571604
.lines()
572605
.filter_map(|line| {
@@ -586,9 +619,13 @@ fn get_last_artifact(out: &str) -> Option<PathBuf> {
586619
.filenames
587620
.unwrap()
588621
.into_iter()
589-
.filter(|v| v.ends_with(".spv"));
622+
.filter(|v| v.ends_with(ARTIFACT_SUFFIX));
590623
let filename = filenames.next()?;
591-
assert_eq!(filenames.next(), None, "Crate had multiple .spv artifacts");
624+
assert_eq!(
625+
filenames.next(),
626+
None,
627+
"build had multiple `{ARTIFACT_SUFFIX}` artifacts"
628+
);
592629
Some(filename.into())
593630
}
594631

0 commit comments

Comments
 (0)