前面的话

第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的。这次打算好好了解一下C跟lua是如何交互的

那么如何使用Lua语言?

lua是c语言编写的,而且开源。可以在https://www.lua.org官网上下载Lua的源码,然后尝试编译它!是不是跟我一样好激动,一直用集成环境,写上层语言,今天居然要碰编译了!!~ 可怎么编译呢?

让我们召唤出编译神器:gcc!【GNU编译器套件(GNU Compiler Collection)包括C、C++、Objective-C、Fortran、Java、Ada和Go语言的前端,也包括了这些语言的库(如libstdc++、libgcj等等)。】

在Mac上安装GCC

如果你安装了Homebrew的话,只要一行就可以了。

brew install gcc

装完后用

brew info gcc
或者
gcc -v

看一下是不是成功了

编译Lua

当你安装好了编译器后,编译lua就变得非常简单了



Lua官网的文档里有说编译方式, 但MakeFile里默认的是编译成静态链接库,被这个坑了,后面再说

建议安装在/opt目录下

sudo su
cd /opt
curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz
tar zxf lua-5.3.4.tar.gz
cd lua-5.3.4
make macosx test
make macosx install

安装好后用lua -v查看下如果有信息, 恭喜你,Lua编译好了!~

下面正式开干了~

写一个C调用Lua的Demo编译运行

add.c内容

//你需要include这几个lua头文件
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h" lua_State* L;
int
luaadd(int x, int y)
{
int sum;
/*函数名*/
lua_getglobal(L,"add");
/*参数入栈*/
lua_pushnumber(L, x);
/*参数入栈*/
lua_pushnumber(L, y);
/*开始调用函数,有2个参数,1个返回值*/
lua_call(L, 2, 1);
/*取出返回值*/
sum = (int)lua_tonumber(L, -1);
/*清除返回值的栈*/
lua_pop(L,1);
return sum;
} int
main(int argc, char *argv[])
{
int sum;
L = luaL_newstate(); /* 创建lua状态机 */
luaL_openlibs(L); /* 打开Lua状态机中所有Lua标准库 */
/*加载lua脚本*/
luaL_dofile(L, "add.lua");
/*调用C函数,这个里面会调用lua函数*/
sum = luaadd(99, 10);
printf("The sum is %d \n",sum);
/*清除Lua*/
lua_close(L);
return 0;
}

add.lua放到与C同级的目录下,里面写一个简单的函数,让C调用

function add(x,y)
return x + y
end

好了,终于到了用GCC编译的阶段了,直接gcc add.c一下看看行不行。



果然报错了!

这是因为没有把add.c里面的函数链接到我们前面编译出来的lua库里导致的。怎么让他指定链接哪个库呢?看GCC的文档得知-l参数可以指定要链接的库

-l参数和-L参数

-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文

件名有什么关系呢?

就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的

头lib和尾.so去掉就是库名了

那我们再试一下,gcc add.c -llua,这次编译出来了: a.out



执行成功!

如何让Lua调用C?

Lua调用C,我了解到的有3种方式

1.通过在C中注册函数给lua调用

2.封装成c动态链接库,在lua中require

3.在LuaJIT里面可以使用ffi高性能的调用C(但是IOS上不支持LuaJIT。。)

1.在C中注册函数给Lua

lua提供了lua_register函数注册C函数给lua端调用

hello.c

#include        <stdio.h>
#include <string.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h" static int l_SayHello(lua_State *L)
{
const char *d = luaL_checkstring(L, 1);//获取参数,字符串类型
int len = strlen(d);
char str[100] = "hello ";
strcat(str, d);
lua_pushstring(L, str); /* 返回给lua的值压栈 */
return 1;
} int
main(int argc, char *argv[])
{
lua_State *L = luaL_newstate(); /* 创建lua状态机 */
luaL_openlibs(L); /* 打开Lua状态机中所有Lua标准库 */
lua_register(L, "SayHello", l_SayHello);//注册C函数到lua const char* testfunc = "print(SayHello('lijia'))";//lua中调用c函数
if(luaL_dostring(L, testfunc)) // 执行Lua命令。
printf("Failed to invoke.\n"); /*清除Lua*/
lua_close(L);
return 0;
}

