1

本文环境为windows10+visual studio 2013
lua在linux下编译、添加cc++模块还是比较直接方便的,资料也多,windows就那么直接了,经过一番折腾终于成功了

编译源码

首先去官网下载最新的源码,解压
打开vs的命令行工具,如图,若要64位编译打开x64工具
clipboard.png
进入解压的源码目录
clipboard.png
抛开本身链接的运行时库类型(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
clipboard.png
配置属性->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

clipboard.png

参考链接


silvercore
15 声望1 粉丝