【问题标题】:Running luajit object file from C从 C 运行 luajit 目标文件
【发布时间】:2013-10-25 08:50:11
【问题描述】:

来自文档:http://luajit.org/running.html

luajit -b test.lua test.obj                 # Generate object file
# Link test.obj with your application and load it with require("test")

但没有解释如何做这些事情。我猜他们假设任何使用 Lua 的人也是 C 程序员,但我不是这样!我能得到一些帮助吗?以 GCC 为例。

我也想做同样的事情,除了 C 字节数组头。我也找不到这方面的文档。

luajit -bt h -n test test.lua test.h

这会创建头文件,但我不知道如何从 C 中运行它。谢谢。

【问题讨论】:

  • 您应该能够使用luaL_loadstring 来加载该C 数组。将函数返回堆栈后,您可以使用callpcall 之类的方法执行它,或者如果您以后需要它,可以将其保存到package.preload 表中——取决于您想要做什么.

标签: c lua luajit


【解决方案1】:

ma​​in.lua

print("Hello from main.lua")

app.c

#include <stdio.h>

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

int main(int argc, char **argv)
{
  int status;
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);
  lua_getglobal(L, "require");
  lua_pushliteral(L, "main");
  status = lua_pcall(L, 1, 0, 0);
  if (status) {
    fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
    return 1;
  }
  return 0;
}

Shell 命令:

luajit -b main.lua main.o
gcc -O2 -Wall -Wl,-E -o app app.c main.o -Ixx -Lxx -lluajit-5.1 -lm -ldl

-Ixx-Lxx 替换为 LuaJIT 包含和库目录。如果你已经将它安装在/usr/local(默认)中,那么大多数 GCC 安装都会发现它没有这两个选项。

第一个命令将 Lua 源代码编译成字节码并嵌入到目标文件main.o

第二个命令编译并链接最小的 C 应用程序代码。请注意,它也在嵌入的字节码中链接。 -Wl,-E 是强制性的(在 Linux 上)从可执行文件中导出所有符号。

现在将原始 main.lua 移开(以确保它真正运行的是嵌入式字节码而不是 Lua 源代码文件),然后运行您的应用程序:

mv main.lua main.lua.orig
./app
# Output: Hello from main.lua

【讨论】:

  • 太棒了!谢谢! luac也能生成.o文件吗?
  • 不,只有luajit -b 可以一步完成。有像 bin2c 这样的第 3 方工具可以帮助实现普通 Lua。查看the other answer 了解一般方法。
  • 有什么办法可以用assert(loadfile("main"))代替require("main")loadfile 似乎没有像require 那样找到链接模块,而是跑去搜索文件。我正在尝试将参数(从 app.c 使用 argv)传递给链接模块,但不能使用 require,因为它不会像 loadfile 那样将模块作为我可以调用的函数返回。跨度>
【解决方案2】:

基本用法如下:

  • 使用luajit生成头文件
  • #include 源文件中将引用其符号的标头
  • 根据您的用例将源代码编译为 lua 的可运行可执行文件或共享二进制模块。

这里有一个简单的例子来说明:

test.lua

return
{
  fooprint = function (s) return print("from foo: "..s) end,
  barprint = function (s) return print("from bar: "..s) end
}

test.h

// luajit -b test.lua test.h
#define luaJIT_BC_test_SIZE 155
static const char luaJIT_BC_test[] = {
27,76,74,1,2,44,0,1,4,0,2,0,5,52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15,
102,114,111,109,32,102,111,111,58,32,10,112,114,105,110,116,44,0,1,4,0,2,0,5,
52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15,102,114,111,109,32,98,97,114,
58,32,10,112,114,105,110,116,58,3,0,2,0,5,0,7,51,0,1,0,49,1,0,0,58,1,2,0,49,1,
3,0,58,1,4,0,48,0,0,128,72,0,2,0,13,98,97,114,112,114,105,110,116,0,13,102,
111,111,112,114,105,110,116,1,0,0,0,0
};

runtest.cpp

// g++ -Wall -pedantic -g runtest.cpp -o runtest.exe -llua51
#include <stdio.h>
#include <assert.h>

#include "lua.hpp"
#include "test.h"

static const char *runtest = 
"test = require 'test'\n"
"test.fooprint('it works!')\n"
"test.barprint('it works!')\n";


int main()
{
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);

  lua_getglobal(L, "package");
  lua_getfield(L, -1, "preload");
  // package, preload, luaJIT_BC_test
  bool err = luaL_loadbuffer(L, luaJIT_BC_test, luaJIT_BC_test_SIZE, NULL);
  assert(!err);

  // package.preload.test = luaJIT_BC_test
  lua_setfield(L, -2, "test");

  // check that 'test' lib is now available; run the embedded test script 
  lua_settop(L, 0);
  err = luaL_dostring(L, runtest);
  assert(!err);

  lua_close(L);
}

这很简单。此示例获取字节码并将其放入该程序的 lua 环境的package.preload 表中。然后其他 lua 脚本可以通过 require 'test' 使用它。 runtest 中的嵌入式 lua 源正是这样做并输出:

from foo: it works!
from bar: it works!

【讨论】:

  • 太棒了,谢谢!这就是我需要知道的,luaL_loadbuffer。您能告诉我使用常规 luac 是否可以实现相同的操作?
猜你喜欢
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 2014-07-19
  • 1970-01-01
  • 2023-03-27
  • 2010-12-23
  • 1970-01-01
相关资源
最近更新 更多