# FFI 接口

<cite>
**本文引用的文件**
- [tsn_ffi.rs](file://src/tsn_ffi.rs)
- [lib.rs](file://src/lib.rs)
- [loader 主程序](file://loader/src/main.rs)
- [运行时库](file://runtime/src/lib.rs)
- [Cargo.toml](file://Cargo.toml)
- [项目编译器](file://src/project_compiler.rs)
- [独立生成器](file://src/standalone_gen.rs)
- [项目模块](file://src/project.rs)
- [架构设计](file://docs/架构设计/架构设计.md)
- [代码生成器](file://src/codegen.rs)
- [SWC 转换器](file://src/swc_transform.rs)
- [COFF 解析器](file://src/coff.rs)
</cite>

## 更新摘要
**变更内容**
- 新增 addon_dlls 字段支持，允许外部调用者获取 addon 信息
- 更新 TsnCompileResult 和 CompileContext 结构体以包含 addon 相关数据
- 增强 FFI 接口以支持 addon 相关的数据结构和内存管理
- 更新编译流程以收集和暴露 addon DLL 信息

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件系统性地文档化 ts-native 的 FFI 接口，聚焦于外部函数接口的设计与实现、数据类型转换规则、调用约定、与外部加载器的交互机制、函数注册与回调处理、错误传播策略，以及 C 语言与 Rust 之间的数据交换协议。文档同时提供使用示例与集成指南，并总结类型安全检查与边界条件处理的最佳实践。

**更新** 新增对 addon 信息暴露的支持，允许外部调用者获取编译过程中使用的 addon DLL 信息。

## 项目结构
- FFI 导出位于库模块的导出层，面向外部加载器（loader）暴露稳定的 ABI。
- 加载器负责动态加载 ts-native 编译器 DLL，调用 FFI 函数进行编译与执行。
- 运行时库提供 C ABI 的运行时函数，供编译产物在执行期调用。
- 核心编译管线（SWC → HIR → CodeGen → COFF）为 FFI 输出提供底层能力。
- **新增** addon 系统支持，允许在编译过程中收集和暴露第三方 DLL 信息。

```mermaid
graph TB
subgraph "编译器侧"
A["tsn_ffi.rs<br/>导出 DLL 函数"]
B["swc_transform.rs<br/>解析与 HIR 生成"]
C["codegen.rs<br/>Cranelift 代码生成"]
D["coff.rs<br/>COFF 对象解析"]
E["project_compiler.rs<br/>项目编译与 addon 处理"]
F["standalone_gen.rs<br/>独立可执行文件生成"]
end
subgraph "加载器侧"
L["loader/src/main.rs<br/>动态加载 DLL/应用重定位/执行"]
end
subgraph "运行时侧"
R["runtime/src/lib.rs<br/>C ABI 运行时函数"]
end
A --> B --> C --> D
L --> A
L --> R
E --> A
F --> E
```

**图表来源**
- [tsn_ffi.rs:1-355](file://src/tsn_ffi.rs#L1-L355)
- [loader 主程序:130-743](file://loader/src/main.rs#L130-L743)
- [运行时库:1-800](file://runtime/src/lib.rs#L1-800)
- [项目编译器:400-599](file://src/project_compiler.rs#L400-L599)
- [独立生成器:15-214](file://src/standalone_gen.rs#L15-L214)

**章节来源**
- [lib.rs:1-17](file://src/lib.rs#L1-L17)
- [Cargo.toml:17-21](file://Cargo.toml#L17-L21)

## 核心组件
- FFI 导出接口（tsn_ffi.rs）
  - 导出编译函数、结果释放函数、版本查询函数，以及可选的 COFF 编译导出。
  - 定义与 C ABI 对齐的数据结构（TsnSymbol、TsnRelocation、TsnCompileResult），**新增 addon_dlls 字段**。
- 加载器（loader/src/main.rs）
  - 动态加载 ts-native DLL，解析导出函数指针，调用编译函数，复制内存，应用重定位，最终执行入口函数。
- 运行时库（runtime/src/lib.rs）
  - 提供 C ABI 的运行时函数（字符串、数组、对象、数学、IO 等），支持日志回调与可选的 DOM/FS 占位实现。
- 编译管线
  - SWC 解析 → HIR 生成 → CodeGen → COFF 输出，为 FFI 提供原始节区、符号与重定位信息。
- **新增** Addon 系统
  - 支持第三方 DLL 的配置和加载，通过项目配置文件中的 native_addons 段落进行管理。

**章节来源**
- [tsn_ffi.rs:9-46](file://src/tsn_ffi.rs#L9-L46)
- [tsn_ffi.rs:48-60](file://src/tsn_ffi.rs#L48-L60)
- [loader 主程序:233-268](file://loader/src/main.rs#L233-L268)
- [loader 主程序:337-502](file://loader/src/main.rs#L337-L502)
- [运行时库:135-800](file://runtime/src/lib.rs#L135-L800)
- [SWC 转换器:10-34](file://src/swc_transform.rs#L10-L34)
- [代码生成器:19-43](file://src/codegen.rs#L19-L43)
- [项目编译器:400-599](file://src/project_compiler.rs#L400-L599)
- [独立生成器:15-214](file://src/standalone_gen.rs#L15-L214)

## 架构总览
下图展示 FFI 接口在整体架构中的位置与交互，包括新增的 addon 系统：

```mermaid
sequenceDiagram
participant CLI as "命令行/调用方"
participant Loader as "加载器(loader/src/main.rs)"
participant DLL as "ts-native DLL(tsn_ffi.rs)"
participant RT as "运行时(runtime/src/lib.rs)"
participant Addon as "Addon DLL 系统"
CLI->>Loader : 传入 .ts 或 .obj 文件
Loader->>Loader : 解析参数/选择编译模式
Loader->>DLL : 动态加载并解析导出函数
Loader->>DLL : 调用 tsn_compile(source)
DLL->>DLL : 收集 addon 信息
DLL-->>Loader : 返回 TsnCompileResult含代码/数据/符号/重定位/Addon信息
Loader->>Loader : 复制内存至可执行/只读内存
Loader->>Loader : 应用重定位内部/外部符号
Loader->>Addon : 加载指定的 addon DLL
Loader->>RT : 可选：注册日志回调
Loader->>Loader : 调用入口函数main
Loader-->>CLI : 返回执行结果
```

**图表来源**
- [loader 主程序:337-502](file://loader/src/main.rs#L337-L502)
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [运行时库:423-455](file://runtime/src/lib.rs#L423-L455)
- [项目编译器:549-554](file://src/project_compiler.rs#L549-L554)

## 详细组件分析

### FFI 数据结构与调用约定
- C 结构体与 Rust 结构体一一对应，使用 #[repr(C)] 确保二进制布局一致。
- 关键结构体：
  - TsnSymbol：包含节号、偏移与固定长度名称缓冲。
  - TsnRelocation：包含节号、偏移、重定位类型与目标符号名。
  - **更新** TsnCompileResult：包含代码/数据/Rdata 指针与长度、符号与重定位表、错误信息与上下文、内部上下文指针，**新增 addon_dlls 字段**。
  - **新增** CompileContext：包含所有编译相关的内存，**新增 addon_dlls 字段**。
- 调用约定：
  - 所有导出函数使用 extern "C"，参数与返回值为 C 可互操作类型（裸指针、基本整数、字符指针）。
  - 字符串以 C 风格字符串传递；错误信息通过 C 字符串返回。
  - 结果对象通过裸指针返回，调用方负责释放。

```mermaid
classDiagram
class TsnSymbol {
+uint8 section
+uint32 offset
+[64]u8 name
}
class TsnRelocation {
+uint8 section
+uint32 offset
+uint8 type_
+uint8 _padding
+[64]u8 target_name
}
class TsnCompileResult {
+*u8 code_ptr
+u32 code_len
+*u8 data_ptr
+u32 data_len
+*u8 rdata_ptr
+u32 rdata_len
+*TsnSymbol symbols
+u32 symbol_count
+*TsnRelocation relocations
+u32 reloc_count
+*c_char error_msg
+u32 error_line
+u32 error_col
+*c_char error_context
+*c_void _context
+*c_char addon_dlls
}
class CompileContext {
+Vec~u8~ code
+Vec~u8~ data
+Vec~u8~ rdata
+Vec~TsnSymbol~ symbols
+Vec~TsnRelocation~ relocations
+Option~CString~ error_msg
+Option~CString~ error_context
+Option~CString~ addon_dlls
}
```

**图表来源**
- [tsn_ffi.rs:11-46](file://src/tsn_ffi.rs#L11-L46)
- [tsn_ffi.rs:48-60](file://src/tsn_ffi.rs#L48-L60)

**章节来源**
- [tsn_ffi.rs:9-46](file://src/tsn_ffi.rs#L9-L46)
- [tsn_ffi.rs:48-60](file://src/tsn_ffi.rs#L48-L60)

### 编译函数与结果生命周期
- tsn_compile(source: *const c_char) -> *mut TsnCompileResult
  - 输入校验：空指针与 UTF-8 校验。
  - 编译流程：解析 → 生成原始数据 → 构建代码/数据节区 → 转换符号与重定位 → **收集 addon 信息** → 创建上下文并填充结果。
  - 返回：Box 化的 TsnCompileResult 指针，调用方需后续调用 tsn_free_result 释放。
- tsn_free_result(result: *mut TsnCompileResult)
  - 释放错误信息与上下文（包含所有内存），**包括 addon_dlls 字符串**。
- tsn_version() -> *const c_char
  - 返回静态 C 字符串指针。

```mermaid
sequenceDiagram
participant Caller as "调用方"
participant DLL as "tsn_ffi.rs"
participant Addon as "Addon 系统"
Caller->>DLL : tsn_compile(source)
DLL->>DLL : 参数校验/UTF-8 校验
DLL->>DLL : 解析/生成/构建
DLL->>Addon : 收集 addon DLL 信息
DLL-->>Caller : 返回 *TsnCompileResult
Caller->>DLL : tsn_free_result(result)
DLL->>DLL : 释放错误信息与上下文
DLL->>DLL : 释放 addon_dlls 字符串
```

**图表来源**
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [tsn_ffi.rs:172-305](file://src/tsn_ffi.rs#L172-L305)
- [tsn_ffi.rs:83-113](file://src/tsn_ffi.rs#L83-L113)

**章节来源**
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [tsn_ffi.rs:172-305](file://src/tsn_ffi.rs#L172-L305)
- [tsn_ffi.rs:83-113](file://src/tsn_ffi.rs#L83-L113)

### Addon 信息暴露机制
**新增功能** ts-native 现在支持暴露编译过程中使用的 addon DLL 信息：

- addon_dlls 字段
  - 类型：*mut c_char（C 风格字符串）
  - 格式：逗号分隔的 DLL 名称列表
  - 示例："sharp.dll,sqlite3.dll,opencv4.dll"
  - 生命周期：与 TsnCompileResult 一起释放
- 收集流程
  - 项目编译器从配置中收集所有 native_addons
  - 将 DLL 名称列表转换为 CString
  - 通过 addon_dlls 指针暴露给调用方
- 使用场景
  - 外部加载器需要预加载特定的 addon DLL
  - 调试和诊断目的
  - 动态依赖分析

**章节来源**
- [tsn_ffi.rs:44-45](file://src/tsn_ffi.rs#L44-L45)
- [tsn_ffi.rs:59](file://src/tsn_ffi.rs#L59)
- [tsn_ffi.rs:104-107](file://src/tsn_ffi.rs#L104-L107)
- [tsn_ffi.rs:269-302](file://src/tsn_ffi.rs#L269-L302)
- [项目编译器:549-554](file://src/project_compiler.rs#L549-L554)

### COFF 编译导出（可选特性）
- tsn_compile_coff(source: *const c_char, out_len: *mut u32) -> *mut u8
  - 返回 COFF 字节流指针与长度，调用方需通过 tsn_free_coff(ptr, len) 释放。
- tsn_free_coff(ptr: *mut u8, len: u32)
  - 使用 Vec::from_raw_parts 释放内存。
- 该功能受 feature "coff" 控制。

**章节来源**
- [tsn_ffi.rs:125-178](file://src/tsn_ffi.rs#L125-L178)

### 加载器与外部加载器交互
- 动态加载 DLL 并解析导出函数：
  - tsn_compile、tsn_free_result、可选 tsn_compile_coff、tsn_free_coff。
- 编译流程：
  - 调用 tsn_compile，复制代码/数据节区到本地 Vec，解析符号与重定位。
  - **新增** 检查 addon_dlls 字段，获取需要预加载的 DLL 列表。
- 执行流程：
  - 分配可执行内存与数据内存，复制节区内容。
  - 应用重定位（内部/外部符号），调用入口函数（main）。
- 错误传播：
  - 若返回结果包含错误信息，加载器构造详细错误消息并释放结果。

```mermaid
flowchart TD
Start(["开始"]) --> LoadDLL["加载 DLL 并解析导出函数"]
LoadDLL --> CallCompile["调用 tsn_compile(source)"]
CallCompile --> CheckError{"是否存在错误信息？"}
CheckError --> |是| BuildError["提取错误消息/行列/上下文"]
BuildError --> FreeResult["调用 tsn_free_result"]
FreeResult --> EndErr(["返回错误"])
CheckError --> |否| ExtractAddons["检查 addon_dlls 字段"]
ExtractAddons --> LoadAddons["预加载指定的 addon DLL"]
LoadAddons --> CopySections["复制 code/data/rdata 到本地缓冲"]
CopySections --> ParseSyms["解析符号表"]
ParseSyms --> ParseRelocs["解析重定位表"]
ParseRelocs --> AllocMem["分配可执行/数据内存"]
AllocMem --> ApplyRelocs["应用重定位内部/外部"]
ApplyRelocs --> CallMain["调用入口函数 main"]
CallMain --> Cleanup["释放内存"]
Cleanup --> EndOk(["返回执行结果"])
```

**图表来源**
- [loader 主程序:337-502](file://loader/src/main.rs#L337-L502)
- [loader 主程序:537-743](file://loader/src/main.rs#L537-L743)

**章节来源**
- [loader 主程序:337-502](file://loader/src/main.rs#L337-L502)
- [loader 主程序:537-743](file://loader/src/main.rs#L537-L743)

### 运行时函数与回调处理
- 运行时提供大量 C ABI 函数（字符串、数组、对象、数学、IO 等），供编译产物在执行期调用。
- 日志回调：
  - js_set_log_callback 设置回调函数指针。
  - 运行时在需要时调用回调输出日志。
- 回调签名：extern "C" fn(level: i32, msg: *const c_char)。

**章节来源**
- [运行时库:423-455](file://runtime/src/lib.rs#L423-L455)
- [运行时库:135-800](file://runtime/src/lib.rs#L135-L800)

### C 语言与 Rust 之间的数据交换协议
- 字符串传递：C 风格字符串（*const c_char），UTF-8 编码；错误信息通过 CString 返回。
- 指针与长度：代码/数据节区以指针 + 长度形式返回，调用方负责复制与释放。
- 结构体对齐：#[repr(C)] 确保二进制布局一致。
- 生命周期：结果对象通过裸指针返回，调用方必须遵循释放约定（tsn_free_result / tsn_free_coff）。
- **新增** Addon 信息：addon_dlls 字段提供逗号分隔的 DLL 名称列表，调用方需要正确处理这个字符串。

**章节来源**
- [tsn_ffi.rs:3-4](file://src/tsn_ffi.rs#L3-L4)
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [tsn_ffi.rs:125-178](file://src/tsn_ffi.rs#L125-L178)

### 使用示例与集成指南
- 基本流程
  - 通过命令行参数选择编译模式（.ts 文件自动进入编译模式）。
  - 加载器动态加载 ts-native DLL，调用 tsn_compile 编译 TypeScript 源码。
  - 复制节区数据，应用重定位，调用入口函数 main。
- **更新** Addon 集成流程
  - 检查 TsnCompileResult.addon_dlls 字段获取需要的 DLL 列表。
  - 预加载指定的 addon DLL（支持同目录和当前工作目录搜索）。
  - 确保 DLL 文件存在于预期位置。
- 集成要点
  - 确保 DLL 导出函数存在（tsn_compile、tsn_free_result）。
  - 正确处理错误信息与上下文，避免内存泄漏。
  - 对于外部符号（以 js_ 或 __ 开头），确保运行时库已提供相应实现或插件已加载。
  - **新增** 处理 addon_dlls 字符串，正确解析逗号分隔的 DLL 名称列表。

**章节来源**
- [loader 主程序:42-127](file://loader/src/main.rs#L42-L127)
- [loader 主程序:337-502](file://loader/src/main.rs#L337-L502)
- [独立生成器:136-168](file://src/standalone_gen.rs#L136-L168)

## 依赖分析
- 模块耦合
  - tsn_ffi.rs 依赖 swc_transform 与 codegen，提供编译能力。
  - loader 依赖 tsn_ffi 的导出接口，负责内存管理与重定位。
  - 运行时库与编译产物通过符号名约定（js_*）交互。
  - **新增** 项目编译器依赖 addon 配置系统。
- 外部依赖
  - SWC 生态用于解析 TypeScript。
  - Cranelift 用于代码生成。
  - object crate 用于 COFF 解析。

```mermaid
graph LR
Loader["loader/src/main.rs"] --> FFI["src/tsn_ffi.rs"]
FFI --> SWC["src/swc_transform.rs"]
FFI --> CG["src/codegen.rs"]
Loader --> RT["runtime/src/lib.rs"]
Loader --> COFF["src/coff.rs"]
ProjectCompiler["src/project_compiler.rs"] --> FFI
StandaloneGen["src/standalone_gen.rs"] --> ProjectCompiler
Project["src/project.rs"] --> ProjectCompiler
```

**图表来源**
- [loader 主程序:130-743](file://loader/src/main.rs#L130-L743)
- [tsn_ffi.rs:6-8](file://src/tsn_ffi.rs#L6-L8)
- [SWC 转换器:10-34](file://src/swc_transform.rs#L10-L34)
- [代码生成器:1-200](file://src/codegen.rs#L1-L200)
- [COFF 解析器:1-200](file://src/coff.rs#L1-L200)
- [运行时库:1-800](file://runtime/src/lib.rs#L1-L800)
- [项目编译器:400-599](file://src/project_compiler.rs#L400-L599)
- [独立生成器:15-214](file://src/standalone_gen.rs#L15-L214)
- [项目模块:1-200](file://src/project.rs#L1-L200)

**章节来源**
- [Cargo.toml:22-47](file://Cargo.toml#L22-L47)
- [项目编译器:1-200](file://src/project_compiler.rs#L1-L200)
- [项目模块:1-200](file://src/project.rs#L1-L200)

## 性能考量
- 编译性能统计：编译器在内部记录解析与代码生成阶段耗时，并输出性能摘要。
- 内存管理：加载器复制节区数据到本地缓冲，避免跨模块共享导致的复杂性。
- 重定位效率：按类型应用 REL32/ADDR64，减少运行时开销。
- **新增** Addon 系统性能
  - addon_dlls 字符串的创建和管理开销很小。
  - 预加载 DLL 的成本取决于具体 DLL 的大小和初始化时间。
- 建议
  - 在生产环境中开启日志级别控制，避免过度输出影响性能。
  - 对大型项目采用分模块编译与并行处理策略（项目编译器已提供阶段计时与内存估算）。
  - **新增** 对于大量 addon DLL 的情况，考虑异步预加载策略。

**章节来源**
- [tsn_ffi.rs:172-205](file://src/tsn_ffi.rs#L172-L205)
- [项目编译器:27-121](file://src/project_compiler.rs#L27-L121)

## 故障排查指南
- 常见错误
  - Null source 指针：tsn_compile 返回错误结果，调用方需检查并释放。
  - 非法 UTF-8：tsn_compile 返回错误结果，建议在上游确保字符串编码正确。
  - 重定位失败：外部符号未解析或符号名为空，检查插件加载与符号命名。
  - **新增** Addon DLL 加载失败：检查 DLL 文件是否存在，权限设置，以及兼容性问题。
- 诊断步骤
  - 检查 tsn_compile 返回的错误消息与行列信息。
  - 验证 DLL 导出函数是否可用（tsn_compile、tsn_free_result）。
  - 确认分配的可执行/数据内存大小与内容正确。
  - **新增** 检查 addon_dlls 字段的内容，验证 DLL 名称列表的正确性。
- 释放责任
  - 必须调用 tsn_free_result 释放编译结果。
  - **更新** 释放过程会自动处理 addon_dlls 字符串。
  - 若使用 COFF 编译导出，需调用 tsn_free_coff 释放字节流。
- **新增** Addon 相关故障排查
  - 验证 DLL 文件路径和权限。
  - 检查 DLL 与主程序的架构兼容性（x86/x64）。
  - 确认 DLL 的依赖项已满足。

**章节来源**
- [tsn_ffi.rs:66-80](file://src/tsn_ffi.rs#L66-L80)
- [tsn_ffi.rs:294-325](file://src/tsn_ffi.rs#L294-L325)
- [loader 主程序:387-413](file://loader/src/main.rs#L387-L413)
- [loader 主程序:632-711](file://loader/src/main.rs#L632-L711)

## 结论
ts-native 的 FFI 接口以稳定 ABI 为核心，结合清晰的内存管理约定与错误传播机制，实现了从 TypeScript 到原生代码的高效编译与执行。通过加载器与运行时的协作，开发者可以安全地集成 ts-native 的编译能力，并在 C 与 Rust 之间建立可靠的互操作通道。

**更新** 新增的 addon 信息暴露功能进一步增强了 ts-native 的生态系统集成能力，允许外部调用者获取编译过程中使用的第三方 DLL 信息，为更复杂的插件架构提供了基础支持。

建议在实际工程中严格遵循释放约定、输入校验与边界条件处理，以获得最佳的稳定性与性能表现。对于使用 addon 功能的项目，还需要额外关注 DLL 的部署和兼容性问题。

## 附录
- 相关文档
  - [架构设计:1-184](file://docs/架构设计/架构设计.md#L1-L184)
- 示例项目
  - [主程序示例:1-15](file://test_multi_entry/src/main.ts#L1-L15)
- **新增** Addon 配置示例
  - 在项目配置文件中添加 native_addons 段落，指定 DLL 名称和函数映射。
  - 编译时自动收集并暴露 addon 信息给外部加载器。