03. 重新编译 Lua 程序库

Par @Martin dans le
Tags :

通过上二篇的介绍, 已经可以在 C/C++ 程序中简单的使用 Lua 脚本, 然而那只是简单地在 VC 程序中直接访问 Lua API.
对于小项目来说这是可以的, 但更好的方式是抽象出简单的 Lua 程序库, 让它整合 C/C++ 和 Lua API 代码, 让其可以复用在多个项目中.
不是有首程序员版的<双截棍>吗, 里面有句歌词是这样的: 一个优秀的库函数, 一用好多年, 拷贝好带身边.
接下来就开始创建这个程序库.

同第一篇一样, 采用 VS2013 + lua-5.2.4 来进行编译, 先去 Lua 官网下载 Lua 源码: http://www.lua.org
然后修改源码, 使 Lua 支持中文的变量名及函数名.
接下来打开 VS2013 新建一个 win32 静态链接库 程序, 取名为 LuaLib, 不要勾选预编译头.
将 src 整个文件夹复制到工作目录下(注意这里是连 src 文件夹一起复制的, 第一篇中是复制的源码), 然后在刚新建的工程中添加除 luac.c 和 lua.c 外的其他源代码文件.

打开属性编辑框, 在工程的预处理器设置中添加一行 _CRT_SECURE_NO_WARNINGS, 并且设置当前工程的包含目录.

将下来为工程创建一个 CLua 类(源码传送门), 该类封装了一部分 Lua API 函数, 隐藏了 Lua 需要的初始化和关闭处理, 它的使用说明及源码分析将在后面进一步说明.

好, 接下来就开始编译 LuaLib 工程的 Debug 和 Release 版本, 将生成的 .lib 文件分别命名为 LuaLib_Debug.lib 和 LuaLib_Release.lib.

现在把 CLua.h 单独复制出来, 在文件开头添加如下代码:

#ifdef _DEBUG
#pragma comment(lib,"LuaLib_Debug.lib")
#else
#pragma comment(lib,"LuaLib_Release.lib")
#endif


好, 现在的 CLua.h 中的代码如下:

#pragma once

#ifdef _DEBUG
#pragma comment(lib,"LuaLib_Debug.lib")
#else
#pragma comment(lib,"LuaLib_Release.lib")
#endif

struct lua_State;

#define LuaGlue extern "C" int// 定义 LuaGlue 宏

extern "C" { // 定义一个 C 方式的 LuaFunctionType 类型函数指针
  typedef int(*LuaFunctionType)(lua_State *pLuaState);
};

class cLua {
public:
  cLua();
  virtual ~cLua();

  bool        RunScript(const char* pFilename);
  bool        RunString(const char* pCommand);
  const char* GetErrorString(void);

  bool        AddFunction(const char* pFunctionName, LuaFunctionType pFunction);

  const char* GetStringArgument(int num, const char* pDefault = NULL);
  double        GetNumberArgument(int num, double dDefault = 0.0);
  int         GetIntArgument(int num, int nDefault = 0);

  void        PushString(const char* pString);
  void        PushNumber(double value);
  void        PushInt(int value);

  void        SetErrorHandler(void(*pErrHandler)(const char* pError));

  lua_State*  GetScriptContext(void);

private:
  lua_State*  m_pScriptContext;
  void(*m_pErrorHandler)(const char *pError);
};


此时, 我们新的 Lua 程序库就制作完毕了, 使用时只要将 刚修改的 CLua.hLuaLib_Debug.libLuaLib_Release.lib 三份文件复制到工程目录下, 然后在合适的地方导入头文件 #include “CLua.h” 就可以了.


接下来使用 CLua 来实现第二篇中的例子.
打开 VS2013 新创建一个 win32 应用程序 工程, 将 CLua.h、LuaLib_Debug.lib 和 LuaLib_Release.lib 三份文件拷贝过去.
修改源码如下:

#include <windows.h>
#include "CLua.h"


LuaGlue LuaGule_Out(lua_State* L) {
  printf("This is a LuaGule! \r\n");
  return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
  cLua lua;
  lua.AddFunction("新函数", LuaGule_Out);
  lua.RunScript("C:/Users/Administrator/Desktop/test.lua");

  system("PAUSE");
  return 0;
}


可以看到, 相对第二篇中的程序, 新代码中的主要变化有:
*. 主程序中不再有初始化和关闭 Lua 环境的代码;
*. LuaGlue 函数的定义因为使用了 LuaGlue 宏而简化了;
*. 注册 LuaGlue 函数的 Lua API 被 CLua::AddFunction 代替;
*. 执行 Lua 脚本的 Lua API 被 CLua::RunScript 代替.