VS2019搭建lua开发环境笔记和C++与lua之间交互

以下内容取自网上公开文档

1.下载源码:http://www.lua.org/ftp/

2.编译dll,lib和exe:

2.1在“C/C++” -> “预处理器” -> “预处理器定义” 中添加LUA_BUILD_AS_DLL:不加没有lib

2.2不添加(lua.c 和 luac.c)

2.3编译exe添加对应的文件

lua.c:编译器

luac.c:解释器

3.使用生成的库(x64,x86要一致)

3.1栈的操作

VS2019搭建lua开发环境笔记和C++与lua之间交互
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 
 4 //注意添加extern "C",否则出现链接错误
 5 extern "C" {
 6 #include "lua.h"
 7 #include "lualib.h"
 8 #include "lauxlib.h"
 9 }
10 
11 #ifdef _DEBUG
12 #pragma comment(lib,"./Lua/Debug/Luad.lib")
13 #else
14 #pragma comment(lib,"./Lua/Release/Lua.lib")
15 #endif
16 
17 static void stackDump(lua_State* L)
18 {
19     int i = 0;
20     int top = lua_gettop(L);
21     for (i = 1; i <= top; i++)
22     {
23         int t = lua_type(L, i);
24         switch (t)
25         {
26         case LUA_TSTRING: /* strings */
27             printf("`%s'", lua_tostring(L, i));
28             break;
29         case LUA_TBOOLEAN: /* booleans */
30             printf(lua_toboolean(L, i) ? "true" : "false");
31             break;
32         case LUA_TNUMBER: /* numbers */
33             printf("%g", lua_tonumber(L, i));
34             break;
35         default: /* other values */
36             printf("%s", lua_typename(L, t));
37             break;
38         }
39         printf(" "); /* put a separator */
40     }
41     printf("\n"); /* end the listing */
42 }
43 
44 int main(int argc, char** argv)
45 {
46     lua_State* L = luaL_newstate();  // 创建Lua虚拟机
47 
48     luaL_openlibs(L);                // 打开Lua状态机"L"中的所有Lua标准库
49 
50     // 向虚拟栈中压入值
51     lua_pushboolean(L, 1);           // true
52     lua_pushnumber(L, 10);           // 10
53     lua_pushnil(L);                  // nil
54     lua_pushstring(L, "hello");      // "hello"
55     stackDump(L);                    // true  10  nil  'hello'
56 
57     lua_pushvalue(L, -4);            // 将索引-4处的值的副本入栈
58     stackDump(L);                    // true  10  nil  'hello'  true
59 
60     lua_replace(L, 3);               // 将栈顶元素移动到索引3处,并覆盖原先的元素
61     stackDump(L);                    // true  10  true  'hello'
62 
63     lua_settop(L, 6);                // 将栈顶设置为索引6处,多出来的新元素被赋值为"nil"
64     stackDump(L);                    // true  10  true  'hello'  nil  nil
65 
66     lua_remove(L, -3);               // 移除索引-3处的元素,其上所有元素下移
67     stackDump(L);                    // true  10  true  nil  nil
68 
69     lua_settop(L, -5);              // 将栈顶设置为索引-5处
70     stackDump(L);                   // true
71 
72     lua_close(L);                   // 关闭Lua状态机
73 
74     system("pause");//在Linux下编译,请注释调这行
75 
76     return 0;
77 }
View Code

VS2019搭建lua开发环境笔记和C++与lua之间交互

  3.2 C调用Lua

VS2019搭建lua开发环境笔记和C++与lua之间交互

VS2019搭建lua开发环境笔记和C++与lua之间交互
 1 static int multi_math(lua_State* L, int x, int y)
 2 {
 3     int ret = 0;
 4     int add_ret = 0;
 5     int sub_ret = 0;
 6     int mul_ret = 0;
 7 
 8     //call lua_add
 9     lua_getglobal(L, "lua_add");//把函数lua_add压入栈中
10     stackDump(L);                //function
11     lua_pushnumber(L, x);        //function 2
12     lua_pushnumber(L, y);        //fucntion 2 1
13     stackDump(L);
14     lua_call(L, 2, 1);         //指明有2个参数,1个返回值,且把function 2 1弹出栈,并把返回值压入栈
15 
16     stackDump(L);
17     add_ret = (int)lua_tonumber(L, -1);
18     stackDump(L);
19     printf("add_ret = %d\n", add_ret);
20     lua_pop(L, 1);                //弹出栈顶
21     stackDump(L);
22 
23 #if 0
24     //call local lua_sub will cause running error 
25     lua_getglobal(L, "lua_sub");
26     lua_pushnumber(L, x);
27     lua_pushnumber(L, y);
28     lua_call(L, 2, 1);
29     sub_ret = (int)lua_tonumber(L, -1);
30     printf("sub_ret = %d\n", sub_ret);
31     lua_pop(L, 1);
32 #endif
33     //call lua_mul
34     lua_getglobal(L, "lua_mul");
35     lua_pushnumber(L, x);
36     lua_pushnumber(L, y);
37     lua_call(L, 2, 1);
38     mul_ret = (int)lua_tonumber(L, -1);
39     printf("mul_ret = %d\n", mul_ret);
40     lua_pop(L, 1);
41 
42     return ret;
43 }
44 int main(int argc, char** argv)
45 {
46     lua_State* L = luaL_newstate(); // 创建Lua虚拟机
47     luaL_openlibs(L);               // 打开Lua状态机"L"中的所有Lua标准库
48 
49     printf("call lua ....\n");
50     if (luaL_dofile(L, "main.lua"))//加载运行main.lua
51     {
52         printf("call lua failed!\n");
53     }
54     if (multi_math(L, 2, 1))
55     {
56         printf("call multi_math failed!\n");
57     }
58 
59     lua_close(L); // 关闭Lua状态机
60 
61     system("pause");
62 
63     return 0;
64 }
View Code