gcc -o hello hello.c -llua编译执行

2.调用C动态链接库

创建一个mylib.c的文件,然后我们把它编译成动态链接库

#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h> /* 所有注册给Lua的C函数具有
* "typedef int (*lua_CFunction) (lua_State *L);"的原型。
*/
static int l_sin(lua_State *L)
{
// 如果给定虚拟栈中索引处的元素可以转换为数字,则返回转换后的数字,否则报错。
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d)); /* push result */ /* 这里可以看出,C可以返回给Lua多个结果,
* 通过多次调用lua_push*(),之后return返回结果的数量。
*/
return 1; /* number of results */
} /* 需要一个"luaL_Reg"类型的结构体,其中每一个元素对应一个提供给Lua的函数。
* 每一个元素中包含此函数在Lua中的名字,以及该函数在C库中的函数指针。
* 最后一个元素为“哨兵元素”(两个"NULL"),用于告诉Lua没有其他的函数需要注册。
*/
static const struct luaL_Reg mylib[] = {
{"mysin", l_sin},
{NULL, NULL}
}; /* 此函数为C库中的“特殊函数”。
* 通过调用它注册所有C库中的函数,并将它们存储在适当的位置。
* 此函数的命名规则应遵循:
* 1、使用"luaopen_"作为前缀。
* 2、前缀之后的名字将作为"require"的参数。
*/
extern int luaopen_mylib(lua_State* L)
{
/* void luaL_newlib (lua_State *L, const luaL_Reg l[]);
* 创建一个新的"table",并将"l"中所列出的函数注册为"table"的域。
*/
luaL_newlib(L, mylib); return 1;
}

使用gcc -o mylib.so -fPIC -shared mylib.c -llua -ldl编译成so

然后创建一个lua文件,把我们编译出来的c库引入进来

--[[ 这里"require"的参数对应C库中"luaopen_mylib()"中的"mylib"。
C库就放在"a.lua"的同级目录,"require"可以找到。]]
local mylib = require "mylib" -- 结果与上面的例子中相同,但是这里是通过调用C库中的函数实现。
print(mylib.mysin(3.14 / 2)) --> 0.99999968293183

执行a.lua文件,后报错,说Lua存在多个虚拟机!

lua: multiple Lua VMs detected

为什么呢?查了一些资料发现因为lua默认编译的是静态链接库,这样会导致链接多个VM冲突。

那么我们自己再编译个lua解释器动态链接一下。

mylua.c

#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h" int main() { lua_State *L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, "a.lua") || lua_pcall(L, 0, 0, 0)) {
printf("%s", lua_tostring(L, -1));
} }

gcc -o mylua mylua.c -llua -ldl -lm -Wall

这样就能编译出mylua可执行文件

在命令行./mylua执行,成功打印出0.99999968293183

总结

gcc命令,编译lua,编译C动态链接库这些之前都接触的比较少。所以也爬了不少坑,哈哈哈。接下来要好好研究下怎么在c中解析二进制协议给lua调用,在c中怎么封装好luatable

参考资料:

https://www.cnblogs.com/pied/archive/2012/10/26/2741601.html

http://blog.csdn.net/vermilliontear/article/details/50947379

http://blog.csdn.net/casularm/article/details/316149

