本文环境为windows10+visual studio 2013
lua在linux下编译、添加cc++模块还是比较直接方便的,资料也多,windows就那么直接了,经过一番折腾终于成功了
编译源码
首先去官网下载最新的源码,解压
打开vs的命令行工具,如图,若要64位编译打开x64工具
进入解压的源码目录
抛开本身链接的运行时库类型(MD、 MT),编译可分两种,链接静态库或动态库
编译链接静态lib,最终生成lua.exe(解释器)、luac.exe(编译器)、lua.lib(静态链接库)
静态链接的lua.exe不依赖dll,但是无法添加新的c\c++模块,因为相关函数不能link多份,只想把lua作为程序嵌入脚本或者运行纯lua静态链接更便捷
cl /MD /O2 /c *.c
ren lua.obj lua.o
ren luac.obj luac.o
lib /OUT:lua.lib *.obj
link /OUT:lua.exe lua.o lua.lib
link /OUT:luac.exe luac.o lua.lib
1、各个c文件编译成obj文件
2,3、 lua.obj、luac.obj含有main函数,生成lib或dll时要排除
4、合并obj生成lib库,包含所有obj的函数
5、lua.o中有main函数,链接lua.lib生成lua.exe
6、luac.o中有main函数,链接lua.lib生成luac.exe
编译链接动态dll,最终生成lua.exe(解释器)、luac.exe(编译器)、lua.dll(静态链接库)、lua.lib(导出库)
动态链接的lua.exe依赖dll,后续可添加新的dll模块
cl /MD /O2 /c /DLUA_BUILD_AS_DLL *.c
ren lua.obj lua.o
ren luac.obj luac.o
link /DLL /IMPLIB:lua.lib /OUT:lua.dll *.obj
link /OUT:lua.exe lua.o lua.lib
link /OUT:luac.exe luac.o *.obj
1:在cl编译的时候加入了一个自定义的宏 /DLUA_BUILD_AS_DLL 这是因为在luaconf.h文件中定义了LUA_BUILD_AS_DLL宏:
#if defined(LUA_BUILD_AS_DLL) /* { */
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
#else /* }{ */
#define LUA_API extern
#endif
它控制了__declspec(dllexport)和__declspec(dllimport)的定义,必须加上这个开关才有这两个定义,否则编译出来的DLL没有任何导出函数。luac.c中定义了LUA_CORE,最后不要链接动态库
2、3:重命名编译成的lua.obj luac.obj 在生成dll库时不需要这两文件(含有main函数),否则在链接生成最终的exe文件时会有函数重定义的错误。
4:链接1步中编译出的obj文件,生成lua.dll和导出库lua.lib,如果没有定义DLUA_BUILD_AS_DLL 宏,不会生成导出库lua.lib,无法进行最后的链接,lua.lib中只有声明导出的函数(LUA_API),所以链接生成luac.exe时要链接*.obj文件。
5:链接1步中编译出的lua.obj文件(lua.o),和4步中生成的导出库,生成lua.exe(必须有lua.dll才能运行)。
6:链接luac.o,不能链接llua.lib导出库(只有导出函数,有些函数找不到),重新链接所有的obj,运行不依赖lua.dll,因为*.obj是__declspec(dllexport)编译生成,链接还会生成luac.lib导出库,应该和lua.lib是一样的
也可以在vs建立相关项目,将全部源码文件添加,根据需要排除或添加lua.cluac.c,配置相关属性进行编译
编译脚本
两种编译方式写了bat脚本(同样要在vs的命令行工具中运行),放到解压目录,会将编译结果以及头文件拷贝到相应目录
build_dll.bat:
@echo off
rem out lua.exe luac.exe lua.lib lua.dll
set ver=5.3.0
set op=build_dll
md %op%
md %op%\include\
cd src
cl /MD /O2 /c /DLUA_BUILD_AS_DLL *.c
ren lua.obj lua.o
ren luac.obj luac.o
link /DLL /IMPLIB:lua.lib /OUT:lua.dll *.obj
link /OUT:lua.exe lua.o lua.lib
link /OUT:luac.exe luac.o *.obj
move *.exe ..\%op%\
move *.lib ..\%op%\
move *.dll ..\%op%\
del /q *.obj
del /q *.o
del /q *.exp
copy lua.h ..\%op%\include\
copy lualib.h ..\%op%\include\
copy lauxlib.h ..\%op%\include\
copy lua.hpp ..\%op%\include\
copy luaconf.h ..\%op%\include\
cd ..\
build_static.bat:
@echo off
set ver=5.3.0
set op=build_static
rem out lua.exe luac.exe lua.lib
md %op%
md %op%\include\
cd src
cl /MD /O2 /c *.c
ren lua.obj lua.o
ren luac.obj luac.o
lib /OUT:lua.lib *.obj
link /OUT:lua.exe lua.o lua.lib
link /OUT:luac.exe luac.o lua.lib
move *.exe ..\%op%\
move *.lib ..\%op%\
move *.dll ..\%op%\
del /q *.obj
del /q *.o
del /q *.exp
copy lua.h ..\%op%\include\
copy lualib.h ..\%op%\include\
copy lauxlib.h ..\%op%\include\
copy lua.hpp ..\%op%\include\
copy luaconf.h ..\%op%\include\
cd ..\
编写cc++模块
1.在vs中建立c++项目dlltest,属性->常规->配置类型,选择动态库dll,
2.如果是拷贝所有lua源码去除lua.c、luac.c添加到项目,需要在属性->C/C++->预处理器中,添加宏定义LUA_BUILD_AS_DLL,
如果已有编译成的导入库lua.lib和lua.dll,不用定义LUA_BUILD_AS_DLL宏,导出库中本就是导出函数
拷贝头文件与lua.lib
配置属性->C/C++->常规->附加包含目录 和 配置属性->链接器->常规->附加库目录
或者直接在代码中写 #pragma comment(lib, "路径")
3.添加源文件dlltest.cpp
#include "../build_dll/include/lua.hpp"
#pragma comment(lib, "../build_dll/lua.lib")
#define EXTERN_C extern "C"
#define API_DECLSPEC __declspec(dllexport)
EXTERN_C static int l_mystr(lua_State *L)
{
lua_pushstring(L, "looyer");//返回的第一个参数, 字符串“looyer”
lua_pushnumber(L, 37);//返回的第二个参数,数字37
//返回第三个参数table = {['ac'] = 17, [2] = "bn"}
lua_newtable(L);//在栈顶创建一个table
//方法一,设置table的键和值
lua_pushstring(L, "ac");
lua_pushnumber(L, 17);
lua_settable(L, -3);//在table中设置键值对['ac'] = 17, 设置后,自动pop掉栈顶的两个元素
//方法二,设置table的键和值
lua_pushstring(L, "bn");
lua_setfield(L, -2, "2");//将栈顶元素设置为键“2”的值,并且赋个索引为-2的栈中table
return 3;//返回参数的个数
}
//演示输入多个参数,检查输入一个数字,一个字符串,一个table
EXTERN_C static int l_myadd(lua_State *L)
{
int a = luaL_checknumber(L, 1);
const char *p = luaL_checkstring(L, 2);
lua_getfield(L, 3, "yt");//将第三个参数table的“yt”键的值压入栈
int b = luaL_checknumber(L, -1);//取出该“yt”键的值
lua_pushnumber(L, a + b);
return 1;//返回一个参数
}
//只有luaopen_dlltest需要dllexport
//_后要和生成的dll同名否则require找不到对应的库
EXTERN_C API_DECLSPEC int luaopen_dlltest(lua_State *L)
{
luaL_Reg l[] = {
{ "mystr", l_mystr },
{ "myadd", l_myadd },
{ NULL, NULL },
};
luaL_newlib(L, l);
return 1;
}
生成,在Release或Debug目录下拷贝dlltest.dll到运行目录
在运行目录编写mytest.lua
dlltest = require "dlltest"
local cpath = package.cpath..";"
print("-----------start-------------")
for path in string.gmatch(cpath, "(.-);") do
print(path)
end
a, b, c = dlltest.mystr()
print(a,b,c)
print(c[ac], c[2])
print(c["ac"], c[2])
print(c["ac"], c["2"])
a = 10
b = "tty"
c = { ["yt"] = 19}
print(dlltest.myadd(a,b, c))
print("-----------end-------------")
在运行目录打开命令行,用lua.exe 运行mytest.lua