Add root_path_env property to shaders macro (#2180)

* shaders: minor fix that some Vecs were always allocated with capacity of 0

* shaders: add root_path_env property to allow loading shaders generated by a build script

* shaders: Apply root_path_env suggestions from code review

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* shaders: added root_path_env docs about env vars specified by a build script

---------

Co-authored-by: Firestar99 <4696087-firestar99@users.noreply.gitlab.com>
Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
This commit is contained in:
Firestar99 2023-04-11 11:28:45 +02:00 committed by GitHub
parent 8297cc863f
commit 9ba796d453
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -126,6 +126,20 @@
//! in conjunction with the `src` or `path` field. This allows using shaders compiled through a //! in conjunction with the `src` or `path` field. This allows using shaders compiled through a
//! separate build system. //! separate build system.
//! //!
//! ## `root_path_env: "..."`
//!
//! Instead of searching relative to your `Cargo.toml`, search relative to some other folder
//! specified by this env variable. The intended use case is using `OUT_DIR` to be able to load
//! shaders generated by your build script. Defaults to `CARGO_MANIFEST_DIR` corresponding to the
//! folder of your `Cargo.toml`.
//!
//! See [`cargo-env-vars`] for a full set of env variables set by cargo. It is also possible to
//! specify env variables from within the build script using the following:
//! ```rust
//! # let shader_out_dir = "";
//! println!("cargo:rustc-env=SHADER_OUT_DIR={shader_out_dir}");
//! ```
//!
//! ## `shaders: { first: { src: "...", ty: "..." }, ... }` //! ## `shaders: { first: { src: "...", ty: "..." }, ... }`
//! //!
//! With these options the user can compile several shaders in a single macro invocation. Each //! With these options the user can compile several shaders in a single macro invocation. Each
@ -200,6 +214,7 @@
//! | `shaderc-build-from-source` | Build the `shaderc` library from source when compiling. | //! | `shaderc-build-from-source` | Build the `shaderc` library from source when compiling. |
//! | `shaderc-debug` | Compile shaders with debug information included. | //! | `shaderc-debug` | Compile shaders with debug information included. |
//! //!
//! [`cargo-env-vars`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html
//! [cargo-expand]: https://github.com/dtolnay/cargo-expand //! [cargo-expand]: https://github.com/dtolnay/cargo-expand
//! [`ShaderModule::from_words_with_data`]: vulkano::shader::ShaderModule::from_words_with_data //! [`ShaderModule::from_words_with_data`]: vulkano::shader::ShaderModule::from_words_with_data
//! [`SpecializationConstants`]: vulkano::shader::SpecializationConstants //! [`SpecializationConstants`]: vulkano::shader::SpecializationConstants
@ -247,12 +262,34 @@ pub fn shader(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
} }
fn shader_inner(mut input: MacroInput) -> Result<TokenStream> { fn shader_inner(mut input: MacroInput) -> Result<TokenStream> {
let root = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into()); let (root, relative_path_error_msg) = match input.root_path_env.as_ref() {
None => (
env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into()),
"to your Cargo.toml".to_owned(),
),
Some(root_path_env) => {
let root = match env::var(root_path_env.value()) {
Ok(e) => e,
Err(e) => {
bail!(
root_path_env,
"failed to fetch environment variable: {e}; typical parameters are \
`OUT_DIR` to gather results from your build script, or left default to \
search relative to your Cargo.toml",
)
}
};
let env = root_path_env.value();
let error = format!("to the path `{root}` specified by the env variable `{env:?}`");
(root, error)
}
};
let root_path = Path::new(&root); let root_path = Path::new(&root);
let shaders = mem::take(&mut input.shaders); // yoink let shaders = mem::take(&mut input.shaders); // yoink
let mut shaders_code = Vec::with_capacity(input.shaders.len()); let mut shaders_code = Vec::with_capacity(shaders.len());
let mut types_code = Vec::with_capacity(input.shaders.len()); let mut types_code = Vec::with_capacity(shaders.len());
let mut type_registry = TypeRegistry::default(); let mut type_registry = TypeRegistry::default();
for (name, (shader_kind, source_kind)) in shaders { for (name, (shader_kind, source_kind)) in shaders {
@ -273,7 +310,7 @@ fn shader_inner(mut input: MacroInput) -> Result<TokenStream> {
bail!( bail!(
path, path,
"file `{full_path:?}` was not found, note that the path must be relative \ "file `{full_path:?}` was not found, note that the path must be relative \
to your Cargo.toml", {relative_path_error_msg}",
); );
} }
@ -302,7 +339,7 @@ fn shader_inner(mut input: MacroInput) -> Result<TokenStream> {
bail!( bail!(
path, path,
"file `{full_path:?}` was not found, note that the path must be relative \ "file `{full_path:?}` was not found, note that the path must be relative \
to your Cargo.toml", {relative_path_error_msg}",
); );
} }
@ -350,6 +387,7 @@ enum SourceKind {
} }
struct MacroInput { struct MacroInput {
root_path_env: Option<LitStr>,
include_directories: Vec<PathBuf>, include_directories: Vec<PathBuf>,
macro_defines: Vec<(String, String)>, macro_defines: Vec<(String, String)>,
shared_constants: bool, shared_constants: bool,
@ -365,6 +403,7 @@ impl MacroInput {
#[cfg(test)] #[cfg(test)]
fn empty() -> Self { fn empty() -> Self {
MacroInput { MacroInput {
root_path_env: None,
include_directories: Vec::new(), include_directories: Vec::new(),
macro_defines: Vec::new(), macro_defines: Vec::new(),
shared_constants: false, shared_constants: false,
@ -382,6 +421,7 @@ impl Parse for MacroInput {
fn parse(input: ParseStream<'_>) -> Result<Self> { fn parse(input: ParseStream<'_>) -> Result<Self> {
let root = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into()); let root = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into());
let mut root_path_env = None;
let mut include_directories = Vec::new(); let mut include_directories = Vec::new();
let mut macro_defines = Vec::new(); let mut macro_defines = Vec::new();
let mut shared_constants = None; let mut shared_constants = None;
@ -583,6 +623,13 @@ impl Parse for MacroInput {
} }
} }
} }
"root_path_env" => {
let lit = input.parse::<LitStr>()?;
if root_path_env.is_some() {
bail!(lit, "field `root_path_env` is already defined");
}
root_path_env = Some(lit);
}
"include" => { "include" => {
let in_brackets; let in_brackets;
bracketed!(in_brackets in input); bracketed!(in_brackets in input);
@ -709,6 +756,7 @@ impl Parse for MacroInput {
} }
Ok(MacroInput { Ok(MacroInput {
root_path_env,
include_directories, include_directories,
macro_defines, macro_defines,
shared_constants: shared_constants.unwrap_or(false), shared_constants: shared_constants.unwrap_or(false),