VS2019搭建lua开发环境笔记和C++与lua之间交互

 3.3 lua 调用 C

其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L)

VS2019搭建lua开发环境笔记和C++与lua之间交互
 1 //待Lua调用的C注册函数。
 2 static int add2(lua_State* L)
 3 {
 4     //检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
 5     //如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
 6     double op1 = luaL_checknumber(L, 1);
 7     double op2 = luaL_checknumber(L, 2);
 8     //将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
 9     lua_pushnumber(L, op1 + op2);
10     //返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
11     return 1;
12 }
13 //另一个待Lua调用的C注册函数。
14 static int sub2(lua_State* L)
15 {
16     double op1 = luaL_checknumber(L, 1);
17     double op2 = luaL_checknumber(L, 2);
18     lua_pushnumber(L, op1 - op2);
19     return 1;
20 }
21 const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
22 
23 int main()
24 {
25     lua_State* L = luaL_newstate();
26     luaL_openlibs(L);
27     //将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码
28     //在调用C函数时使用的全局函数名,第二个参数为实际C函数的指针。
29     lua_register(L, "add2", add2);
30     lua_register(L, "sub2", sub2);
31     //在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
32     if (luaL_dostring(L, testfunc))
33         printf("Failed to invoke.\n");
34     lua_close(L);
35     return 0;
36 
37 }
View Code

VS2019搭建lua开发环境笔记和C++与lua之间交互

 3.4 C函数库成为Lua的模块(暂时不用直接摘录)。

将包含C函数的代码生成库文件,如Linux的so,或Windows的DLL,同时拷贝到Lua代码所在的当前目录,或者是LUA_CPATH环境变量所指向的目录,以便于Lua解析器可以正确定位到他们。在我当前的Windows系统中,我将其copy到"C:\Program Files\Lua\5.1\clibs\",这里包含了所有Lua可调用的C库。见如下C语言代码和关键性注释:


#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>
//待注册的C函数,该函数的声明形式在上面的例子中已经给出。
//需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
//函数代码和上例相同,这里不再赘述。
extern "C" int add(lua_State* L) 
{
    double op1 = luaL_checknumber(L,1);
    double op2 = luaL_checknumber(L,2);
    lua_pushnumber(L,op1 + op2);
    return 1;
}
extern "C" int sub(lua_State* L)
{
    double op1 = luaL_checknumber(L,1);
    double op2 = luaL_checknumber(L,2);
    lua_pushnumber(L,op1 - op2);
    return 1;
}
//luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
//第一个字段为C函数指针。
//结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
static luaL_Reg mylibs[] = { 
    {"add", add},
    {"sub", sub},
    {NULL, NULL} 
};
//该C库的唯一入口函数。其函数签名等同于上面的注册函数。见如下几点说明:
//1. 我们可以将该函数简单的理解为模块的工厂函数。
//2. 其函数名必须为luaopen_xxx,其中xxx表示library名称。Lua代码require "xxx"需要与之对应。
//3. 在luaL_register的调用中,其第一个字符串参数为模块名"xxx",第二个参数为待注册函数的数组。
//4. 需要强调的是,所有需要用到"xxx"的代码,不论C还是Lua,都必须保持一致,这是Lua的约定,
//   否则将无法调用。
extern "C" __declspec(dllexport)
int luaopen_mytestlib(lua_State* L) 
{
    const char* libName = "mytestlib";
    luaL_register(L,libName,mylibs);
    return 1;

见如下Lua代码:

 require "mytestlib"  --指定包名称
 --在调用时,必须是package.function
 print(mytestlib.add(1.0,2.0))
 print(mytestlib.sub(20.1,19))

上一篇:VS2019手动升级


下一篇:VS2019 无法创建MFC工程 解决方法