Lua 作为一种小巧的语言,一般都是嵌入到 C/C++ 中作为扩展语言,但是也可以作为独立的脚本语言使用,并且可以使用 C/C++ 编写扩展模块。在参考资料 [1] 中有怎样用 C/C++ 编写模块的介绍,但是比较零散,也不是很详细,所以在这里整理一下。

这里使用的 Lua 版本是 5.2.3,系统是 Debian 7。

Hello, world!

不废话,还是先看一下经典的 “Hello, world!” 例子。

luahello.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
 
static int l_hello(lua_State* l)
{
printf("Hello, world!\n");
return 0;
}
 
static const struct luaL_Reg hello_lib[] = {
{"hello", l_hello},
{NULL, NULL},
};
 
int luaopen_luahello(lua_State* l)
{
luaL_newlib(l, hello_lib);
return 1;
}

这里用到的一个函数是

void luaL_newlib (lua_State *L, const luaL_Reg *l);

它其实是一个宏,被定义为

(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

作用是先创建一个新的 table,再把指定的函数注册到这个 table 中。

要注意的是,创建自定义模块的函数都需要以 “luaopen_” 作为函数名的前缀,这样在 require 中加载某个模块(例如这里的模块名叫 “luahello”)的时候,Lua 会去找相应的创建模块的函数(例如 luaopen_luahello),然后调用这个函数,获得对应的返回值,之后就可以被使用了。

另外由于 require 的参数是一个字符串,如果我们写成 “require(‘a.b’)” 也是合法的,但是在 C 语言中无法定义 “luaopen_a.b” 这样一个函数。Lua 很智能地为我们做了转换,将 “.” 转换成 “_”。

编译和执行

先说一下静态加载的方法。

查看 src/Makefile,可以发现 Lua 为我们预留了一些编译变量,例如 MYCFLAGS 和 MYLIBS 等。如果需要解析器能使用我们自己编写的模块,只需把我们的模块加到这些变量中。根据参考资料 [1] 的建议,还需要修改 luaL_openlibs(),把 luaopen_hello() 添加到 loadedlibs[] 这个数组中,让 Lua 解析器调用相应的函数后才能被调用。如果要把上面的模块编译到 Lua 解析器中,可以把 luahello.o 加入到MYOBJS 中:

make posix MYOBJS=`pwd`/luahello.o -C /path/to/lua

重新编译之后就能使用我们自定义的函数了。

可见每增加一个模块就要重新编译一次 Lua 显然是不现实的,因此更好的方法是采用动态加载。

Lua 默认只生成静态链接库 liblua.a,编译 Lua 解析器也是用的静态链接。但是 Lua 的实现中用到了一个全局变量,如果多次链接 liblua.a 会出问题(见参考资料 [2]),因此如果主程序和模块都分别链接了 liblua.a,接着主程序加载了模块运行会导致程序崩溃,需要使用选项 “-Wl,-E” 重新编译 Lua 解析器;为了能加载动态链接库,还需要打开相应的选项,在 Linux 下完整的编译命令为:

make posix MYCFLAGS="-DLUA_USE_DLOPEN -Wl,-E" MYLIBS="-ldl"

重新编译后应该就能正常加载运行脚本了。作为实验封装了一个 MySQL 的 Lua 客户端,放在 这里

参考资料

[转]使用 C 编写 Lua 模块的更多相关文章

  1. lua 模块与环境

    编写一个模块的最简单方法: -- complex.lua -- 模块实际上是一个表 complex = {} -- 定义模块函数 function complex.add(c1,c2) ... end ...

  2. 为Lua5.3编写C模块简单示例

    为Lua5.3编写C模块简单示例 一.编译安装Lua5.3 MSVC 命令行安装脚本: @echo off md bin md lib md include cd src cl /c /nologo ...

  3. Lua模块的加载与内存释放

    今天早上听说一件事情让我觉得很诡异的事情:公司线上的一款游戏,加载一份配置资源后,内存涨了几十M,然后内存再也下不来了.因为好奇,所以要来了最大的一个配置文件(4.5M,去除空格与换行后的大小),进行 ...

  4. Step By Step(Lua模块与包)

    Step By Step(Lua模块与包) 从Lua 5.1开始,我们可以使用require和module函数来获取和创建Lua中的模块.从使用者的角度来看,一个模块就是一个程序库,可以通过requi ...

  5. Nginx使用Lua模块实现WAF

    前言:最近一段时间在写加密数据功能,对安全相关知识还是缺少积累,无意间接触到了WAF相关知识,刚好Nginx可以实现WAF功能,也简单学习了Lua这门语言,分享下 一.WAF产生的背景 过去企业通常会 ...

  6. 【转】PowerShell入门(十一):编写脚本模块

    转至:http://www.cnblogs.com/ceachy/archive/2013/03/08/PowerShell_Script_Module.html 现在通过编写模块就可以在PowerS ...

  7. 用Perl编写Apache模块续二 - SVN动态鉴权实现SVNAuth 禅道版

    代码地址:https://code.csdn.net/x3dcn/svnauth 以禅道项目管理系统的数据库结构为标准,实现了可用的svn authz验证功能. 以用户名.密码.项目的acl开发程度o ...

  8. 用Perl编写Apache模块

    前言 Apache被许多大流量网站所嫌弃,但很多企业级的场景则更为适用. Apache httpd 从 2.0 之后,已经不仅仅局限于一个 http 的服务器,更是一个完善而强大.灵活而健壮且容易扩展 ...

  9. vim编译安装+lua模块

    vim编译安装+lua模块 使用背景:代码自动补全插件,需要安装lua模块 安装准备,首先下载安装vim所依赖的其它安装包,ncurses,lua,readline,vim 源码下载,编译安装 ncu ...

随机推荐

  1. IDispatch error #3092

    在采用ADO访问ACCESS数据库的时候,出现IDispatch error #3092错误的原因之一是在SQL语句中使用了保留关键字.比如:如果表的名称为User 则会出现该错误.,若字段为valu ...

  2. elasticsearch之python备份

    一:elasticsearch原理 Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎.无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进.性能最好的.功 ...

  3. Oracle软件开发分析

    软件开发的步骤可大致分为: 1.需求分析 2.系统设计 3.编码实现 4.系统测试 5.运行维护 student class     多对一 sno name age gender cid id  c ...

  4. 深入浅出设计模式——代理模式(Proxy Pattern)

    模式动机在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到 ...

  5. iOS - Xcode 插件

    Xcode 插件 Xcode 插件安装目录: ~/library/Application Support/Developer/Shared/Xcode/Plug-ins Xcode 插件大全 http ...

  6. Redis redis-cli常用操作

    一.安装 二.连接 在bin目录下./redis-cli -p port -a password 授权auth password 查看是否连接成功 ping PONG表示连接成功 三.键值相关命令 k ...

  7. jQuery Easing 使用方法及其图解

    jQuery Easing 使用方法及其图解,非常详尽:http://blog.sina.com.cn/s/blog_70a3539f0102v8az.html

  8. 【转】 strcpy和memcpy的区别

    strcpy和memcpy都是标准C库函数,它们有下面的特点.strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符. 已知strcpy函 ...

  9. javascript中数组常用的方法

    在JavaScript中,数组可以使用Array构造函数来创建,或使用[]快速创建,这也是首选的方法.数组是继承自Object的原型,并且他对typeof没有特殊的返回值,他只返回'object'. ...

  10. 使用 Hive 作为 ETL 或 ELT 工具

    用来处理数据的 ETL 和 ELT 工具的概述 数据集成和数据管理技术已存在很长一段时间.提取.转换和加载(ETL)数据的工具已经改变了传统的数据库和数据仓库.现在,内存中转换 ETL 工具使得提取. ...