10个版本 (6个破坏性版本)

0.10.0 2023年3月10日
0.9.0 2023年3月9日
0.8.0 2022年4月16日
0.4.0 2019年8月28日
0.1.2 2016年2月21日

#231操作系统

Download history 34/week @ 2024-03-14 14/week @ 2024-03-21 47/week @ 2024-03-28 55/week @ 2024-04-04 22/week @ 2024-04-11 13/week @ 2024-04-18 8/week @ 2024-04-25 4/week @ 2024-05-16 1/week @ 2024-05-23

每月172次下载
用于 3个 软件包 (直接使用2个)

MIT/Apache

40KB
663

Build Status Coverage Status Crates.io Documentation

dynamic_reload是一个用Rust编写的跨平台库,它使得共享库(Windows上的dll,*nix上的.so,Mac上的.dylib等)的重新加载变得更加容易。它的目的是允许应用程序在代码发生变化时无需关闭应用程序即可动态重新加载代码。这可以看作是Rust的“实时”编码的轻量级版本。值得注意的是,共享库的重新加载不仅限于用Rust编写的库,也可以用任何可以针对共享库的语言来实现。一个典型的场景可能如下所示

1. Application Foo starts.
2. Foo loads the shared library Bar.
3. The programmer needs to make some code changes to Bar.
   Instead of closing down Foo the programmer does the change, recompiles the code.
4. Foo will detect that Bar has been changed on the disk,
   will unload the old version and load the new one.

dynamic_reload库不会尝试解决Foo中的Bar残留的任何旧数据。在Foo重新加载之前,Foo需要确保所有数据都已清理。在Bar重新加载之前,Foo将从dynamic_reload收到一个回调,这允许Foo采取必要的行动。然后,在Bar重新加载之后,将进行另一个调用,允许Foo在需要时恢复Bar的状态。

用法

# Cargo.toml
[dependencies]
dynamic_reload = "0.10.0"

示例

要实际测试此示例的重新加载,请执行以下操作

1, cargo run --example example
2. In another shell change src/test_shared.rs to return another value
3. Run cargo build
4. Notice that the value return in 1. is now changed
use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
use std::{sync::Arc, time::Duration, thread};

struct Plugins {
    plugins: Vec<Arc<Lib>>,
}

impl Plugins {
    fn add_plugin(&mut self, plugin: &Arc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Arc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i] == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Arc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Arc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn main() {
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default,
                                                Duration::from_sec(2));

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    loop {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> = unsafe {
                plugs.plugins[0].lib.get(b"shared_fun\0").unwrap()
            };

            println!("Value {}", fun());
        }

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }
}

致谢

dynamic_reload使用这两个crate来处理大部分繁重的工作。谢谢!

通知: https://github.com/passcod/rsnotify

libloading: https://github.com/nagisa/rust_libloading/

许可证

根据以下任一项许可:

任选其一。

贡献

除非你明确声明,否则根据Apache-2.0许可证定义的,你有意提交给作品包括在内的任何贡献,都应双许可如上所述,没有额外的条款或条件。

依赖关系

~2–11MB
~125K SLoC