Linux下lua安装使用,与C/C++交互

24 篇文章 7 订阅

来源:微信公众号「编程学习基地」

ubuntu 18.04 lua安装命令

curl -R -O http://www.lua.org/ftp/lua-5.4.3.tar.gz
tar zxf lua-5.4.3.tar.gz
cd lua-5.4.3
make all test
sudo make install

C++调用lua

一、Lua堆栈

要理解Lua和C++交互,首先要理解Lua堆栈。

简单来说,Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出。

在Lua中,Lua堆栈就是一个struct

堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。

二、堆栈的操作

因为Lua与C/C++是通过栈来通信,Lua提供了C API对栈进行操作。

我们先来看一个最简单的例子:

#include <iostream>  
#include <string.h>  
using namespace std;  
   
extern "C"  
{  
    #include "lua.h"  
    #include "lauxlib.h"  
    #include "lualib.h"  
}  
int main()  
{  
    //1.创建一个state  
    lua_State *luaHandle = luaL_newstate(); 
    //2.入栈操作  
    lua_pushstring(luaHandle, "I am so cool~");   
    lua_pushnumber(luaHandle,20);  
    //3.取值操作  
    if( lua_isstring(luaHandle,1)){             //判断是否可以转为string  
        cout<<lua_tostring(luaHandle,1)<<endl;  //转为string并返回  
    }  
    if( lua_isnumber(luaHandle,2)){  
        cout<<lua_tonumber(luaHandle,2)<<endl;  
    }  
    //4.关闭state  
    lua_close(luaHandle);  
    return 0;  
}
g++ -o lua lua.cpp -llua

运行

$ ./lua 
I am so cool~
20

其他一些栈操作:

int   lua_gettop (lua_State *L);            //返回栈顶索引(即栈长度)  
void  lua_settop (lua_State *L, int idx);   //                
void  lua_pushvalue (lua_State *L, int idx);//将idx索引上的值的副本压入栈顶  
void  lua_remove (lua_State *L, int idx);   //移除idx索引上的值  
void  lua_insert (lua_State *L, int idx);   //弹出栈顶元素,并插入索引idx位置  
void  lua_replace (lua_State *L, int idx);  //弹出栈顶元素,并替换索引idx位置的值

ua_settop将栈顶设置为一个指定的位置,即修改栈中元素的数量。如果值比原栈顶高,则高的部分nil补足,如果值比原栈低,则原栈高出的部分舍弃。所以可以用lua_settop(0)来清空栈

C++调用lua的脚本

创建一个lua脚本 test.lua

str = "I am so cool"  
tbl = {name = "shun", id = 20114442}  
function add(a,b)  
    return a + b  
end

编写.cpp文件调用lua代码

/**
 * @file test.cpp
 * @author deroy (you@domain.com)
 * @brief C/C++调用lua代码
 * @version 0.1
 * @date 2021-11-24
 * 
 * @copyright Copyright (c) 2021
 * 
 */
#include <iostream>  
#include <string.h>  
using namespace std;  

extern "C"  
{  
    #include "lua.h"  
    #include "lauxlib.h"  
    #include "lualib.h"  
}  
int main()  
{  
    //1.创建一个state  
    lua_State *luaHandle = luaL_newstate();  
       
    //2.加载Lua文件  
    int bRet = luaL_loadfile(luaHandle,"test.lua");  
    if(bRet)  
    {  
        cout<<"load file error"<<endl;  
        return 0;  
    } 
    //3.运行Lua文件  
    bRet = lua_pcall(luaHandle,0,0,0);  
    if(bRet)  
    {  
        cout<<"pcall error"<<endl;  
        return 0;  
    }

    //4.读取变量  
    lua_getglobal(luaHandle,"str");
    string str = lua_tostring(luaHandle,-1);
    cout<<"str = "<<str.c_str()<<endl;         //str = I am so cool~ 
   
    //5.读取table  
    lua_getglobal(luaHandle,"tbl");
    lua_getfield(luaHandle,-1,"name");
    str = lua_tostring(luaHandle,-1);
    cout<<"tbl:name = "<<str.c_str()<<endl;     //tbl:name = shun  

    //6.读取函数  
    lua_getglobal(luaHandle, "add");        // 获取函数,压入栈中  
    lua_pushnumber(luaHandle, 10);          // 压入第一个参数  
    lua_pushnumber(luaHandle, 20);          // 压入第二个参数  
    int iRet= lua_pcall(luaHandle, 2, 1, 0);// 调用函数,调用完成以后,会将返回值压入栈中,2表示参数个数,1表示返回结果个数。  
    if (iRet)                       // 调用出错  
    {  
        const char *pErrorMsg = lua_tostring(luaHandle, -1);  
        cout << pErrorMsg << endl;  
        lua_close(luaHandle);  
        return 0;
    }  
    if (lua_isnumber(luaHandle, -1))        //取值输出  
    {  
        double fValue = lua_tonumber(luaHandle, -1);  
        cout << "Result is " << fValue << endl;  
    }
    
    //至此,栈中的情况是:  
    //=================== 栈顶 ===================   
    //  索引  类型      值  
    //   4   int:      30   
    //   3   string:   shun   
    //   2   table:     tbl  
    //   1   string:    I am so cool~  
    //=================== 栈底 ===================   
   
    //7.关闭state  
    lua_close(luaHandle);  
    return 0;  
}

