动态加载的 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 只用作库而不是二进制文件,因此 TypeId
s 应该是一致的。
为了让它正常工作我必须做的一切的总结:
- 对所有 crate 使用相同的工具链版本
- 在所有 crate 中使用相同的依赖版本
- 不要使用
-Cmetadata
,这不再有效,实际上有相反的效果
- 将加载器 crate 和加载的 crate 中使用的所有类型提取到一个新的 crate 中,并将其添加到所有 crate 的依赖项中
- 每当你在这个 'common types crate' 中更改某些内容时,你必须重新编译所有其他 crate,因此
TypeId
S 是最新的
如果你仍然有问题,你可以回退到不安全的生锈(例如 unsafe { &*(value as *const dyn Any as *const Type)
})。请注意,根本没有检查,因此如果类型不匹配,您可能会遇到分段错误。
特别感谢@trentcl 为我指明了正确的方向。
我有一个插件系统,我将 &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 只用作库而不是二进制文件,因此 TypeId
s 应该是一致的。
为了让它正常工作我必须做的一切的总结:
- 对所有 crate 使用相同的工具链版本
- 在所有 crate 中使用相同的依赖版本
- 不要使用
-Cmetadata
,这不再有效,实际上有相反的效果 - 将加载器 crate 和加载的 crate 中使用的所有类型提取到一个新的 crate 中,并将其添加到所有 crate 的依赖项中
- 每当你在这个 'common types crate' 中更改某些内容时,你必须重新编译所有其他 crate,因此
TypeId
S 是最新的
如果你仍然有问题,你可以回退到不安全的生锈(例如 unsafe { &*(value as *const dyn Any as *const Type)
})。请注意,根本没有检查,因此如果类型不匹配,您可能会遇到分段错误。
特别感谢@trentcl 为我指明了正确的方向。