Skip to content

file!() returns incorrect Paths on WASM target built on Windows. #140883

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

Open
andriyDev opened this issue May 10, 2025 · 3 comments
Open

file!() returns incorrect Paths on WASM target built on Windows. #140883

andriyDev opened this issue May 10, 2025 · 3 comments
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@andriyDev
Copy link

andriyDev commented May 10, 2025

Here is a minimal reproducible example: https://github.com/andriyDev/wasm-path-error

The file!() macro produces nonsensical paths for WASM built on Windows.

On Windows, file!() in src/lib.rs produces src\\lib.rs with the components ["src", "lib.rs"].

I would expect file!() to produce the same set of components on WASM. However, on WASM built on Windows, file!() in src/lib.rs produces src\\lib.rs with the components ["src\\lib.rs"].

It seems that the path is not translated appropriately from Windows to WASM.

Meta

rustc --version --verbose:

rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: x86_64-pc-windows-msvc
release: 1.85.0
LLVM version: 19.1.7

Additional Context

This is relevant for bevyengine/bevy#14246. We are using the file path to refer to an asset in the src directory, but due to the incorrect components, we can't remove the src prefix.

@andriyDev andriyDev added the C-bug Category: This is a bug. label May 10, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 10, 2025
@hanna-kruppe
Copy link
Contributor

The precise meaning of file!() is currently a bit fuzzy (see #134442) but it refers to a file on the machine that’s doing the compilation (the host). Naturally this uses the path syntax of the host OS because if anything tries to find the file on disk they’re most likely going to do it on the host machine. It won’t be meaningful as a path on an entirely different machine, and trying to translate it approximately would have many edge cases for unclear benefit.

I see that the relevant Bevy code does some runtime (in-Wasm) processing of file!() so I’m not surprised to hear it doesn’t work. I’m more surprised that Linux host + Wasm module does work — how’s the Wasm module getting access to the file on the host? If there’s some Bevy-specific code that runs outside Wasm to load the file either at build time or at run time, the fix might be to leave all path manipulation to that host code.

@andriyDev
Copy link
Author

andriyDev commented May 10, 2025

We do this for embedded assets. Embedded assets use include_bytes! to include an asset's bytes into the binary and then lets users refer to it relative to their src directory. So users (roughly) call embedded_asset!("splash_screen.png") and can now access the asset at "embedded://splash_screen.png". Of course in order to do this we need to strip off the src prefix (Note for crates file!() returns the whole path, something like "C:\some_crate_path\src\splash_screen.png", in which case we still want to access the asset at "embedded://splash_screen.png").

Essentially the file!() macro is being used as a key into a map, but we need to do some processing on the path to make it do what we want.

How can we manipulate the path on the host code? The only way I know of would be a proc_macro but that seems very heavyweight for what we need. It's not clear to me that Path is the correct type for file!() since it refers to a path on the host, which as you've said can be very different from the target.

Alternatively, if we could know the host machine, we could apply the fix specifically for Windows host + non-Windows target. If we do this now, we can only conditionally compile based on the target which means preventing use of \\ in paths on non-Windows targets just in case you're cross-compiling from Windows. To be fair, that is something I am willing to give up, but that seems like a restricting solution.

Edit: I've totally confused myself. file!() doesn't return Path, it returns str.

@hanna-kruppe
Copy link
Contributor

Ah, I see, I jumped to the conclusion that since the macro expands to runtime path manipulation code, it must be also loading the files based on the computed paths. If you're delegating the file loading to include_bytes! then forget everything I said about wasm. But of course this is another good reason why file!() needs to be a host path and not "translated" to target path syntax.

Alternatively, if we could know the host machine, we could apply the fix specifically for Windows host + non-Windows target. If we do this now, we can only conditionally compile based on the target which means preventing use of \\ in paths on non-Windows targets just in case you're cross-compiling from Windows. To be fair, that is something I am willing to give up, but that seems like a restricting solution.

You could add a build script to the crate that defines this macro (if it doesn't have one already) and have set a cfg for that crate based on the value of cfg!(windows) or std::path::MAIN_SEPARATOR in the build script.

@lolbinarycat lolbinarycat added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants