【Lua】Windows 下编写 C 扩展模块:VS 编译与 Lua 调用全流程

发布于:2025-09-14 ⋅ 阅读:(25) ⋅ 点赞:(0)

🛫 导读

需求

在Windows环境下,通过Lua C扩展模块实现“高性能C代码与Lua脚本集成”(如封装Windows API、硬件接口),但常面临“开发环境配置复杂”、“编译工具选择(MinGW/Visual Studio)”、“动态库加载路径”等问题。

本文聚焦Windows平台,提供从“Lua开发库准备”、“C模块代码编写”、“VS编译”到“Lua调用”的全流程方案,以mymath模块为例(含加法、幂运算功能),帮助开发者快速掌握Windows下Lua C扩展的核心能力。

环境

版本号 描述
文章日期 2025-09-13
操作系统 Win11
IDE VS2019
软件位数 x86
lua 5.1.5

1️⃣ 核心原理:Windows下Lua与C的交互逻辑

Lua通过C API(定义于lua.hlauxlib.h)实现与C代码的交互,核心依赖栈(stack)动态链接库(DLL),Windows环境下的关键逻辑如下:

  1. 数据传递:C与Lua的所有参数、返回值均通过“栈”交互(C向栈推数据供Lua使用,从栈取Lua传入的参数);
  2. 模块形式:C扩展需编译为*.dll(Windows动态链接库),文件名需与模块名一致(如mymath.dll对应模块mymath);
  3. 加载入口:模块必须包含固定命名的入口函数luaopen_模块名(如luaopen_mymath),Lua通过require加载DLL时自动调用该函数,完成C函数向Lua的注册。

2️⃣ Windows下编写步骤:以mymath模块为例

实现mymath模块,包含两个功能:add(a,b)(计算两数之和)、pow(a,b)(计算ab次方),全程基于Windows环境操作。

2.1 步骤1:准备Windows开发环境

需先获取Lua开发库(含lua.h等头文件和lua5x.lib链接库),Windows下推荐两种方式:

方式1:官网下载Lua源码并编译(可控性高)
  1. 下载Lua源码:访问Lua官网,下载Windows源码包(如lua-5.1.5.tar.gz);

  2. 解压源码至无空格目录(如${PRO_DIR});

  3. 编译Lua开发库:

    • 若用MinGW:打开MinGW终端,进入源码src目录,执行mingw32-make PLAT=mingw,生成lua5.1.lib(链接库)、lua5.1.dll(动态库)及lua.h(头文件,位于src目录);
    • 若用Visual Studio:打开VS命令提示符(如“x86 Native Tools Command Prompt for VS 2019”),进入源码src目录,执行nmake /f Makefile.win,生成lua5.1.liblua5.1.dll
  4. 整理开发文件:创建${PRO_DIR}目录,按如下结构存放(便于后续编译引用):

    ${PRO_DIR}\
    ├─ include\lua5.1\  # 头文件
    │  ├─ lua.h
    │  ├─ lauxlib.h
    │  └─ luaconf.h
    └─ lib\      # 链接库
       ├─ lua5.1.lib(32位,2019,静态)
       └─ lua5.1.dll(非静态需要dll)
    
方式2:使用sourceforge下载编译好的项目(新手友好,免编译)
  1. 打开https://sourceforge.net/projects/luabinaries/files/5.1.5/Windows%20Libraries/Static/

  2. 找到合适的版本(32位,2019,静态);
    在这里插入图片描述

  3. 将解压出来的文件拷贝到项目中,按照下面目录组织。
    在这里插入图片描述

2.2 步骤2:编写mymath模块的C代码

新建一个dll项目

创建mymath.c文件,完整代码如下(包含函数实现、注册逻辑):

#include "pch.h"  // 预编译头(可选)
#include <cmath>  // 引入C++标准库(用于数学计算)