C和Lua之间的相互调用的更多相关文章

  1. uLua学习笔记(三):Unity3D和Lua之间的相互调用

    这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方 ...

  2. JAVA和C/C++之间的相互调用。

    在一些Android应用的开发中,需要通过JNI和 Android NDK工具实现JAVA和C/C++之间的相互调用. Java Native Interface (JNI)标准是java平台的一部分 ...

  3. C 程序与 C++ 程序之间的相互调用

    因为 C 编译器编译函数时不带参数的类型信息,只包含函数的符号名字.如 void foo( int x ) , C 编译器会将此函数编译成类似 _foo 的符号,C 链接器只要找到了调用函数的符号,就 ...

  4. lua编程之lua与C相互调用

    lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情 ...

  5. C#与Javascript变量、函数之间的相互调用

    原文地址:http://blog.csdn.net/wonsoft/article/details/2595743 C#与Javascript变量.函数之间的相互调用  一.javascript调用C ...

  6. Lua与C++相互调用

    {--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...

  7. Iframe父页面与子页面之间的相互调用

    iframe元素就是文档中的文档. window对象: 浏览器会在其打开一个HTML文档时创建一个对应的window对象.但是,如果一个文档定义了一个或者多个框架(即:包含一个或者多个frame或者i ...

  8. lua语言自学知识点----Lua与.Net相互调用

    知识点: LuaInterface作用是用来完成Lua与C#的相互调用. LuaInterface核心库:1.luainterface.dll 用于C#读取lua(放在bin目录同级) 2.luane ...

  9. Lua 与 OC 相互调用

    本文主要讲如何完成lua和object-c的相互调用.       lua是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...

随机推荐

  1. UVA12493 - Stars(求1-N与N互质的个数)欧拉函数

    Sample Input 3 4 5 18 36 360 2147483647 Sample Output 1 1 2 3 6 48 1073741823 题目链接:https://uva.onlin ...

  2. xcode 6 改动组织及开发人员

    搞个ios 开发死去活来的,各个地方说的都不一样,defaults write 不好用 在xcode6中 改动方法例如以下 改动create by __FULLUSERNAME___ 部分 Syste ...

  3. 教女朋友学Python运行环境搭建

    下班比较早,吃了饭没什么事,就和女朋友一起研究了Python. 编程语言有很多,为什么选择它呢?因为它火吧,没什么好解释的,下面开始第一步,环境搭建.网上的教程实在太多,各种系统的各种版本,本地链接下 ...

  4. JAVA入门[6]-Mybatis简单示例

    初次使用Mybatis,先手写一个hello world级别的例子,即根据id查询商品分类详情. 一.建表 create table Category ( Id INT not null, Name ...

  5. effective java学习笔记之不可实例化的类

    在没有显式声明一个类的构造方法时,编译器会生成默认的无参构造方法,在设计工具类时,我们通常将方法设置成静态方法,以类名.方法名的形式调用,此时这个类就没有必要创建实例,我们知道抽象类不可以被实例化,但 ...

  6. 使用docker+consul+nginx集成分布式的服务发现与注册架构

    一.环境说明: 1.一台虚拟机,该系统已经装好了docker: ip 192.168.10.224 虚拟网卡,与主机互通 操作系统rhel6 内核 2.6.32  64位 docker版本 1.7.1 ...

  7. Django安装与开发虚拟环境搭建01

    Django是一款基于python的MVT的web开发框架(m表示model,主要用于对数据库层的封装  ,v表示view,用于向用户展示结果,c表示controller,是核心,用于处理请求.获取数 ...

  8. 如何通过Mock API提高APP开发效率?

    APP开发过程中,如果可以在客户端的正常项目代码中,自然地(不影响最终apk)添加一种模拟服务器数据返回的功能,这样就可以很方便的在不依赖服务器的情况下展开客户端的开发. Mock API提供了这一问 ...

  9. InfluxDB:cannot use field in group by clause

    最近在使用InfluxDB时,发现一个很奇怪的问题,一个本来正常的功能,做了一次改动后,就不能正常显示了. 一.查询语句 SELECT MEMORY FROM "ACM_PROCESS_MO ...

  10. Linux下查看Go语言软件运行情况

    在Linux下,使用"jps"可以查看用Java语言写的软件的运行情况,如果要查看GO语言写的软件的运行情况,可以使用"gops",但这不是系统自带的,需要进行 ...