当前位置: 首页 > news >正文

【lua】Windows环境下cffi-lua使用指南:编译、安装与测试

▒ 目录 ▒

    • 🛫 导读
    • 环境
      • 需求
    • 1️⃣ Windows下cffi-lua基础认知
      • 1.1 核心特性(Windows适配)
      • 1.2 必备依赖(Windows环境)
    • 2️⃣ Windows下编译指南(MSVC环境)
      • 2.1 步骤1:准备依赖文件(关键!)
        • 步骤2:配置 meson 编译参数
        • 步骤3:执行编译
    • 3️⃣ Windows下安装与测试
      • 3.1 安装:让Lua找到cffi模块
        • 方式1:手动复制(简单)
        • 方式2:通过 ninja install 自动安装(推荐)
      • 3.2 测试:验证cffi-lua功能
        • 测试1:调用 C 标准库(printf/abs)
        • 测试2:调用 Windows API(MessageBoxA)
      • 3.3 批量测试:运行官方测试用例
    • 4️⃣ Windows特有注意事项与避坑指南
      • 4.1 编译位数匹配(关键!)
      • 4.2 libffi 处理方案(默认就是静态的)
      • 4.3 Lua 链接差异(Windows vs Unix)
      • 4.4 常见编译错误解决
        • 4.4.1 lua.hh(23): fatal error C1083: 无法打开包括文件: “lua.hpp”
        • 4.4.2 src_ffi.cc.obj : error LNK2001: 无法解析的外部符号 `__imp__lua_gettop`
    • 5️⃣ 测试:验证 cffi-lua 功能
      • 5.1 环境准备
      • 5.2 测试 1:调用 C 标准库(printf/abs)
      • 5.3 测试 2:测试 2:调用 Windows API(MessageBoxA)
    • 🛬 文章小结
    • 📖 参考资料

@[TOC]( ▒ 目录 ▒)

🛫 导读

环境

版本号描述
文章日期2025-09-17
操作系统Win11 - 24H226110.4061
VS2022
Lua5.1.5小编要分析某游戏的环境为5.1.5
archx86小编要分析某游戏的环境为x86
libffi9f2acc9
python3.9.9小编使用的meson基于python环境
meson16.2.1
ninjavs自带的

需求

cffi-lua 是基于 libffi 的跨平台 Lua FFI 库,核心价值是为标准 Lua(5.1+,非 LuaJIT) 提供便捷的 C 库调用能力,且兼容 Windows 系统。在 Windows 开发中,常需解决“标准 Lua 调用系统 API/C 库”的需求(如硬件接口、高性能计算),而 cffi-lua 可替代传统 C 扩展模块(无需手动编译 DLL),通过动态绑定实现快速集成。

本文聚焦 Windows 环境,详细讲解 cffi-lua 的依赖准备、MSVC环境编译、安装配置及测试流程,解决 Windows 下“依赖缺失”“编译位数不匹配”“库链接失败”等常见问题。

1️⃣ Windows下cffi-lua基础认知

需先明确 cffi-lua 在 Windows 下的核心特性与依赖,为后续操作铺垫。

1.1 核心特性(Windows适配)

  • 兼容性:支持标准 Lua 5.1~5.4 ,无需修改代码即可在不同 Lua 版本间迁移;
  • 跨架构:适配 Windows x86(32位)、x64(64位)架构,需确保编译产物与 Lua 位数一致;
  • 调用约定:自动处理 Windows 特有调用约定(如 x86 的 stdcall),无需手动声明;
  • libffi 集成:支持手动提供 libffi 或通过 meson 子项目自动拉取(解决 Windows 下 libffi 安装难问题)。

1.2 必备依赖(Windows环境)