// 引入Lua C API头文件(路径需与实际开发库一致)
extern "C" {
#include ".\include\lua5.1\lua.h"
#include ".\include\lua5.1\lualib.h"
#include ".\include\lua5.1\lauxlib.h"

#pragma comment(lib, "./lib/lua5.1.lib")

// 1. 实现add函数:计算a + b(C函数与Lua的交互通过栈)
static int l_mymath_add(lua_State* L) {
    // 从栈取第1个参数(Lua传入的a),自动检查是否为数字,非数字则抛错
    double a = luaL_checknumber(L, 1);
    // 从栈取第2个参数(Lua传入的b)
    double b = luaL_checknumber(L, 2);

    // 将计算结果压入栈(作为返回值,栈顶为第1个返回值)
    lua_pushnumber(L, a + b);

    return 1;  // 返回值数量:1个
}

// 2. 实现pow函数:计算a^b
static int l_mymath_pow(lua_State* L) {
    double a = luaL_checknumber(L, 1);
    double b = luaL_checknumber(L, 2);

    // 调用C标准库的pow函数计算
    double result = pow(a, b);
    lua_pushnumber(L, result);

    return 1;
}

// 3. 定义函数列表:关联“Lua中函数名”与“C函数指针”
static const luaL_Reg mymath_funcs[] = {
    {"add", l_mymath_add},  // Lua调用mymath.add时,执行l_mymath_add
    {"pow", l_mymath_pow},  // Lua调用mymath.pow时,执行l_mymath_pow
    {NULL, NULL}            // 结束标记(不可省略)
};

// 4. 模块入口函数:固定命名为luaopen_模块名(mymath)
__declspec(dllexport) int luaopen_mymath(lua_State* L) {
    // 创建新的Lua表,将mymath_funcs中的函数注册到表中
    luaL_register(L, "mymath", mymath_funcs);
    return 1;  // 返回注册好的函数表(Lua通过require获取该表)
}
}

2.3 步骤3:编译为Windows动态链接库(DLL)

Windows下用Visual Studio工具编译,需确保编译的DLL位数(32位)与Lua位数一致。

2.4 步骤4:在Windows下的Lua中调用模块

编译生成mymath.dll后,需确保DLL能被Lua找到,再通过require加载:

步骤1:配置DLL路径(二选一)
  • 简单方式:将mymath.dll与Lua.exe放在同一目录;
  • 通用方式:将mymath.dll所在目录添加到Windows系统环境变量PATH中(添加后需重启命令提示符)。
步骤2:编写Lua脚本调用模块

创建test.lua文件,内容如下:

-- 加载mymath模块(自动查找mymath.dll)
local mymath = require("mymath")

-- 调用模块中的函数
print("2 + 3 =", mymath.add(2, 3))    -- 输出:2 + 3 = 5.0
print("2^10 =", mymath.pow(2, 10))    -- 输出:2^10 = 1024.0
print("3.5^2 =", mymath.pow(3.5, 2))  -- 输出:3.5^2 = 12.25
步骤3:执行脚本

打开Windows命令提示符,进入test.lua所在目录,执行:

lua test.lua

若输出正确结果,说明Windows下Lua C扩展模块调用成功。
在这里插入图片描述

ps: 也可以直接通过lua.exe,交互式调用
在这里插入图片描述

3️⃣ Windows下关键技术点与避坑指南

3.1 栈操作核心规则(避免Lua虚拟机崩溃)

Windows下Lua C API的栈操作与其他平台一致,但需严格遵守“栈平衡”:

  • 入栈数量 ≤ 出栈处理数量:每个C函数中,推到栈的返回值数量需与return后的数字一致(如return 1表示栈顶有1个返回值);
  • 参数索引正确性:Lua传入C的参数按顺序压栈,第1个参数索引为1,第2个为2(不可用负数索引操作参数,易混淆栈顶位置)。

3.2 Windows下常见编译错误与解决

错误现象 原因 解决方法
fatal error: lua.h: No such file or directory 头文件路径错误 /I后的路径是否正确,确保lua.h存在
undefined reference to 'luaL_newlib' Lua版本不兼容(luaL_newlib是Lua 5.2+新增) 若为Lua 5.1,将luaL_newlib(L, funcs)改为luaL_register(L, "mymath", funcs)
无法找到lua5.1.lib 链接库路径错误或位数不匹配 确认-L//LIBPATH路径正确,且lua5.1.lib位数(32/64)与编译目标一致
Lua加载时提示“找不到指定的模块” DLL路径未配置或位数不匹配 将DLL放入脚本目录或添加到PATH,确保DLL位数与Lua位数一致
LINK2019 _luaL_register #pragma comment(lib, "./lib/lua5.1.lib") 写成#pragma (lib, "./lib/lua5.1.lib")
LINK2019 luaL_checknumber 未指定C引入 extern "C" {

在这里插入图片描述

🛬 文章小结

  1. Windows核心流程:准备Lua开发库(源码编译/ sourceforge下载)→ 编写C代码(含函数实现与入口函数)→ 用VS编译为DLL(确保位数匹配)→ 配置DLL路径→ Lua调用;
  2. 关键避坑点:DLL位数与Lua一致、头文件/链接库路径正确、DLL放入PATH或脚本目录、Lua版本与API兼容(如luaL_newlibvsluaL_register);
  3. 价值:Windows下通过Lua C扩展,可封装Windows API(如文件操作、系统信息)或高性能C逻辑,弥补Lua在底层操作的性能短板。

📖 参考资料


网站公告

今日签到

点亮在社区的每一天
去签到