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

▒ 目录 ▒

    • [🛫 导读](#🛫 导读)
    • [1️⃣ 核心原理:Windows下Lua与C的交互逻辑](#1️⃣ 核心原理:Windows下Lua与C的交互逻辑)
    • [2️⃣ Windows下编写步骤:以`mymath`模块为例](#2️⃣ Windows下编写步骤:以mymath模块为例)
    • [3️⃣ Windows下关键技术点与避坑指南](#3️⃣ Windows下关键技术点与避坑指南)
      • [3.1 栈操作核心规则(避免Lua虚拟机崩溃)](#3.1 栈操作核心规则(避免Lua虚拟机崩溃))
      • [3.2 Windows下常见编译错误与解决](#3.2 Windows下常见编译错误与解决)
    • [🛬 文章小结](#🛬 文章小结)

🛫 导读

需求

在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 Libraries/Static/

  2. 找到合适的版本(32位,2019,静态);

  3. 将解压出来的文件拷贝到项目中,按照下面目录组织。

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

新建一个dll项目

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

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文件,内容如下:

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所在目录,执行:

cmd 复制代码
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在底层操作的性能短板。

📖 参考资料

相关推荐
LGL6030A14 小时前
算法题实战积累(3)——方块转换(C语言)
c语言·算法
努力写代码的熊大16 小时前
List迭代器和模拟(迭代器的模拟)
数据结构·windows·list
长路归期无望17 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
口嗨农民工18 小时前
win10默认搜索APP和window设置控制命板
linux·服务器·c语言
爱吃小胖橘19 小时前
Lua语法
开发语言·unity·lua
东方芷兰20 小时前
JavaWeb 课堂笔记 —— 20 SpringBootWeb案例 配置文件
java·开发语言·笔记·算法·log4j·intellij-idea·lua
楼田莉子20 小时前
vscode搭建C/C++配置开发环境
c语言·开发语言·c++·vscode·学习·编辑器
胖咕噜的稞达鸭20 小时前
list 实现链表封装节点的底层逻辑:如何克服不连续无法正常访问挑战
windows·链表·list
DarkBule_21 小时前
分享几个好用的windows镜像网站
windows
人群多像羊群21 小时前
Windows复现MonoDETR记录
windows·计算机视觉