依赖项说明推荐版本
C++ 编译器需支持 C++14,可选 MSVC 或 MinGW(二选一)VS2017+ / MinGW-w64 8.0+
Lua 环境标准 Lua 5.1~5.4(需包含头文件、导入库 .lib、动态库 .dllLua 5.4.6
libffi外部函数调用库,可选“手动提供”或“meson 自动拉取”libffi 3.4.4+
meson构建工具,用于生成编译配置(替代 Makefile)meson 1.2.0+
ninja编译执行工具,配合 meson 高效编译ninja 1.11.1+

依赖安装提示:

  • meson:通过python安装:pip install meson

  • ninja:直接使用VS自带的(或vcpkg安装的)即可

    • D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja\ninja.exe
  • Lua:从 Lua 官网 下载 Windows 源码编译(需生成 .lib.dll);或者直接在sourceforge下载用对应编译器编译,或使用 LuaForWindows 预编译包。

ps: meson/ninja:也可以通过 Chocolatey 安装(choco install meson ninja),或直接下载 预编译包 并添加到系统 PATH

2️⃣ Windows下编译指南(MSVC环境)

Windows 下 cffi-lua 支持两种主流编译环境:MSVC(Visual Studio 工具链)和 MinGW(类 Unix 工具链),我们这里选择MSVC环境。

2.1 步骤1:准备依赖文件(关键!)

需将 Lua (使用前文中提到的下载好的压缩包lua-5.1.5_Win32_vc17_lib.zip)和 libffi (小编未处理libffi库,由meson自动拉取)的文件按约定放入 deps 目录(解决 meson 自动查找问题),目录结构如下:

cffi-lua源码根目录/
├─ deps/                # 依赖存放目录(手动创建)
│  ├─ include/          # 头文件目录
│  │  ├─ lua.h          # Lua 头文件(来自 Lua 安装目录的 include 文件夹)
│  │  ├─ lua.hpp
│  │  ├─ lauxlib.h
│  │  ├─ lauconf.h
│  │  ├─ laulib.h
│  │  ├─ ffi.h          # libffi 头文件(可选,不提供则 meson 自动拉取)
│  │  └─ ffitarget.h    # libffi 头文件(可选,不提供则 meson 自动拉取)
│  ├─ lua5.1.lib         # Lua 导入库(32/64位需与编译目标一致)
│  ├─ lua5.1.dll         # Lua 动态库
│  └─ lua.exe           # Lua 可执行文件(用于后续测试)
└─ build/               # 编译输出目录(编译过程自动创建)

在这里插入图片描述

说明:若不提供 libffi 头文件和库,meson 会自动下载 libffi 子项目并静态链接,无需额外操作。

步骤2:配置 meson 编译参数
  1. 打开“VS 开发命令提示符”(如“x64 Native Tools Command Prompt for VS 2022”,对应 64 位编译;32 位选“x86”版本);

在这里插入图片描述

  1. 进入 cffi-lua 源码根目录,执行以下命令进入编译目录并配置 meson:

    # 根据官网文档,需要切换到build目录
    cd build
    meson .. -Dlua_version=5.1  -Dtests=false
    
    • 参数说明:
      • -Dlua_version=vendor:指定从 deps 目录读取 Lua 依赖(匹配步骤1的目录结构);
      • -Dtests=false:指定不处理test内容
      • -Dshared_libffi=false:强制静态链接 libffi(Windows 推荐,避免依赖额外的 libffi-8.dll);
      • 若需编译 64 位版本,需在“x64 Native Tools Command Prompt for VS 2022”中执行,无需额外参数。
步骤3:执行编译

在 build 目录下执行 ninja all, meson 会自动生成 VS 工程文件并编译,最终产物为 build/cffi.dll(Lua 可加载模块)。

3️⃣ Windows下安装与测试

编译完成后需将 cffi.dll 安装到 Lua 可识别路径,或通过环境变量指定,再验证功能是否正常。

3.1 安装:让Lua找到cffi模块

有两种安装方式,根据需求选择:

方式1:手动复制(简单)

build/cffi.dll 复制到以下任一目录(Lua 会自动在这些路径查找模块):

  • Lua 安装目录的 clibs 文件夹(如 C:\Lua54\clibs);
  • 与 Lua 脚本同一目录(适合临时测试);
  • 系统环境变量 PATH 包含的目录(如 C:\Windows\System32,不推荐,易冲突)。
方式2:通过 ninja install 自动安装(推荐)
  1. 在编译目录(build)下执行:

    ninja install
    
  2. 默认安装路径为 %LUA_CPATH% 对应的目录(如 Lua 5.1 会安装到 C:\Lua54\clibs),无需手动复制;

  3. 若需自定义安装路径,可在 meson 配置时添加 -Dlua_install_path=自定义路径(如 -Dlua_install_path=C:\my-lua-modules\@0@@0@ 会自动替换为 Lua 版本,如 5.1)。

3.2 测试:验证cffi-lua功能

通过简单脚本测试“调用 C 标准库”和“Windows API”,确保模块正常工作。

测试1:调用 C 标准库(printf/abs)

创建 test_c_std.lua 脚本:

local cffi = require("cffi")-- 声明 C 标准库函数(msvcrt.dll 为 Windows 内置 C 库)
cffi.cdef[[#include <stdio.h>#include <stdlib.h>int printf(const char *format, ...);int abs(int x);
]]-- 加载 C 标准库
local msvcrt = cffi.load("msvcrt")-- 调用函数
msvcrt.printf("cffi-lua 测试:abs(-10) = %d\n", msvcrt.abs(-10))  -- 输出:abs(-10) = 10
print("C 标准库调用成功!")

执行脚本(需确保 Lua 可执行文件在 PATH 中):

lua test_c_std.lua

若输出“C 标准库调用成功!”,说明基础功能正常。

测试2:调用 Windows API(MessageBoxA)

创建 test_win_api.lua 脚本(验证 Windows 特有 API 调用):

local cffi = require("cffi")-- 声明 Windows API 类型和函数(来自 user32.dll)
cffi.cdef[[typedef void* HWND;enum {MB_OK = 0x00000000L,MB_ICONINFORMATION = 0x00000040L};int MessageBoxA(HWND hWnd, const char *lpText, const char *lpCaption, unsigned int uType);
]]-- 加载 user32.dll(Windows 窗口相关 API 库)
local user32 = cffi.load("user32")-- 调用 MessageBoxA 弹出窗口
user32.MessageBoxA(nil, "cffi-lua 调用 Windows API 成功!", "测试提示", cffi.C.MB_OK + cffi.C.MB_ICONINFORMATION)

执行脚本后,若弹出 Windows 标准消息框,说明 Windows API 调用正常。

3.3 批量测试:运行官方测试用例

cffi-lua 源码自带测试用例,可验证完整功能:

  1. 进入 cffi-lua 源码的 tests 目录;

  2. 执行测试 runner 脚本(需指定 TESTLIB_PATH 为编译生成的测试库路径,通常在 build/tests):

    set TESTLIB_PATH=D:\cffi-lua\build\tests
    lua runner.lua basic.lua  -- 运行基础测试用例
    
  3. 若所有测试用例返回 0(成功),说明 cffi-lua 在 Windows 下功能完整。

4️⃣ Windows特有注意事项与避坑指南

4.1 编译位数匹配(关键!)

  • 若 Lua 为 64 位,cffi-lua 必须编译为 64 位(需用“x64 VS 开发命令提示符”或“MinGW 64-bit”终端);
  • 若编译 32 位,需对应 32 位 Lua 和 32 位编译器,否则会出现“模块不是有效的 Win32 应用程序”错误;
  • 验证位数:通过 lua -v 查看 Lua 位数(如 Lua 5.1.6 64-bit),或使用die等工具查看。

4.2 libffi 处理方案(默认就是静态的)

  • 推荐静态链接 libffi( meson 配置时 -Dshared_libffi=false),避免分发时额外携带 libffi-8.dll
  • 若手动提供 libffi,需确保 libffi 位数与 Lua/cffi-lua 一致,且头文件版本与库版本匹配(如 libffi 3.4.4 对应头文件需为 3.4.4 版本)。

4.3 Lua 链接差异(Windows vs Unix)

  • Windows 下编译 cffi-lua 必须链接 Lua 的导入库(如 lua5.1.lib),否则会出现“无法解析的外部符号”错误;
  • Unix 下无需链接 Lua 库,但 Windows 下必须通过 deps 目录提供或通过 pkg-config 指定,meson 会自动处理链接逻辑。

4.4 常见编译错误解决

错误现象原因解决方法
fatal error C1083: 无法打开包括文件: “lua.h”: No such file or directorymeson 未找到 Lua 头文件检查 deps/include 目录是否存在 lua.h,或重新执行 meson 时指定 -Dlua_version=vendor
LNK2019: 无法解析的外部符号 lua_pushcfunction未链接 Lua 导入库确保 deps 目录存在 lua5.1.lib(对应 Lua 版本),或通过 pkg-config 正确配置 Lua 路径
模块 “cffi” 不是有效的 Lua 模块编译位数与 Lua 不匹配重新用对应位数的编译器编译(32/64位),并验证 cffi.dll 平台属性
ninja编译过程出现错误提示为乱码:娉ㄦ剰: 鍖呭惈鏂囦欢:编码环境切换语言:chcp 65001
4.4.1 lua.hh(23): fatal error C1083: 无法打开包括文件: “lua.hpp”

编译过程中发现FAILED: cffi.dll.p/src_main.cc.obj报错,经过分析定位到下面报错:

在这里插入图片描述

很明显是路径问题,修改lua.hh代码如下即可:

在这里插入图片描述

4.4.2 src_ffi.cc.obj : error LNK2001: 无法解析的外部符号 __imp__lua_gettop

继续编译,又报了《无法解析的外部符号 __imp__lua_gettop》的错误,记得lua是c语言编写,函数符号应该是_lua_gettop才对,IDA打开lua5.1.lib,确认函数符号的确是不带__imp_前缀的。

在这里插入图片描述

__imp_前缀是一个符号前缀,表示import(导入)的意思。 在Windows平台上,当我们编写一个动态链接库DLL时,需要使用__declspec (dllexport)关键字来标识需要导出的函数或变量。 而在使用这个DLL的应用程序中,需要使用__declspec (dllimport)关键字来标识需要导入的函数或变量。

显然,我们要处理__declspec (dllimport)相关内容,这跟LUA_API的宏有关,在luaconf.h中我们做如下修改:

在这里插入图片描述

5️⃣ 测试:验证 cffi-lua 功能

通过简单脚本测试 “调用 C 标准库” 和 “Windows API”,确保模块正常工作。

5.1 环境准备

  1. 参考《【lua】Lua 入门教程:从环境搭建到基础编程 https://blog.csdn.net/kinghzking/article/details/150998449》,下载lua-5.1.5_Win32_bin.zip,解压后即可作为lua环境使用。
  2. 将编译好到cffi.dll文件拷贝到解压后的lua目录中。
  3. (可选)默认可执行文件为lua5.1.exe,问了后续测试方便,将其重命名文件为lua.exe

5.2 测试 1:调用 C 标准库(printf/abs)

创建 test_c_std.lua 脚本:

local cffi = require("cffi")-- 声明 C 标准库函数(msvcrt.dll 为 Windows 内置 C 库)
cffi.cdef[[int printf(const char *format, ...);int abs(int x);int sum(int x, int y);
]]-- 加载 C 标准库
local msvcrt = cffi.load("msvcrt")-- 调用函数
local ret = msvcrt.abs(-10)
print("cffi-lua 测试: abs(-10) = ", ret)
msvcrt.printf("cffi-lua 测试完成\n")

执行命令lua test_c_std.lua

在这里插入图片描述

5.3 测试 2:测试 2:调用 Windows API(MessageBoxA)

创建 test_win_api.lua 脚本(验证 Windows 特有 API 调用):

local cffi = require("cffi")-- 声明 Windows API 类型和函数(来自 user32.dll)
cffi.cdef[[typedef void* HWND;enum {MB_OK = 0x00000000L,MB_ICONINFORMATION = 0x00000040L};int MessageBoxA(HWND hWnd, const char *lpText, const char *lpCaption, unsigned int uType);
]]-- 加载 user32.dll(Windows 窗口相关 API 库)
local user32 = cffi.load("user32")-- 调用 MessageBoxA 弹出窗口
user32.MessageBoxA(nil, "cffi-lua 调用 Windows API 成功!", "测试提示", cffi.C.MB_OK + cffi.C.MB_ICONINFORMATION)

执行命令lua test_win_api.lua

弹出 Windows 标准消息框,说明 Windows API 调用正常。

在这里插入图片描述

🛬 文章小结

  1. Windows核心流程:准备依赖(Lua/libffi/meson)→ 选择编译环境(MSVC)→ 配置 meson 参数 → 编译(ninja all)→ 安装(ninja install)→ 测试(调用C库/Windows API);
  2. 关键避坑点:编译位数必须与 Lua 一致、优先静态链接 libffi、确保 Lua 头文件/库文件在 deps 目录(MSVC 环境);
  3. 适用场景:标准 Lua 调用 Windows API、C 库集成、高性能计算场景,无需编写传统 C 扩展模块,大幅简化开发流程;
  4. 优势对比:相比 alien 等库,cffi-lua 支持更复杂的 C 类型(结构体/函数指针),且维护活跃,兼容最新 Lua 5.4 版本。

📖 参考资料

  • 【lua】Lua 入门教程:从环境搭建到基础编程 https://blog.csdn.net/kinghzking/article/details/150998449
  • cffi-lua 官方文档:GitHub 仓库
  • meson 官方指南:使用说明

文章转载自:

http://V6XiP1vL.ctLjs.cn
http://YJNuejCY.ctLjs.cn
http://GxtgD2qs.ctLjs.cn
http://Ufe8S8wv.ctLjs.cn
http://gLCht6uf.ctLjs.cn
http://EYe6upRI.ctLjs.cn
http://M9nBlIFY.ctLjs.cn
http://wzaPcwb1.ctLjs.cn
http://ZnXYQK65.ctLjs.cn
http://klSpu0GZ.ctLjs.cn
http://8NYGz8um.ctLjs.cn
http://gtKsWVgj.ctLjs.cn
http://BEx6GQ8l.ctLjs.cn
http://FtK2JVun.ctLjs.cn
http://K6Vg2tSQ.ctLjs.cn
http://K8YSEc0p.ctLjs.cn
http://EGF7XQ9V.ctLjs.cn
http://JwqJ1Sks.ctLjs.cn
http://FQldLrZ3.ctLjs.cn
http://G0H4aUtw.ctLjs.cn
http://UceNcjOc.ctLjs.cn
http://f5mm3pNu.ctLjs.cn
http://Ldz2v7yg.ctLjs.cn
http://AAMIpPep.ctLjs.cn
http://7dm6leFh.ctLjs.cn
http://d3xygqB6.ctLjs.cn
http://B4pqSYdf.ctLjs.cn
http://IEJrnyHQ.ctLjs.cn
http://KzNM54TE.ctLjs.cn
http://m82NBNhM.ctLjs.cn
http://www.dtcms.com/a/387548.html

相关文章:

  • 我优化了昨天的C++/Lua插件系统:添加了插件沙箱、Lua 状态池
  • 【数据库】SQLite安装部署与使用指南
  • Android Kotlin 请求方法代码
  • 【easy_tools】一个跨平台裸机工具库,包含任务/堆栈/消息/定时器/日志等实现
  • ARM(11) - LM75
  • FPGA实现SRIO数据回环传输,基于Serial Rapidlo Gen2架构,提供6套工程源码和技术支持
  • 第十九章 Arm C1-Premium TRBE技术解析
  • HTB writeup
  • 科学研究系统性思维的理论基础:数字化研究工具
  • 基于有限元-元胞自动机法(CAFE)的增材制造过程组织模拟
  • 电视行业复兴,数字化制造如何重塑“视界”新格局?
  • 从兼容到极致性能——qData数据中台商业版核心指标解读
  • MAC-枚举反射工具类
  • 搜索百科(1):Lucene —— 打开现代搜索世界的第一扇门
  • 学习日记-JS+DOM-day57-9.17
  • Java异常处理最佳实践指南
  • Ansible简介
  • pytest使用总结笔记
  • 在VSCode中设置Qt开发环境
  • 斜杠命令Slash Commands:Roo Code 的自动化利器
  • 大数据毕业设计选题推荐-基于大数据的慢性肾病数据可视化分析系统-Spark-Hadoop-Bigdata
  • 基于红尾鹰优化的LSTM深度学习网络模型(RTH-LSTM)的一维时间序列预测算法matlab仿真
  • TDengine IDMP 基本功能——数据可视化(2. 柱状图)
  • Python与Google Earth Engine (GEE) 实现地理空间数据自动化处理:高效分析与批量任务执行
  • Dify Agent + AntV 实战:从 0 到 1 打造数据可视化解决方案
  • 系统架构设计师备考第25天——软件测试
  • 十、vue3后台项目系列——登录页面的搭建
  • 在博主内容推送系统中,通过RabbitMQ异步解耦及消息持久化+重试机制,使推送效率提升300%,成功率提升至99.9%的原理及实现
  • 【FreeRTOS】二值信号量vs互斥量核心差异
  • 记一次golang结合前端的axios进行预签名分片上传遇到403签名错误踩坑