动态加载的 crate 的一致 TypeId

Consistent TypeIds for dynamically loaded crates

我有一个插件系统,我将 &dyn Any 传递给动态加载的 rust 函数,但是由于 TypeId 不同(对于同一类型),向下转换引用失败,尽管我添加了 rustflags = ["-Cmetadata=12345678"] 到两个板条箱的货物配置。此外,似乎只有来自外部板条箱的类型受到影响(我尝试了 () 并且它在两个板条箱中产生了相同的 TypeId )。我目前正在转换原始指针 (unsafe { &*(v as *const dyn Any as *const Type) }) 来解决这个问题,但我更喜欢没有不安全代码的解决方案。

例如下面的代码:

println!("CRATE 1: TypeId of `()`: `{:?}`, TypeId of `toml::Value`: `{:?}`",
                 TypeId::of::<()>(), TypeId::of::<toml::Value>());

产生这个输出:

CRATE 1: TypeId of `()`: `TypeId { t: 7549865886324542212 }`, TypeId of `toml::Value`: `TypeId { t: 9270396907601429078 }`
CRATE 2: TypeId of `()`: `TypeId { t: 7549865886324542212 }`, TypeId of `toml::Value`: `TypeId { t: 5704635987193303200 }`

编辑: 这似乎不是不同依赖版本的问题,因为 crate 2(动态加载)依赖于 crate 3(也是动态加载)并且问题仍然存在,尽管 crate 2 和 crate 3 都是本地的依赖项(因此只有一个版本)。板条箱 1 是顺便说一句。装载板条箱 2 和 3 的板条箱。

编辑: 我从所有 3 个板条箱中删除了 -Cmetadata 选项,现在我得到了 toml::Value 相同的 TypeId,但是我想向下转换的板条箱 1 中的一个类型的 TypeId板条箱 2 仍然不同。

经过一些测试后,我发现 TypeId 是不同的,因为加载程序 crate(crate 1)在其他 2 个 crate 中用作库,但作为二进制文件执行。

为了解决这个问题,我将我想在加载的箱子中使用的所有箱子 1 的类型提取到一个新的箱子中,并将其添加到每个箱子的依赖项中。这个新 crate 只用作库而不是二进制文件,因此 TypeIds 应该是一致的。

为了让它正常工作我必须做的一切的总结:

  • 对所有 crate 使用相同的工具链版本
  • 在所有 crate 中使用相同的依赖版本
  • 不要使用-Cmetadata,这不再有效,实际上有相反的效果
  • 将加载器 crate 和加载的 crate 中使用的所有类型提取到一个新的 crate 中,并将其添加到所有 crate 的依赖项中
  • 每当你在这个 'common types crate' 中更改某些内容时,你必须重新编译所有其他 crate,因此 TypeIdS 是最新的

如果你仍然有问题,你可以回退到不安全的生锈(例如 unsafe { &*(value as *const dyn Any as *const Type) })。请注意,根本没有检查,因此如果类型不匹配,您可能会遇到分段错误。

特别感谢@trentcl 为我指明了正确的方向。