rksm / hot-lib-reloader-rs

Reload Rust code without app restarts. For faster feedback cycles.
MIT License
589 stars 19 forks source link

Usage with nested crate structure does not work #38

Open kaphula opened 2 weeks ago

kaphula commented 2 weeks ago

Edit: see the last message for solution.

Hey,

Is it possible use hot reloading with bevy_ecs crate only without the whole bevy dependency. Is it possible or necessary to use bevy_dylib dependency in this case? Does this require nightly Rust?

I tried to integrate everything to my project as shown in the bevy example, but I am running into error where attempting to hot load the modules panics:

#[cfg(not(feature = "reload"))]
use hot_systems::*;
#[cfg(feature = "reload")]
use systems_hot::*;

#[cfg(feature = "reload")]
#[hot_lib_reloader::hot_module(dylib = "hot_systems")]  // this panics
mod systems_hot {
    use bevy_ecs::prelude::*;
    pub use hot_components::*;
    hot_functions_from_file!("project_crate/src/game/hot_systems/src/lib.rs");
}

With the following message:

thread 'main' panicked at project_crate/src/game/ecs_schedules_and_systems.rs:49:1:
failed to create hot reload loader: LibraryCopyError(Custom { kind: NotFound, error: "file \"/project_root/project_crate/target/debug\" does not exist" })

Also my IDE complains that Use of an undeclared crate or module hot_lib_reloader which does not happen on the hot reload bevy example. However, the crate should be included as dependency correctly, no?

[features]
default = []
reload = [
    "dep:hot-lib-reloader",
    # Make sure that the types don't change:
    # This is important on windows for avoiding file locking issues:
    # "bevy/dynamic_linking",
]

[dependencies]
hot_components = {path = "src/game/hot_components"}
hot_systems = {path = "src/game/hot_systems"}
hot-lib-reloader = { version = "0.7.0", optional = true }

Note that the crates for bevy components and systems are in my project called hot_components and hot_systems respectively. The proper library files for hot_systems library do exist in my target debug folder though.

I can try to make a reproducable smaller project using bevy_ecs only with prints if this does not get solved and it should be possible use only bevy_ecs and hot reloading.

kaphula commented 2 weeks ago

It seems the issue occurs when nested crate structure is being used. With flat crate structure it seems to work. I created a repo (edit: this links now to the previous broken commit) that reproduces this error.

The project structure is the following:

.
├── Cargo.lock
├── Cargo.toml
├── main
│   ├── Cargo.toml
│   └── src
│       ├── components
│       │   ├── Cargo.toml
│       │   └── src
│       │       └── lib.rs
│       ├── main.rs
│       └── systems
│           ├── Cargo.toml
│           └── src
│               ├── lib.rs
│               └── utilities.rs
├── README.md
├── runcc-windows.yml
├── runcc.yml
└── rust-toolchain.toml

There is main crate for the main program and under its src/ the components and systems crates are defined. Is this kind of project structure supposed to be working and therefore this is a bug?

kaphula commented 2 weeks ago

I found the solution. lib_dir must be used to specify the correct dynamic library location if the hot-reload module is not being loaded from the root crate. In this case I am loading dynamically from a crate that is nested 1 step deep so the dynamic library path must be adjusted accordingly:


#[cfg(feature = "reload")]
#[hot_lib_reloader::hot_module(
    dylib = "systems",
    lib_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../target/debug")

)]

Is this the intended way to solve this situation? If yes, this issue can be closed.