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

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

▒ 目录 ▒

    • 🛫 导读
      • 需求
      • 环境
    • 1️⃣ 核心原理:Windows下Lua与C的交互逻辑
    • 2️⃣ Windows下编写步骤:以`mymath`模块为例
      • 2.1 步骤1:准备Windows开发环境
        • 方式1:官网下载Lua源码并编译(可控性高)
        • 方式2:使用sourceforge下载编译好的项目(新手友好,免编译)
      • 2.2 步骤2:编写`mymath`模块的C代码
      • 2.3 步骤3:编译为Windows动态链接库(DLL)
      • 2.4 步骤4:在Windows下的Lua中调用模块
        • 步骤1:配置DLL路径(二选一)
        • 步骤2:编写Lua脚本调用模块
        • 步骤3:执行脚本
    • 3️⃣ Windows下关键技术点与避坑指南
      • 3.1 栈操作核心规则(避免Lua虚拟机崩溃)
      • 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
IDEVS2019
软件位数x86
lua5.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在底层操作的性能短板。

📖 参考资料

  • lua源码下载地址: https://lua.org/ftp/
  • lua 静态库下载地址: https://sourceforge.net/projects/luabinaries/files/5.1.5/Windows%20Libraries/Static/

文章转载自:

http://zOlLe23t.cLgbb.cn
http://WvGH8bZp.cLgbb.cn
http://H62dGk7y.cLgbb.cn
http://3LnbXi7Y.cLgbb.cn
http://igNNlyRw.cLgbb.cn
http://2FcM0Euj.cLgbb.cn
http://9dxEYdiE.cLgbb.cn
http://21ChFJne.cLgbb.cn
http://GToAP87Y.cLgbb.cn
http://j3SfAohz.cLgbb.cn
http://a28Rp4g3.cLgbb.cn
http://rkhRy4tc.cLgbb.cn
http://dfiiqp8p.cLgbb.cn
http://PMCn4n8g.cLgbb.cn
http://d6OVEfaB.cLgbb.cn
http://z7qdLgK0.cLgbb.cn
http://L53qlmHu.cLgbb.cn
http://rhBv3tf7.cLgbb.cn
http://6HOXdIVN.cLgbb.cn
http://ynbmGJ3b.cLgbb.cn
http://JiFlU0Sj.cLgbb.cn
http://Q1NcyOXw.cLgbb.cn
http://RMB6Bfm8.cLgbb.cn
http://dP751Mq4.cLgbb.cn
http://YKpzTgmu.cLgbb.cn
http://V1D7Ke3F.cLgbb.cn
http://fX3DQlw6.cLgbb.cn
http://uFMBsY24.cLgbb.cn
http://KibbMeBu.cLgbb.cn
http://Br8D1D0H.cLgbb.cn
http://www.dtcms.com/a/381662.html

相关文章:

  • 004 Rust控制台打印输出
  • idea自动编译,idea不重启项目,加载修改的内容
  • 阻塞 IO为什么叫BIO,非阻塞IO为什么叫NIO,异步IO为什么叫AIO
  • 少即是多:从 MPTCP 看优化干预的边界
  • 2025服贸会“海淀之夜”,点亮“科技”与“服务”底色
  • String留言板
  • js生成excel表格进阶版
  • Win 11 ARM 版搭建ESP-IDF环境问题记录
  • MyBatis主键返回:必须显式配置
  • MySQL——MVCC实现原理流程分析
  • Linux -- 基于TCP服务器实现一个简单的电商网站
  • 佳维视工业一体机 vs 普通电脑:工业场景选哪个?
  • 小迪安全v2023学习笔记(八十二讲)—— Java组件安全SolrShiroLog4jCVE复现
  • Spring AI(四)机构化输出
  • 单体到微服务拆分方案
  • 云端服务器使用指南:如何跨机传输较大文件(通过windows自带工具远程桌面连接 非常方便)
  • Linux 高性能 I/O 事件通知机制的核心系统调用—— `epoll_ctl`
  • 域格YM310 X09移芯CAT1模组HTTPS连接服务器
  • 连续随机变量无法用点概率描述出现了概率密度函数(Probability Density Function, PDF)
  • Go语言实战案例 — 工具开发篇:Go 实现条形码识别器
  • 洛谷-P1923 【深基9.例4】求第 k 小的数-普及-
  • DeerFlow实践:华为ITR流程的评审智能体设计
  • K均值聚类(K-Means)算法介绍及示例
  • 【企业架构】TOGAF-4A架构概览
  • 华为防火墙三层部署模式
  • Linux Kernel Core API:printk
  • 空间信息与数字技术专业主要学什么技能?
  • 遗传算法模型深度解析与实战应用
  • “开源AI智能名片链动2+1模式S2B2C商城小程序”在直播公屏引流中的应用与效果
  • C语言第五课:if、else 、if else if else 控制语句