# FFI 外部函数接口

<cite>
**本文引用的文件**
- [tsn_ffi.rs](file://src/tsn_ffi.rs)
- [tsn_abi.h](file://tsn_abi.h)
- [lib.rs](file://src/lib.rs)
- [Cargo.toml](file://Cargo.toml)
- [README.md](file://README.md)
- [ARCHITECTURE.md](file://ARCHITECTURE.md)
- [runtime/lib.rs](file://runtime/src/lib.rs)
</cite>

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

## 简介
本文件为 ts-native 的 FFI 外部函数接口（C 调用约定）完整 API 文档，覆盖以下内容：
- 外部函数定义与调用约定
- 数据结构 TsnCompileResult、TsnSymbol、TsnRelocation 的字段与用法
- C 调用约定与数据类型映射关系
- 不同语言绑定的使用示例（C、Python、Go）
- 内存管理策略与生命周期注意事项
- 错误码与错误上下文说明
- 性能优化建议与最佳实践
- 跨语言使用的正确性与安全性保障

## 项目结构
ts-native 通过一个 C 头文件暴露稳定的 ABI，并由 Rust 实现具体逻辑。FFI 接口位于 C 头文件与 Rust 模块之间，形成“头文件定义 + Rust 实现”的双端契约。

```mermaid
graph TB
A["C 头文件<br/>tsn_abi.h"] --> B["Rust FFI 模块<br/>src/tsn_ffi.rs"]
B --> C["编译管线与运行时<br/>src/codegen.rs / src/swc_transform.rs"]
B --> D["运行时导出函数<br/>runtime/src/lib.rs"]
E["库入口 re-export<br/>src/lib.rs"] --> B
F["构建配置<br/>Cargo.toml"] --> B
```

图表来源
- [tsn_abi.h:1-92](file://tsn_abi.h#L1-L92)
- [tsn_ffi.rs:1-341](file://src/tsn_ffi.rs#L1-L341)
- [lib.rs:1-17](file://src/lib.rs#L1-L17)
- [Cargo.toml:1-57](file://Cargo.toml#L1-L57)

章节来源
- [tsn_abi.h:1-92](file://tsn_abi.h#L1-L92)
- [tsn_ffi.rs:1-341](file://src/tsn_ffi.rs#L1-L341)
- [lib.rs:1-17](file://src/lib.rs#L1-L17)
- [Cargo.toml:1-57](file://Cargo.toml#L1-L57)

## 核心组件
- 外部函数（C 调用约定）
  - tsn_compile：编译 TypeScript 源码为 TSN 模块，返回 TsnCompileResult 指针
  - tsn_compile_coff（可选，coff feature）：编译为标准 COFF .obj 字节流
  - tsn_free_result：释放 tsn_compile 返回的结果
  - tsn_free_coff（可选，coff feature）：释放 tsn_compile_coff 返回的字节流
  - tsn_version：获取版本字符串
- 数据结构
  - TsnCompileResult：包含代码段、数据段、只读数据段、符号表、重定位表、错误信息等
  - TsnSymbol：符号条目（节区、偏移、名称）
  - TsnRelocation：重定位条目（节区、偏移、类型、目标符号）

章节来源
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [tsn_ffi.rs:115-170](file://src/tsn_ffi.rs#L115-L170)
- [tsn_ffi.rs:27-44](file://src/tsn_ffi.rs#L27-L44)
- [tsn_ffi.rs:11-25](file://src/tsn_ffi.rs#L11-L25)
- [tsn_ffi.rs:11-16](file://src/tsn_ffi.rs#L11-L16)

## 架构总览
ts-native 的 FFI 层负责将 Rust 的编译产物以稳定 ABI 暴露给外部加载器（loader）。C 头文件定义了数据结构与函数签名，Rust 模块实现具体逻辑，并通过 #[no_mangle] extern "C" 导出。

```mermaid
sequenceDiagram
participant Loader as "外部加载器"
participant CABI as "C ABI 头文件"
participant FFI as "Rust FFI 模块"
participant CG as "编译管线"
participant RT as "运行时导出"
Loader->>CABI : 包含 tsn_abi.h
Loader->>FFI : 调用 tsn_compile(source)
FFI->>CG : 解析/生成/提取节区/符号/重定位
CG-->>FFI : 原始数据函数/数据/符号/重定位
FFI-->>Loader : 返回 TsnCompileResult*
Loader->>FFI : 调用 tsn_free_result(result)
FFI-->>Loader : 释放内部内存
```

图表来源
- [tsn_abi.h:62-86](file://tsn_abi.h#L62-L86)
- [tsn_ffi.rs:60-106](file://src/tsn_ffi.rs#L60-L106)
- [tsn_ffi.rs:172-292](file://src/tsn_ffi.rs#L172-L292)

## 详细组件分析

### 外部函数 API
- tsn_compile
  - 输入：const char* source（UTF-8，以 null 结尾）
  - 输出：TsnCompileResult*（调用者需调用 tsn_free_result 释放）
  - 行为：解析 TypeScript，生成原生代码与数据，填充 TsnCompileResult；若失败返回错误信息与上下文
- tsn_compile_coff（feature: coff）
  - 输入：const char* source，uint32_t* out_len
  - 输出：uint8_t*（调用者需调用 tsn_free_coff 释放）
  - 行为：编译为标准 COFF .obj 字节流
- tsn_free_result
  - 输入：TsnCompileResult* result
  - 行为：释放 result 及其内部错误信息与上下文
- tsn_free_coff（feature: coff）
  - 输入：uint8_t* ptr, uint32_t len
  - 行为：释放 tsn_compile_coff 返回的字节流
- tsn_version
  - 输出：const char*（静态版本字符串）

章节来源
- [tsn_ffi.rs:60-113](file://src/tsn_ffi.rs#L60-L113)
- [tsn_ffi.rs:115-170](file://src/tsn_ffi.rs#L115-L170)
- [tsn_abi.h:62-86](file://tsn_abi.h#L62-L86)

### 数据结构定义与字段说明
- TsnCompileResult
  - code_ptr, code_len：代码段指针与长度
  - data_ptr, data_len：数据段指针与长度
  - rdata_ptr, rdata_len：只读数据段指针与长度
  - symbols, symbol_count：符号表指针与数量
  - relocations, reloc_count：重定位表指针与数量
  - error_msg, error_line, error_col, error_context：错误信息与上下文
  - _context：内部上下文指针（Rust 分配的内存，供 tsn_free_result 释放）
- TsnSymbol
  - section：节区索引（0=.text, 1=.data, 2=.rdata, 255=external）
  - offset：在节区内的偏移
  - name[64]：符号名称（以 null 结尾）
- TsnRelocation
  - section：节区索引
  - offset：需要重定位的位置
  - type_：重定位类型（0=REL32, 1=ADDR64）
  - _padding：对齐填充
  - target_name[64]：目标符号名称（字符串形式）

章节来源
- [tsn_ffi.rs:27-44](file://src/tsn_ffi.rs#L27-L44)
- [tsn_ffi.rs:11-25](file://src/tsn_ffi.rs#L11-L25)
- [tsn_abi.h:30-60](file://tsn_abi.h#L30-L60)
- [tsn_abi.h:14-28](file://tsn_abi.h#L14-L28)

### C 调用约定与数据类型映射
- 调用约定：extern "C"，函数名不进行 Rust 名称修饰（#[no_mangle]）
- 数据类型映射（C ↔ Rust）：
  - const char* ↔ *const c_char
  - uint8_t* ↔ *mut u8
  - uint32_t ↔ u32
  - void* ↔ *mut c_void
  - struct* ↔ *mut struct（C 结构体与 #[repr(C)] Rust 结构体一一对应）
- 对齐与布局：结构体均使用 #[repr(C)]，保证与 C 头文件一致

章节来源
- [tsn_ffi.rs:3-4](file://src/tsn_ffi.rs#L3-L4)
- [tsn_ffi.rs:11-25](file://src/tsn_ffi.rs#L11-L25)
- [tsn_abi.h:7-9](file://tsn_abi.h#L7-L9)

### 内存管理策略与生命周期
- tsn_compile 返回的 TsnCompileResult* 必须由调用者持有并在不再使用时调用 tsn_free_result 释放
- tsn_compile_coff 返回的字节流必须由调用者持有并在不再使用时调用 tsn_free_coff 释放
- 错误信息（error_msg、error_context）由 Rust 分配，释放时会回收
- _context 字段为内部上下文指针，仅用于 tsn_free_result 释放相关内存
- 生命周期要点：
  - 仅在 tsn_free_result 之前读取 symbols/relocations/code/data/rdata 指针
  - 不要自行释放这些指针指向的内存
  - 若出现错误，错误上下文长度固定为最后 60 字符

章节来源
- [tsn_ffi.rs:83-106](file://src/tsn_ffi.rs#L83-L106)
- [tsn_ffi.rs:152-160](file://src/tsn_ffi.rs#L152-L160)
- [tsn_ffi.rs:294-325](file://src/tsn_ffi.rs#L294-L325)

### 错误处理与错误上下文
- 错误信息提取：
  - error_msg：UTF-8 字符串，调用者无需释放
  - error_line：从错误消息中提取的行号（若无法提取则为 0）
  - error_context：错误上下文（最后 60 字符）
- 常见错误场景：
  - source 为 null
  - source 不是有效的 UTF-8
  - 解析/编译失败
- 建议：
  - 在调用 tsn_compile 前校验输入
  - 在 tsn_free_result 之后不再使用任何指针

章节来源
- [tsn_ffi.rs:66-81](file://src/tsn_ffi.rs#L66-L81)
- [tsn_ffi.rs:294-325](file://src/tsn_ffi.rs#L294-L325)
- [tsn_ffi.rs:327-340](file://src/tsn_ffi.rs#L327-L340)

### 性能与可观测性
- 编译阶段计时与统计：
  - 解析阶段、代码生成阶段、总耗时
  - 函数数量、字符串数量
  - SourceMap 条目摘要
- 建议：
  - 合理缓存编译结果
  - 在 CI 中关注阶段耗时与内存峰值
  - 使用 feature: coff 时注意字节流的生命周期管理

章节来源
- [tsn_ffi.rs:172-205](file://src/tsn_ffi.rs#L172-L205)

### 运行时导出（与 FFI 协作）
- 运行时导出函数（C 调用约定）用于与编译后的代码交互，例如字符串、数组、对象、数学函数等
- 这些函数与 FFI 接口共同构成 ts-native 的运行时能力边界

章节来源
- [runtime/lib.rs:137-200](file://runtime/src/lib.rs#L137-L200)
- [runtime/lib.rs:425-455](file://runtime/src/lib.rs#L425-L455)

## 依赖关系分析
- 头文件与实现的一致性：C 头文件定义的数据结构与 Rust 的 #[repr(C)] 结构体保持字段顺序与类型一致
- 构建配置：库类型为 cdylib 与 rlib，便于外部以 DLL 方式加载
- 特性开关：coff feature 控制 tsn_compile_coff 与 tsn_free_coff 的可用性

```mermaid
graph LR
H["tsn_abi.h"] --> R["src/tsn_ffi.rs"]
R --> L["src/lib.rs"]
R --> CFG["Cargo.toml"]
R --> RT["runtime/src/lib.rs"]
```

图表来源
- [tsn_abi.h:1-92](file://tsn_abi.h#L1-L92)
- [tsn_ffi.rs:1-341](file://src/tsn_ffi.rs#L1-L341)
- [lib.rs:1-17](file://src/lib.rs#L1-L17)
- [Cargo.toml:17-21](file://Cargo.toml#L17-L21)

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

## 性能考量
- 避免重复编译：对相同源码复用编译结果
- 控制内存峰值：及时调用释放函数，避免长时间持有大块内存
- COFF 输出：使用 feature: coff 时，注意字节流的生命周期与拷贝成本
- 统计与监控：利用编译阶段计时与统计指标优化构建流程

## 故障排除指南
- 常见问题
  - tsn_compile 返回空指针：检查 source 是否为 null 或 UTF-8 无效
  - 读取 symbols/relocations 指针崩溃：确认在 tsn_free_result 之前使用
  - 错误信息为空：确认错误提取逻辑与消息格式
- 调试建议
  - 开启日志：TSN_LOG 环境变量初始化日志
  - 检查版本：tsn_version 返回当前版本字符串
  - 核对 ABI：确保 C 头文件与 Rust 结构体一致

章节来源
- [tsn_ffi.rs:63-68](file://src/tsn_ffi.rs#L63-L68)
- [tsn_ffi.rs:108-113](file://src/tsn_ffi.rs#L108-L113)
- [tsn_ffi.rs:172-196](file://src/tsn_ffi.rs#L172-L196)

## 结论
ts-native 的 FFI 接口通过清晰的 C ABI 与严格的内存管理策略，为外部加载器提供了稳定、可移植的编译能力。遵循本文的调用约定、内存管理与错误处理规范，可在不同语言环境中安全高效地使用该接口。

## 附录

### C 语言绑定使用示例（概念性）
- 加载 DLL 并调用 tsn_compile
- 读取 TsnCompileResult 的节区与符号
- 调用 tsn_free_result 释放资源

### Python 绑定使用示例（ctypes 概念性）
- 使用 ctypes.CDLL 加载 DLL
- 定义 TsnCompileResult、TsnSymbol、TsnRelocation 结构体
- 调用 tsn_compile 并处理返回值
- 调用 tsn_free_result 释放

### Go 绑定使用示例（cgo 概念性）
- 使用 // #include "tsn_abi.h" 引入头文件
- 定义 Go 结构体映射 C 结构体
- 调用 tsn_compile 并释放结果

### 最佳实践清单
- 始终校验输入参数（source 非空、UTF-8 有效）
- 严格遵守释放顺序：先读取数据，再调用释放函数
- 使用 feature: coff 时，配合 tsn_free_coff 释放字节流
- 在 CI 中观察阶段耗时与内存峰值，持续优化