outputs: ⋯.spv⋯.spv.json, ⋯.spv.dir/⋯⋯.spvs/⋯.spv (or ⋯.spv).

This commit is contained in:
Eduard-Mihai Burtescu 2022-12-12 14:17:57 +02:00 committed by Eduard-Mihai Burtescu
parent 3fca36ecb2
commit 6fb35ffeeb
3 changed files with 76 additions and 45 deletions

View File

@ -137,40 +137,34 @@ fn link_exe(
let cg_args = CodegenArgs::from_session(sess);
let spv_binary = do_link(sess, &cg_args, &objects, &rlibs);
// HACK(eddyb) this removes the `.json` in `.spv.json`, from `out_filename`.
let out_path_spv = out_filename.with_extension("");
let mut root_file_name = out_filename.file_name().unwrap().to_owned();
root_file_name.push(".dir");
let out_dir = out_filename.with_file_name(root_file_name);
let compile_result = match do_link(sess, &cg_args, &objects, &rlibs) {
linker::LinkResult::SingleModule(module) => {
let module_filename = out_path_spv;
post_link_single_module(sess, &cg_args, module.assemble(), &module_filename);
cg_args.do_disassemble(&module);
let module_result = ModuleResult::SingleModule(module_filename);
CompileResult {
module: module_result,
entry_points: entry_points(&module),
}
}
linker::LinkResult::MultipleModules(map) => {
let out_dir = out_path_spv.with_extension("spvs");
if !out_dir.is_dir() {
std::fs::create_dir_all(&out_dir).unwrap();
}
let compile_result = match spv_binary {
linker::LinkResult::SingleModule(spv_binary) => {
let mut module_filename = out_dir;
module_filename.push("module");
post_link_single_module(sess, &cg_args, spv_binary.assemble(), &module_filename);
cg_args.do_disassemble(&spv_binary);
let module_result = ModuleResult::SingleModule(module_filename);
CompileResult {
module: module_result,
entry_points: entry_points(&spv_binary),
}
}
linker::LinkResult::MultipleModules(map) => {
let entry_points = map.keys().cloned().collect();
let map = map
.into_iter()
.map(|(name, spv_binary)| {
.map(|(name, module)| {
let mut module_filename = out_dir.clone();
module_filename.push(sanitize_filename::sanitize(&name));
post_link_single_module(
sess,
&cg_args,
spv_binary.assemble(),
&module_filename,
);
module_filename.set_extension("spv");
post_link_single_module(sess, &cg_args, module.assemble(), &module_filename);
(name, module_filename)
})
.collect();

View File

@ -81,7 +81,7 @@ impl SpirvTarget {
o.allows_weak_linkage = false;
o.crt_static_allows_dylibs = true;
o.dll_prefix = "".into();
o.dll_suffix = ".spv".into();
o.dll_suffix = ".spv.json".into();
o.dynamic_linking = true;
o.emit_debug_gdb_scripts = false;
o.linker_flavor = LinkerFlavor::Unix(Cc::No);

View File

@ -345,7 +345,15 @@ impl SpirvBuilder {
match &metadata.module {
ModuleResult::SingleModule(spirv_module) => {
assert!(!self.multimodule);
let env_var = at.file_name().unwrap().to_str().unwrap();
let env_var = format!(
"{}.spv",
at.file_name()
.unwrap()
.to_str()
.unwrap()
.strip_suffix(".spv.json")
.unwrap()
);
if self.print_metadata == MetadataPrintout::Full {
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
}
@ -511,23 +519,41 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
// If we're nested in `cargo` invocation, use a different `--target-dir`,
// to avoid waiting on the same lock (which effectively dead-locks us).
// This also helps with e.g. RLS, which uses `--target target/rls`,
// so we'll have a separate `target/rls/spirv-builder` for it.
if let (Ok(profile), Some(mut dir)) = (
env::var("PROFILE"),
env::var_os("OUT_DIR").map(PathBuf::from),
) {
let outer_target_dir = match (env::var("PROFILE"), env::var_os("OUT_DIR")) {
(Ok(profile), Some(dir)) => {
// Strip `$profile/build/*/out`.
if dir.ends_with("out")
&& dir.pop()
&& dir.pop()
&& dir.ends_with("build")
&& dir.pop()
&& dir.ends_with(profile)
&& dir.pop()
{
cargo.arg("--target-dir").arg(dir.join("spirv-builder"));
[&profile, "build", "*", "out"].iter().rev().try_fold(
PathBuf::from(dir),
|mut dir, &filter| {
if (filter == "*" || dir.ends_with(filter)) && dir.pop() {
Some(dir)
} else {
None
}
},
)
}
_ => None,
};
// FIXME(eddyb) use `crate metadata` to always be able to get the "outer"
// (or "default") `--target-dir`, to append `/spirv-builder` to it.
let target_dir = outer_target_dir.map(|outer| outer.join("spirv-builder"));
if let Some(target_dir) = target_dir {
// HACK(eddyb) Cargo caches some information it got from `rustc` in
// `.rustc_info.json`, and assumes it only depends on the `rustc`
// binary, but in our case, `rustc_codegen_spirv` changes are also
// relevant - so we remove the cache file if it may be out of date.
let mtime = |path| std::fs::metadata(path)?.modified();
let rustc_info = target_dir.join(".rustc_info.json");
if let Ok(rustc_info_mtime) = mtime(&rustc_info) {
if let Ok(rustc_codegen_spirv_mtime) = mtime(&rustc_codegen_spirv) {
if rustc_codegen_spirv_mtime > rustc_info_mtime {
let _ = std::fs::remove_file(rustc_info);
}
}
}
cargo.arg("--target-dir").arg(target_dir);
}
for (key, _) in env::vars_os() {
@ -552,9 +578,14 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
// we do that even in case of an error, to let through any useful messages
// that ended up on stdout instead of stderr.
let stdout = String::from_utf8(build.stdout).unwrap();
let artifact = get_last_artifact(&stdout);
if build.status.success() {
Ok(artifact.expect("Artifact created when compilation succeeded"))
get_sole_artifact(&stdout).ok_or_else(|| {
eprintln!("--- build output ---\n{stdout}");
panic!(
"`{}` artifact not found in (supposedly successful) build output (see above)",
ARTIFACT_SUFFIX
);
})
} else {
Err(SpirvBuilderError::BuildFailed)
}
@ -566,7 +597,9 @@ struct RustcOutput {
filenames: Option<Vec<String>>,
}
fn get_last_artifact(out: &str) -> Option<PathBuf> {
const ARTIFACT_SUFFIX: &str = ".spv.json";
fn get_sole_artifact(out: &str) -> Option<PathBuf> {
let last = out
.lines()
.filter_map(|line| {
@ -586,9 +619,13 @@ fn get_last_artifact(out: &str) -> Option<PathBuf> {
.filenames
.unwrap()
.into_iter()
.filter(|v| v.ends_with(".spv"));
.filter(|v| v.ends_with(ARTIFACT_SUFFIX));
let filename = filenames.next()?;
assert_eq!(filenames.next(), None, "Crate had multiple .spv artifacts");
assert_eq!(
filenames.next(),
None,
"build had multiple `{ARTIFACT_SUFFIX}` artifacts"
);
Some(filename.into())
}