4个版本 (破坏性更新)
0.4.0 | 2023年7月22日 |
---|---|
0.3.0 | 2020年12月23日 |
0.2.0 | 2020年1月18日 |
0.1.0 | 2018年2月22日 |
#407 in 游戏开发
每月 22 次下载
17KB
137 行
dymod
这个crate提供了一个宏dymod!
,允许你指定一个Rust模块,该模块将在调试模式下动态加载和热插拔,但在发布模式下静态链接。
此crate的当前版本对如何组织你的动态代码有很强的意见。希望未来可以稍微放宽一些。
操作系统兼容性
这个crate已经在macOS (10.14.5),Ubuntu Linux (18.04.1),和Windows 10 (1903) 上进行了测试。但是,这是一个有点奇怪的crate,所以我不奇怪它会在一些其他操作系统上失败。告诉我吧!
用法
你的动态加载代码应该放在你主crate下的自己的子crate中
mycrate/
Cargo.toml
src/
main.rs
subcrate/
Cargo.toml
src/
lib.rs
你的子crate还必须编译为dylib,所以在你的subcrate/Cargo.toml
中添加
[lib]
crate-type = ["dylib"]
现在你需要添加你想要热插拔的代码。任何函数应该是 pub extern "C"
和 #[no_mangle]
。
// subcrate/src/lib.rs
#[no_mangle]
pub extern "C" fn count_sheep(sheep: u32) -> &'static str {
match sheep {
0 => "None",
1 => "One",
2 => "Two",
3 => "Many",
_ => "Lots"
}
}
最后,使用dymod!
宏指定你的模块,以及从中动态可用的函数。
// src/main.rs
use dymod::dymod;
dymod! {
#[path = "../subcrate/src/lib.rs"]
pub mod subcrate {
fn count_sheep(sheep: u32) -> &'static str;
}
}
fn main() {
assert_eq!(subcrate::count_sheep(3), "Many");
loop {
// You can now edit the count_sheep function,
// recompile `subcrate`, and see the result change
// while this code is running.
println!("{}", subcrate::count_sheep(3));
}
}
安全性
在发布模式下,你指定的模块被静态链接,就像是一个普通模块一样,应该没有安全问题。
然而,在调试模式下,当代码正在动态链接时,有很多事情可能会出错。可能会意外触发panic,或者产生未定义的行为。
以下是调试模式下可能会出错的列表的一部分
- 如果你在dylib热插拔时持有dylib拥有的数据,你将得到未定义的行为。
- 除非两个crate都使用系统分配器(幸运的是,自从Rust 1.32.0以来就是默认的),否则释放由另一个crate分配的数据将导致段错误。
- 如果您在边界两侧更改结构体的定义,可能会出现未定义的行为。(这包括添加或删除枚举变体。)
- 如果您在
dymod!
宏中指定了错误的函数签名,您将得到未定义的行为。
由于这些限制,建议您使用少量动态函数,并传递不太可能发生很大变化的类型。例如,在最简单的情况下
use dymod::dymod;
dymod! {
#[path = "../subcrate/src/lib.rs"]
pub mod subcrate {
fn update_application_state(state: &mut ApplicationState);
}
}
上述函数将为您提供在运行时调整任何应用程序状态的灵活性,但接口足够简单,易于维护。
手动重新加载
默认情况下,启用了auto-reload
功能,当动态库发生变化时(在您尝试调用其函数时),它会重新加载。
如果您希望自行处理重新加载,可以禁用此功能(--no-default-features
)并使用dymod模块的reload()
函数重新加载。
出于同样的原因,目前无法在您的dymod模块中定义名为reload
的函数。
依赖关系
~195KB