<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>bigfish的网络博客 - ABI</title>
      <link>https://blog.laofu.online</link>
      <description>记录技术和生活</description>
      <generator>Zola</generator>
      <language>zh</language>
      <atom:link href="https://blog.laofu.online/tags/abi/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Thu, 15 Oct 2026 09:00:00 +0800</lastBuildDate>
      <item>
          <title>从一个 helloworld 动态库到 rpi package：ABI 插件是怎样被加载的</title>
          <pubDate>Thu, 15 Oct 2026 09:00:00 +0800</pubDate>
          <author>bigfish</author>
          <link>https://blog.laofu.online/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/</link>
          <guid>https://blog.laofu.online/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/</guid>
          <description xml:base="https://blog.laofu.online/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/">&lt;p&gt;很多人第一次看到 rpi 的 Rust 插件，会把它理解成“编译出一个动态库，然后让 rpi 找到它”。这句话方向没错，但省略了最关键的部分：动态库如何证明自己是一个 rpi 插件？注册的工具如何跨过 Rust 边界？一次调用结束后，插件里的内存由谁释放？源码目录里的 crate 又是怎样变成项目里的 package 的？&lt;/p&gt;
&lt;p&gt;这篇文章从 &lt;code&gt;examples/plugin-stub&lt;/code&gt; 这样的最小 demo 开始，沿着 &lt;code&gt;rpi-plugin-sdk&lt;/code&gt;、&lt;code&gt;rpi-extensions&lt;/code&gt; 和 &lt;code&gt;rpi-cli&lt;/code&gt; 的实现，解释这条链路：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;mermaid&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;flowchart&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    A&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;插件源码\nRust crate&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt; --&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; B&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;cdylib\n.dll / .so / .dylib&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    B &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; C&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;rpi 加载器\nlibloading&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    C &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; D&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;rpi_plugin_register&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    D &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; E&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;HostApi + ExtensionRegistry&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    E &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; F&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;RegistrySnapshot&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    F &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; G&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;Agent 会话中的工具\n事件与其他扩展能力&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的“插件”指 rpi 的 Rust 原生 ABI 扩展，不是 MCP Server，也不是一个通过 HTTP 或 stdio 运行的外部进程。它和宿主运行在同一个进程里，因此能力强、开销低，但也意味着插件是本机可信代码，ABI、内存所有权和生命周期必须非常明确。&lt;/p&gt;
&lt;p&gt;本文讨论的是 rpi 的原生 ABI 插件机制。由于 ABI、loader 和 package 命令会随仓库版本变化，下面的文件名、符号名和命令都应与所读源码版本一起核对；代码块中明确标注为“示意”的部分，不等于可直接复制运行的最小插件。文章关注一条主线：插件如何从动态库进入注册表，再被会话驱动；不把它扩展成完整的 Rust FFI 教程。&lt;/p&gt;</description>
      </item>
    </channel>
</rss>
