Closed jjant closed 1 year ago
The compiler doesn't provide a way for proc-macros to evaluate macros dynamically, so I don't think this is possible.
That said, the include_dir!()
macro can interpolate environment variables, so could the user just run some_crate::include_assets!("$CARGO_MANIFEST_DIR/assets")
where your macro passes "$CARGO_MANIFEST_DIR/assets"
to include_dir!()
as-is?
It's also possible to hack around the lack of string concatenation with something like paste
.
extern crate paste;
macro_rules! include_dir {
($arg:literal) => {
println!("Including {}", $arg);
};
}
/// The paste crate will only concatenate strings when it looks like they are
/// used in a #[doc] attribute, so this tricks paste into doing the
/// string concatenation rather than creating an (invalid)
/// "$CARGO_MANIFEST_DIR/blah" identifier
macro_rules! include_dir_hack {
(#[doc = $arg:literal]) => {
include_dir!($arg);
};
}
macro_rules! include_assets {
($arg:tt) => {
paste::paste! {
include_dir_hack!(#[doc = "$CARGO_MANIFEST_DIR/" $arg ]);
}
};
}
fn main() {
include_assets!("assets"); // Outputs "Including $CARGO_MANIFEST_DIR/assets"
}
There was an RFC for "eager macro expansion" which does exactly what you want, but that was postponed.
If the above workarounds aren't acceptable, you might need to look for another way to do the same thing.
Also, keep in mind that any macro-based solution will evaluate the $CARGO_MANIFEST_DIR
to the caller's crate directory, not your include_assets!()
crate's directory.
I want to write a crate that interally uses
include_dir
, something like this:But that currently fails because
include_dir
only allows literal strings as arguments.