Michael-F-Bryan / include_dir

The logical evolution of the include_str macro for embedding a directory tree into your binary.
https://michael-f-bryan.github.io/include_dir
MIT License
319 stars 36 forks source link

Accept macro arguments other than string literals #61

Closed arctic-hen7 closed 2 years ago

arctic-hen7 commented 2 years ago

At present, the include_dir! macro only accepts literal strings, which makes including a directory outside the crate's root directory extremely complex. At package-time, it's trivial to simply copy the directory in and use that (packaging won't work with ../ paths), but that requires that one be able to set one path in development and one path in production.

Here's an example:

#[cfg(debug_assertions)]
const PATH: &str = "./dev-path";
#[cfg(not(debug_assertions))]
const PATH: &str = "../../prod-path";

const INCLUDED_DIR: Dir = include_dir!(PATH);

Unfortunately, the macro itself won't allow this, i think because of this line in the macro definition. If the macro could also accept statics and the like, that would be really helpful for this use-case!

Aside: I have practically no experience at all with proc macros, but I'm happy to attempt a fix for this!

arctic-hen7 commented 2 years ago

Okay, having spent some time figuring out how feasible this is, I have absolutely no clue how to do this. @Michael-F-Bryan this isn't urgent, but it'd be great to have!

Michael-F-Bryan commented 2 years ago

This isn't possible because proc macroes run on syntax trees immediately after parsing so runs it will only see the identifier, PATH, and not have any way to access the value it represents (that's only known after type checking).

You could write this instead, though:

#[cfg(debug_assertions)]
const INCLUDED_DIR: Dir = include_dir!("./dev-path");
#[cfg(not(debug_assertions))]
const INCLUDED_DIR: Dir = include_dir!("../../prod-path");
arctic-hen7 commented 2 years ago

Yeah I thought that might be the case. Shame.

arctic-hen7 commented 2 years ago

That unfortunately doesn't seem to work in packaging interestingly! It seems that Rust expands both macros regardless, leading to compile-time errors about one directory not existing, only filtering out which one to use afterward. In other words, there's no prioritization of macro hierarchies (which would be a great language feature).

For anyone else in this boat, I fixed my problem by verbatim copying the external directory to somewhere from which it can be accessed.

Michael-F-Bryan commented 2 years ago

For anyone else in this boat, I fixed my problem by verbatim copying the external directory to somewhere from which it can be accessed.

I normally use symlinks when I want an outside directory to be included in the crate published to crates.io.

arctic-hen7 commented 2 years ago

I think I just assumed Cargo wouldn't work with symlinks, that's a great idea! Thanks!