将Lua加入到C++项目:


方法有2个,第一个就是直接把lua的src源代码直接加入到项目里,方便,快捷。

方案二就是把lua编译成lib库,然后其他项目链接进来,就是了。



方案一:拷贝代码


直接把D:\soft_framework_utiles\lua\lua-5.2.3\src下面的代码拷贝到自己项目里面(除了lua.c和luac.c),


比如:D:\WorkspacesForAll\Lua_C++\Lua_CPP\Lua_CPP\lua




lua 引入txn对象 lua引用其他文件_lua 引入txn对象




但是要删除lua.c和luac.c这两个文件,因为这两个不是库文件,而是lua执行器和编译器的源文件。


用来编译成两个exe的,不是我们的lib文件。





lua 引入txn对象 lua引用其他文件_加载_02




然后写一个Main方法:


#include <stdlib.h>
// 简单点,直接把lua的src拷贝到我们项目里面
// 然后把lua.c和luac.c移除就可以了
#include "lua/lua.hpp"

int main(int argc, char* argv[])
{
	char buff[256];
	int errorCode;

	// 有的 lua_open是个宏了
	// l现在是lua_newstate, luaL_newstate 
	// 
	// L = luaL_newstate();//创建一个指向Lua解释器的指针。
	// 函数加载Lua库
 

	// 使用 lua_newstate() 创建一个新的 Lua 状态机。 
	lua_State* luaState = luaL_newstate();
	// 若有必要,调用 luaL_openlibs() 函数加载 Lua 的标准库。 
	luaL_openlibs(luaState);


	//一旦初始化了 Lua 脚本引擎,你可以通过如下步骤执行一段 Lua 脚本: 
	//1. 使用 luaL_loadfile 加载一段 Lua 程序或脚本到 Lua 执行引擎中; 
	//2. 调用 lua_pcall 函数执行已加载的脚本。 

}






方案二:


建立一个空的静态库工程 (最好不使用预编译头,把预编译头的选项勾去掉),然后把src下的所有文件(除了Makefile)一股脑拷到工程中去。然后将这些文件添加到你的工程中,编译,会生成一个*.llib(*是你起的lua库名),行了,建立一个目录lib,把它拷过去,然后再建立一个include的文件夹,把你工程目录下的lua.h,lualib.h,lauxlib.h,拷贝过去。行了,拿着这两个文件夹,你就可以在你的工程里使用lua了。 



讲解lua的栈


栈是lua相当重要的一块,肩负着数据的传递,才开始用很可能摸不清方向,但是用熟练了,就会发现那是相当的简单。


栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用


无论你何时想要从Lua请求一个值(比如一个全局变量的值),调用Lua,被请求的值将会被压入栈。


比如:


下面的调用就会取出2个数据放在栈上面:




lua 引入txn对象 lua引用其他文件_加载_03



无论你何时想要传递一个值给Lua,首先将这个值压入栈,然后调用Lua(这个值将被弹出)。


记住:调用lua函数之前,如果他是需要参数的,我们应该先把参数入栈,这样调用才会有参数可取。


不管是调用lua的函数,还是给lua某个字段设置值,都是先把值push入栈


lua 引入txn对象 lua引用其他文件_lua 引入txn对象_04




比如给lua的table的某个字段赋值:

// 代码A,就是相当于    myTable .hp = 211   
lua_getglobal( L, "myTable" );   // 获取要设置值的table   
lua_pushstring( L, "hp" );         // "hp"在栈上的位置为-1   
lua_pushnumber( L, 211 );          // "hp"在栈上的位置变为-2,而211则是-1   
lua_settable( L, -3 );               // 值被正确的设置到全局变量(表)的myTable中

比如给某个全局变量赋值:


lua_pushnumber( L, 211 );   
lua_setglobal( L, "hp" );



lua头文件对栈的描述:


我们要给lua数据,就直接push,然后调用lua接口,要想load数据就直接lua_get**从lua获取数据到栈。


要想知道这数据的值,我们就直接lua_to***(比如lua_tostring)就得到他的值了。





lua 引入txn对象 lua引用其他文件_lua_05




C++中调用某个Lua文件中的函数:


代码如下:FILE_LUA 下面的注释就是这个lua文件的内容。


void TestCPPCallLua::testCallLuaFunction()
{
#define FILE_LUA "scripts/lua002_function.lua"
	/***
	print("lua002_function.lua");
	-- 测试加法和减法
	-- 注意这里不是local的
	-- 当被load进来的时候相当于返回一个大函数,函数里面有一个全局函数testAdd_Sub
	-- 但是这并不代表定义过了testAdd_Sub,只有外面的这个大函数执行以下,这个testAdd_Sub
	-- 才会被定义到全局里面
	function testAdd_Sub(a,b)
		return a+b,a-b
	end
	*/

	//读入的东西当成一个匿名函数放在栈顶上
	//这样,这个lua文件就被当做一个匿名函数放在栈顶
	//于是可以使用它的数据了。
	//跟直接在lua里面loadfile一样,只是加载,并没有定义里面的函数,
	//需要执行下才定义里面的testAdd_Sub
	int ret = luaL_loadfile(g_State,FILE_LUA);
	if (ret != 0)
	{
		printf("Error :%s --> luaL_loadfile[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
		return;
	}
	// 这里就是lua的一个匿名类,就是那个“大函数”
	LuaUtiles::stackDump(g_State);

	// 调用testAdd_Sub
	// 1.先取得这个函数,要定义了才取得到,所以先运行一下
	// 2.取函数

	/*1.执行一次,用于定义*/
	int runOk = lua_pcall(g_State,0,0,NULL);
	if (runOk != 0)
	{
		printf("Error :%s --> lua_pcall[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
		return;
	}

	// 这里就是空了,因为匿名函数也调用了,就pop出去了
	LuaUtiles::stackDump(g_State);

	/*2.取函数,就可以取得到函数了,就取到了大函数执行时定义的函数testAdd_Sub*/
	lua_getglobal(g_State,"testAdd_Sub");
	lua_pushnumber(g_State,10);
	lua_pushnumber(g_State,5);
	LuaUtiles::stackDump(g_State); // 就输出3个字段

	// 2个参数,2个返回值
	runOk = lua_pcall(g_State,2,2,NULL);
	if (runOk != 0)
	{
		printf("Error :%s --> lua_pcall[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
		return;
	}

	// 先返回的是add,后sub,于是sub在-1
	printf("testAdd_Sub(10,5) = %d,%d \n",lua_tointeger(g_State,-2),lua_tointeger(g_State,-1));
	LuaUtiles::stackDump(g_State); // 还剩下2个返回值
}




测试结果:






lua 引入txn对象 lua引用其他文件_lua_06