Lua调用C/C++

lua作为脚本语言是无法直接调用静态库的(除非吧静态库编译到Lua解析器里面)

本文介绍的是Lua调用C/C++动态库

对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即

typedef int (*lua_CFunction)(lua_State* L)

编写lua.c文件

#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int bs_pclose (lua_State *L) {
#if 0
  luaL_Stream *p = tolstream(L);
#else
  luaL_Stream *p = (luaL_Stream *)luaL_checkudata(L, 1, LUA_FILEHANDLE);
#endif
  return luaL_execresult(L, pclose(p->f));
}

static int bs_popen (lua_State *L) {
    const char *filename = luaL_checkstring(L, 1);
    const char *mode = luaL_optstring(L, 2, "r");
#if 0
    luaL_Stream *p = newprefile(L);
#else
    luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
    luaL_setmetatable(L, LUA_FILEHANDLE);
    p->closef = &bs_pclose;
#endif
    p->f = popen(filename, mode);

    return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}

static const struct luaL_Reg reg_libs[] =
{
    {"pclose", bs_pclose},
    {"popen",  bs_popen},
    {NULL, NULL}
};

int luaopen_libBsLuaExt(lua_State *L)
{
    lua_newtable(L);
    luaL_setfuncs(L, reg_libs, 0);
    //luaL_register(L, "clibs", reg_libs);
    return 1;
}

编译生成动态库

gcc lua.c -fPIC -shared -o libBsLuaExt.so

在动态库所在文件夹下编辑lua脚本

#!/usr/local/bin/lua

local bs = require("libBsLuaExt")
-- require("logPrint")

--[[
写入固定行数日志
--]]

function file_exists(path)
	local file = io.open(path, "rb")
	if file then
		file:close()
	end
	return file ~= nil
end

function file_lines(path)
	local lineCnt = 0;
	--print(path)
	if(file_exists(path) == true) then
		local sysCmd = bs.popen(string.format("wc -l %s | awk '{print $1}'", path));
		lineCnt = tonumber(sysCmd:read("*a"));
		sysCmd:close();
	end
	--print(lineCnt)
	return tonumber(lineCnt);
end

function file_write(path, data)
	local file = io.open(path, "ab")
	if file then
		file:write(data)
		file:write("\n")
		file:close()
	end
	--print(lineCnt)
	return 0;
end

function logFileWrite(maxLine, logFile, logData)
	local logDir = string.match(logFile, "(.+)/[^/]*%.%w+$");
	local t = {};
	--print("maxLine:",maxLine);
	--print("logFile:",logFile);
	--print("logData:",logData);

	local ret = os.execute(string.format("mkdir -p %s", logDir));
	if(ret ~= true) then
		return string.format("failed to create dir '%s'", logDir), -1
	end

	if(file_lines(logFile) >= tonumber(maxLine)) then
		local cmdDelLine = bs.popen(string.format("sed -i '1d' %s", logFile));
		cmdDelLine:close()
	end

	--local cmdAppend = bs.popen(string.format("echo '%s' >> %s", logData, logFile));
	--cmdAppend:close()
	file_write(logFile, logData);

	return t,"OK",0
end

logFileWrite(10, "/home/ubuntu/learnbase/lua/info.txt", "2222")
if(file_exists("/home/ubuntu/learnbase/lua/info.txt") == true) then
    print("存在")
else
    print("不存在")
end

直接运行lua脚本

$ lua lua.lua 
存在

Lua编程入门

参考链接:https://www.bookstack.cn/read/luaprimer/README.md

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeRoy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值