Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 216 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
[<img src="https://img.shields.io/github/actions/workflow/status/esrrhs/fakelua/build_with_windows.yml?branch=master&label=Windows">](https://github.com/esrrhs/fakelua/actions/workflows/build_with_windows.yml)
[![codecov](https://codecov.io/gh/esrrhs/fakelua/graph/badge.svg?token=9ZCUH1Q632)](https://codecov.io/gh/esrrhs/fakelua)

FakeLua 是一个可嵌入的 Lua 子集执行引擎,将 Lua 脚本编译为 C 代码,再由 TinyCC 或 GCC 生成动态库加载执行
FakeLua 是一个可嵌入的 Lua 子集编译引擎:将 Lua 脚本编译为 C 代码,通过 TinyCC 或 GCC 后端动态编译,生成机器码加载执行。提供 C++23 接口,支持脚本与原生代码高效互操作

## 技术亮点
## 核心特性

### 双 JIT 后端

Expand All @@ -27,6 +27,12 @@ FakeLua 是一个可嵌入的 Lua 子集执行引擎,将 Lua 脚本编译为 C

以递归 Fibonacci(n=32)为例,GCC 后端比 Lua 5.4 快 **9x**,TCC 后端快 **1.9x**(详见 [benchmark/README.md](benchmark/README.md))。

### 自动类型推导

- 静态分析 Lua 脚本,自动推导函数参数和返回值类型
- 生成高效的类型化 C 代码,消除动态类型装箱开销
- 支持根据调用上下文自动生成 int64/double 专特化版本

### CVar:ABI 安全的跨边界值类型

```cpp
Expand All @@ -45,17 +51,87 @@ static_assert(std::is_trivially_copyable_v<CVar>);

`VarInterface` 是 Lua table 等复杂类型与宿主之间的抽象接口,宿主可按需实现自己的版本接入原有对象系统。库内附带 `SimpleVarImpl` 开箱即用。

### C++ 嵌入 API

- `CompileFile` / `CompileString` / `Call`,RAII 风格 `FakeluaStateGuard`
- 支持基本类型、对象、以及自定义 VarInterface 实现的高级映射
- 支持记录编译生成的 C 代码用于调试和性能分析(`CompileConfig::record_c_code`)

## 当前已知限制

### 语法限制
- 不支持多返回值(Call 仅支持单返回值,多返回可通过 Table 实现)
- 不支持 varargs(`...`)
- 不支持 `label` / `goto`
- 泛型 `for in` 仅支持 `pairs()` / `ipairs()`
- 脚本侧函数调用仅支持简单函数名调用(不支持复杂前缀表达式调用,如 `obj:method()` 需通过间接方式实现)

### 初始化约束
- 全局变量初始化不支持 table constructor
- 全局变量初始化不支持部分复杂表达式
- 文件级 local 变量仅支持数值类型(T_INT/T_FLOAT)和 nil/bool/string 的特定初始化

### 类型系统限制
- 类型推导基于静态分析,复杂的动态类型操作无法优化
- 函数 specialization 基于调用点的 math 参数发现
- 函数参数上限 8 个

## 快速上手

### 构建

#### 系统要求
- **C++23** 编译器(GCC 11+ / Clang 16+ / MSVC 2022+)
- CMake 3.5+
- make 或 ninja

#### Linux / macOS

```bash
cmake -S . -B build
cmake --build build --parallel
```

> macOS 需先 `brew install lua cmake`,并在 cmake 时加 `-DCMAKE_PREFIX_PATH="$(brew --prefix)"`。

仅构建核心库与命令行工具(不含测试/基准):

```bash
cmake --build build --target fakelua flua --parallel
```

#### Windows(MSYS2 + MinGW)

```bash
cmake -S . -B build -G Ninja
cmake --build build --parallel
ctest --test-dir build -V
```

### 测试与基准

```bash
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build --parallel
ctest --test-dir build -V
./build/bin/bench_mark
```

> 单元测试与 benchmark 依赖 Lua 开发包(头文件 `lua.h` 和库文件)。
> - 在 Linux 上:`sudo apt-get install liblua5.4-dev` 或 `liblua5.3-dev`
> - 在 macOS 上:`brew install lua`
> - 在 Windows MSYS2 上:`pacman -S mingw-w64-x86_64-lua`

### 命令行工具 `flua`

```bash
./build/bin/flua <script.lua> --entry=<func> --jit_type=<0|1> --repeat=<N>
```

- `--entry`:入口函数名(默认 `main`)
- `--jit_type`:`0`=TCC,`1`=GCC
- `--repeat`:重复调用次数(用于性能测量)

### C++ 嵌入示例

```cpp
Expand All @@ -75,15 +151,6 @@ int main() {

`Call()` 支持最多 8 个参数,参数与返回值在原生 C++ 类型与 `CVar` 之间自动转换。

### 命令行工具 `flua`

```bash
./build/bin/flua <script.lua> --entry=<func> --jit_type=<0|1> --repeat=<N>
```

- `--jit_type`:`0`=TCC,`1`=GCC
- `--repeat`:重复调用次数(用于性能测量)

## 性能基准

对比 C++、Lua 5.4、FakeLua TCC、FakeLua GCC,覆盖 Fibonacci、GCD、快速幂、线性求和、冒泡排序、筛质数等 11 类算法(Release `-O3` 模式):
Expand All @@ -98,8 +165,142 @@ int main() {

> TCC 纯计算类场景(无 table)普遍快于 Lua;含大量 table 操作时 GCC 与 Lua 持平,TCC 偏慢(table 操作尚未特化)。完整数据见 [benchmark/README.md](benchmark/README.md)。

## 已知限制
## C++ API 详细文档

- 不支持多返回值、varargs(`...`)、`label`/`goto`
- 泛型 `for in` 仅支持 `pairs()` / `ipairs()`
- 函数参数上限 8 个
### 状态管理

```cpp
// 手动管理(不推荐,容易泄漏)
State* s = FakeluaNewState(StateConfig{});
// ... 使用 s ...
FakeluaDeleteState(s);

// 或使用 RAII 风格(推荐)
FakeluaStateGuard guard(StateConfig{});
State* s = guard.GetState();
// ... 使用 s ...
// 自动释放
```

### API 概览

| 函数 | 功能 |
|------|------|
| `FakeluaNewState()` | 创建 FakeLua 状态 |
| `FakeluaDeleteState()` | 释放 FakeLua 状态 |
| `CompileFile()` | 编译 Lua 文件 |
| `CompileString()` | 编译 Lua 代码字符串 |
| `Call()` | 调用编译后的函数 |
| `GetLastRecordedCCode()` | 获取最近编译的 C 代码 |
| `SetVarInterfaceNewFunc()` | 设置自定义 VarInterface 工厂 |
| `SetDebugLogLevel()` | 设置全局调试日志级别 |

### 类型转换

FakeLua 提供 `inter::NativeToFakelua()` 和 `FakeluaToNative()` 自动推导型转换:

```cpp
// 原生 → FakeLua
CVar v_int = inter::NativeToFakelua(s, 42);
CVar v_str = inter::NativeToFakelua(s, std::string("hello"));
CVar v_bool = inter::NativeToFakelua(s, true);

// FakeLua → 原生
int native_int = inter::FakeluaToNative<int>(v_int);
std::string native_str = inter::FakeluaToNative<std::string>(v_str);
```

### Table 与对象互转

通过实现 `VarInterface` 可实现 Lua table 与原生对象的双向映射:

```cpp
class CustomVar : public VarInterface {
// 实现所有虚函数...
};

// 注册工厂函数
SetVarInterfaceNewFunc(s, []() { return new CustomVar(); });

// 之后在 Call 中传递的 table 类型参数会自动构造为 CustomVar 实例
```

## 架构概览

### 编译流程

```
Lua 源码
[词法分析] → tokens (flexer)
[语法分析] → AST (bison + syntax_tree)
[预处理] → normalized AST (preprocessor)
[类型推导] → type hints (type_inferencer)
[C 代码生成] → C 源码 (c_gen)
[JIT 编译] → 机器码 (tcc_jit / gcc_jit)
[加载执行] → 结果
```

### 关键组件

| 模块 | 职责 |
|------|------|
| `lexer/parser` | Lua 词法和语法解析 |
| `syntax_tree` | AST 表示和遍历 |
| `preprocessor` | Lua 语法规范化(如 functiondef 提升) |
| `type_inferencer` | 静态类型推导和 specialization 决策 |
| `c_gen` | C 代码生成和类型驱动优化 |
| `compile_common` | 公共类型推导和代码生成工具 |
| `jit/*` | TCC 和 GCC 后端集成 |
| `state` | FakeLua 运行时状态管理 |
| `var` | 动态值 CVar 和转换工具 |

## 项目结构

```
fakelua/
├── include/
│ └── fakelua.h # 公共 C++ API
├── src/
│ ├── compile/ # Lua 编译器实现
│ │ ├── c_gen.h/cpp # C 代码生成
│ │ ├── type_inferencer.h/cpp # 类型推导
│ │ ├── preprocessor.h/cpp # 预处理
│ │ ├── syntax_tree.h/cpp # AST
│ │ └── ...
│ ├── jit/ # JIT 后端
│ │ ├── tcc_jit.h/cpp # TinyCC 后端
│ │ ├── gcc_jit.h/cpp # GCC 后端
│ │ ├── vm.h/cpp # 虚拟机
│ │ └── ...
│ ├── state/ # 运行时状态
│ ├── var/ # 动态值和转换
│ └── util/ # 工具函数
├── test/ # 单元测试
├── benchmark/ # 性能基准
├── cmd/ # 命令行工具 flua
└── cmake/ # CMake 配置
```

## 常见问题

### Q: 为什么选择 Lua 子集而不是完整 Lua?
A: 完整 Lua 的动态特性(如 metatable、varargs、多返回值)很难高效编译。子集实现聚焦于可静态分析的常见模式,通过类型推导和 JIT 编译获得接近 C 的性能。

### Q: TCC 和 GCC 后端如何选择?
A: **TCC** 快速编译(适合脚本小、编译频繁);**GCC** 优化充分(适合脚本大、运行次数多)。在同一 API 下可根据场景动态选择。

### Q: 可以在嵌入式或受限环境中使用吗?
A: 可以,TCC 后端体积小,编译速度快,适合嵌入式。核心库依赖极少(仅 C++ 标准库),可交叉编译。

### Q: 如何调试生成的 C 代码?
A: 启用 `CompileConfig::debug_mode`,查看日志和 C 代码;使用 `GetLastRecordedCCode()` 导出 C 代码进行分析。

### Q: 支持多线程吗?
A: 每个 `State` 当前为线程本地对象,多线程环境中应为每个线程创建独立的 `State`。
Loading