diff --git a/src/lib.rs b/src/lib.rs index 6f013dd..9155a2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,26 +3,26 @@ use { naga::front::wgsl, proc_macro::TokenStream, - quote::quote, - std::fs, + quote::{format_ident, quote}, syn::{parse, LitStr}, }; mod source_reader; struct ShaderModule { - source_text: String, + source_file: source_reader::SourceFile, naga_module: naga::Module, } impl ShaderModule { - fn try_new(source_file: impl Into) -> Result { - let source_filename = source_file.into(); - let source_file = source_reader::read_source_file(source_filename)?; - let source_text = source_file.full_text().to_string(); + fn try_new( + source_dir: &std::path::Path, + source_filename: &std::path::Path, + ) -> Result { + let source_file = source_reader::read_source_file(source_dir, source_filename)?; - let naga_module = wgsl::parse_str(&source_text).map_err(|err| { - if let Some(location) = err.location(&source_text) { + let naga_module = wgsl::parse_str(&source_file.full_text()).map_err(|err| { + if let Some(location) = err.location(&source_file.full_text()) { let (inner_source_filename, inner_line_num) = source_file.map_source_line_num(location.line_number as usize); Error::Message(format!( @@ -41,17 +41,35 @@ impl ShaderModule { } })?; Ok(Self { - source_text, + source_file, naga_module, }) } fn emit_rust_code(&self) -> TokenStream { - let source_text = &self.source_text; + // We include the text of all the source files into the generated code + // with include_bytes!() so that Cargo recognizes them as + // dependencies. It's not pretty but it works. Since the file contents + // are just stored in unused local variables, they should be removed by + // the optimizer and not affect the compiled code. + let source_text = &self.source_file.full_text(); + let dependencies: Vec<_> = self + .source_file + .all_filenames() + .iter() + .map(|path| path.as_os_str().to_string_lossy()) + .collect(); + let dummy_var: Vec<_> = (0u32..) + .map(|n| format_ident!("_{}", n)) + .take(dependencies.len()) + .collect(); quote! { - wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(#source_text)), + { + #(let #dummy_var = include_bytes!(#dependencies);)* + wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(#source_text)), + } } } .into() @@ -60,7 +78,7 @@ impl ShaderModule { struct WgslModuleMacroInput { source_dir: std::path::PathBuf, - filename: String, + filename: std::path::PathBuf, } enum Error { @@ -89,7 +107,7 @@ fn parse_input(token_stream: TokenStream) -> Result let source_dir = token.span().source_file().path().parent().unwrap().into(); let literal: LitStr = parse(token_stream)?; - let filename = literal.value(); + let filename = std::path::Path::new(&literal.value()).into(); Ok(WgslModuleMacroInput { source_dir, filename, @@ -98,8 +116,7 @@ fn parse_input(token_stream: TokenStream) -> Result fn wgsl_module_inner(input_token_stream: TokenStream) -> Result { let input = parse_input(input_token_stream)?; - let full_filename = input.source_dir.join(&input.filename); - let module = ShaderModule::try_new(full_filename)?; + let module = ShaderModule::try_new(&input.source_dir, &input.filename)?; Ok(module.emit_rust_code()) } diff --git a/src/source_reader.rs b/src/source_reader.rs index e6deccf..74a6fe0 100644 --- a/src/source_reader.rs +++ b/src/source_reader.rs @@ -29,10 +29,14 @@ impl SourceFile { pub fn map_source_line_num(&self, line_num: usize) -> (&Path, usize) { (&self.source_map.filename, line_num) } + + pub fn all_filenames(&self) -> Vec<&Path> { + vec![&self.source_map.filename] + } } -pub fn read_source_file(filename: PathBuf) -> Result { - let source_text = fs::read_to_string(&filename).map_err(|err| { +pub fn read_source_file(source_dir: &Path, filename: &Path) -> Result { + let source_text = fs::read_to_string(&source_dir.join(filename)).map_err(|err| { Error::from_message(format!( "Could not open \"{}\": {}", &filename.as_os_str().to_string_lossy(), @@ -42,7 +46,7 @@ pub fn read_source_file(filename: PathBuf) -> Result { Ok(SourceFile { source_text, source_map: SourceMap { - filename, + filename: filename.into(), offset: 0, total_lines: 0, insertions: vec![],