【编程语言学习】Lua程序设计(2) lua调用C
本文最后更新于 38 天前,其中的信息可能已经有所发展或是发生改变。

Lua调用C的几种主流方法

  1. 封装成c动态链接库,在luarequire
  2. 通过在C中注册函数给lua调用
  3. LuaJIT里面可以使用ffi高性能的调用C

调用C动态库

C函数封装成动态库,通过luaL_newlib 将C 函数打包成一个 Lua 模块,以供 Lua 脚本使用

创建文件并保持格式如下

.
|   Makefile
|   test.lua
|
+---inc
|       luaLib.h
|
\---src
        cFuntion.c
        luaLib.c

文件内容如下

test.lua

--设置.so搜寻路径,若动态库与lua文件在同一目录下则无需指定
--package.cpath = "./?.so" 

local myLib = require "mylib"
local add

myLib.printDemo()

add = myLib.addDemo(1, 12)
print(add)

Makefile

CC := gcc
SRCS := $(wildcard ./src/*.c)
OBJS := $(SRCS:.c=.o)
INC_DIR = -I ./inc/
CFLAGS := -Wall -fPIC

# 使用 pkg-config 自动探测 LUA_PKG(仍支持外部覆盖)
PKG_CONFIG ?= pkg-config
LUA_CANDIDATES := lua5.4 lua5.3 lua5.2 luajit lua
LUA_PKG ?= $(firstword $(foreach m,$(LUA_CANDIDATES),$(if $(shell $(PKG_CONFIG) --exists $(m) && echo yes),$(m))))
ifeq ($(strip $(LUA_PKG)),)
$(error 未找到可用的 Lua 开发包,请安装 liblua5.x-dev 或手动设置 LUA_PKG=lua5.4 等)
endif
$(info Using LUA_PKG=$(LUA_PKG))

PKG_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG))
PKG_LIBS   := $(shell $(PKG_CONFIG) --libs   $(LUA_PKG))

PRODUCT := mylib.so

all: $(PRODUCT)

$(PRODUCT): $(OBJS)
	$(CC) -shared -o $@ $^ $(PKG_LIBS)

src/%.o: src/%.c
	$(CC) -c $< -o $@ $(CFLAGS) $(INC_DIR) $(PKG_CFLAGS)

.PHONY: clean
clean:
	rm -f $(PRODUCT) $(OBJS)

luaLib.h

#ifndef __MYLIB_H__
#define __MYLIB_H__

#include <lua.h>
#include <lauxlib.h>

int luaLibAdd(int a, int b);
int luaLibPrint();

#endif

cFunction.c

#include <stdio.h>
#include "luaLib.h"
 
/**
 * 定义在lua中可调用的函数,要遵循规范:返回值必须为int,需传入lua_State
 */
int luaLibAdd(int a, int b)
{
	return a + b;
}

int luaLibPrint()
{
	char *str = "lua calls the C function demo";
	printf("%s\n", str);
	return 0;
}

luaLib.c

#include <stdio.h>
#include "luaLib.h"
 
/**
 * 定义在lua中可调用的函数,要遵循规范:返回值必须为int,需传入lua_State
 */
int addDemo(lua_State *L)
{
	int num_a = luaL_checkinteger(L, 1);
	int num_b = luaL_checkinteger(L, 2);
	int num_c;

	num_c = luaLibAdd(num_a, num_b);
	lua_pushnumber(L, num_c);
	
	return 1;
}

int printDemo(lua_State *L)
{
	luaLibPrint();
	return 0;
}

int luaopen_mylib(lua_State *L)
{
	luaL_Reg Clib[] = 
	{
		{"addDemo", addDemo},
		{"printDemo", printDemo},
		{NULL, NULL}
	};
 
	luaL_newlib(L, Clib);
	return 1;
}

运行结果

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

程序主体在C中运行,C函数注册到Lua中。C调用LuaLua调用C注册的函数,C得到函数的执行结果

创建文件并保持格式如下

.
    demo.c
    Makefile

文件内容如下

demo.c

#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int addDemo(lua_State *L)
{
	int num_a = luaL_checkinteger(L, 1);
	int num_b = luaL_checkinteger(L, 2);
	int num_c = num_a + num_b;

	lua_pushnumber(L, num_c);
	
	return 1;
}

int main(void)
{
    lua_State *L = luaL_newstate();    // 创建Lua状态机。
    luaL_openlibs(L);                  // 打开Lua状态机"L"中的所有Lua标准库。

    lua_pushcfunction(L, addDemo);
    lua_setglobal(L, "addDemo");      // 弹出栈顶元素,并在Lua中用名为"addDemo"的全局变量存储。

    const char* testfunc = "add = addDemo(1,2);print(\"add =\",add)";

    if(luaL_dostring(L, testfunc)) {
        printf("Failed to invoke.\n");
    }

    lua_close(L);    // 关闭Lua状态机。

    return 0;
}

Makefile

CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
CFLAGS := -g -Wall
PRODUCT := a.out

# 使用 pkg-config 自动探测 LUA_PKG(仍支持外部覆盖)
PKG_CONFIG ?= pkg-config
LUA_CANDIDATES := lua5.4 lua5.3 lua5.2 luajit lua
LUA_PKG ?= $(firstword $(foreach m,$(LUA_CANDIDATES),$(if $(shell $(PKG_CONFIG) --exists $(m) && echo yes),$(m))))
ifeq ($(strip $(LUA_PKG)),)
$(error 未找到可用的 Lua 开发包,请安装 liblua5.x-dev 或手动设置 LUA_PKG=lua5.4 等)
endif
$(info Using LUA_PKG=$(LUA_PKG))

PKG_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG))
PKG_LIBS   := $(shell $(PKG_CONFIG) --libs   $(LUA_PKG))

all: $(PRODUCT)

$(PRODUCT): $(OBJS)
	$(CC) -o $@ $^ $(PKG_LIBS)

%.o: %.c
	$(CC) -c $< -o $@ $(CFLAGS) $(PKG_CFLAGS)

.PHONY: clean
clean:
	$(RM) -f $(PRODUCT) $(OBJS)

运行结果

上一篇
下一篇