-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
There is no cross-platform way to use include_*!
#75075
Comments
Can you use a build script to use |
I'll try it. Thanks for pointing this out! |
You can use cfg-ed macros to pass conditional string literals to #[cfg(not(windows))]
macro_rules! main_separator{
()=>{"/"}
}
#[cfg(windows)]
macro_rules! main_separator{
()=>{r#"\"#}
}
fn main(){
println!("{}", include_str!(concat!(".", main_separator!(), "main.rs" )));
} |
|
The
I did that, but that only look at the target platform and should break when the host platform is different (i.e. when cross-compiling).
|
include_bytes!
data generated by a build scriptinclude_bytes!
in a cross-platform way is not discoverable
On Windows if |
Oh that's a bummer, I thought the same parsing here would apply as for |
Well it is the same parsing. Concatenating |
Would it maybe make sense for the include_*! macros to allow syntax like |
//! `build.rs`
#[cfg(windows)]
const HOST_FAMILY: &str = "windows";
#[cfg(unix)]
const HOST_FAMILY: &str = "unix";
fn main ()
{
#[cfg(any(windows, unix))] {
println!("cargo:rust-cfg=host_family={}", HOST_FAMILY);
}
}
and then: #[cfg(host_family = "windows")]
macro_rules! PATH_SEPARATOR {() => (
r"\"
)}
#[cfg(not(host_family = "windows"))]
macro_rules! PATH_SEPARATOR {() => (
r"/"
)}
include_bytes!(concat!(
env!("OUT_DIR"), PATH_SEPARATOR!(), "my_file"
)); |
include_bytes!
in a cross-platform way is not discoverableinclude_bytes!
include_bytes!
include_*!
I think the definition of |
include_bytes!(env!("OUT_DIR"), "some_dir", "some_file.txt")
|
Perhaps to resolve this in an interesting manner, implement the second suggestion above by @therealbnut into a new "path!()" macro that resolves a set of path segments into a platform-specific path at compile time. Edit: For example Edit 2: It appears someone has beat me to the punch in the meantime, just with a different syntax Edit 3: Just realized this would give the appearance that nested macros are a thing, which they most certainly are not. Perhaps not the greatest idea in hindsight. Maybe this behavior could be made into a new set of macros to mirror the old ones? |
For those just looking to use a cross-platform version of this, or those looking to better understand my proposal above, Here's a Crate |
Why are they not? |
As far as I am aware these need special code to work, as all tokens inside a macro invocation need to be parsed by the macro itself, including other macro invocations, and I'm not sure giving the appearance that this pattern can work with any other combination of macros is a good idea. |
I'd argue that the damage has already been done by |
Not a reason to cause further confusion tbh. The better we can do the less confusion there'll be overall. Edit: I feel like this is a whole separate issue we've stumbled upon here. Perhaps this should be addressed in a separate thread. For now, both proposals should be considered by the Rust team. |
@AZMCode you have a point. Apparently the I think a It seems to me the problem domain that the |
Sounds reasonable enough, though I support commas over slashes for the separators for now. |
@AZMCode it's explained here: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#eager-expansion |
Also: rust-lang/rfcs#2320 Edit: I think it's getting a bit off topic though. This thread is not about eager expansion as a general language feature. |
Understandable. |
I have an alternative idea. What if there was an option to tell Cargo to use / path separators for all its path environment variables like OUT_DIR and CARGO_MANIFEST_DIR? |
Build scripts place their output in a folder created by Cargo. The path to it is passed in the environment variable
OUT_DIR
both to the build script and the main code. Since the file is placed in the directory, we need to add the path separator and then the name of the file. There seems to be no way to callinclude_bytes!
with a platform-agnostic path separator, inserting/
or\
depending on the host OS.This works but is not portable:
include_bytes!(concat!(env!("OUT_DIR"), "/myfile"));
This doesn't work:
include_bytes!(concat!(env!("OUT_DIR"), std::path::MAIN_SEPARATOR, "myfile"));
becauseMAIN_SEPARATOR
is not a literal, andconcat!
only eats literals.I've tried to to assemble a
String
inconst fn
, but that doesn't work either becauseString::push()
requires a mutable borrow which are unsable inconst fn
.#[cfg(unix)]
and#[cfg(windows)]
sort of work, but break on cross-compilation because thesecfg
attributes look at the target OS, and we need to add a separator that works on the host OS.It's weird that this is either impossible to accomplish or the way to do so is very obscure. I'd expect this to be a relatively common operation.
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: