I am trying to load the example lproc program (described on Programming Lua, Chapter 30) into Lua and fouling up somehow. I am following this - http://www.lua.org/pil/26.2.html to get my c module into lua. Following are the steps that I've taken:
I have an lproc.h and lproc.c (containing exactly the functions laid out in Chapter 30 of the book). I am compiling lproc.c as --- gcc -c lproc.c -DLUA-USERCONFIG=\"lproc.h\"
I made a library out of lproc.o, named the same.
And then compiled lua.c as instructed. My header files contain the macro LUA_EXTRALIBS and the method declarations.
Went to the Lua interpreter and it gave the following errors:
> require "lproc"
stdin:1: module 'lproc' not found:
no field package.preload['lproc']
no file './lproc.lua'
no file '/opt/local/share/lua/5.1/lproc.lua'
no file '/opt/local/share/lua/5.1/lproc/init.lua'
no file '/opt/local/lib/lua/5.1/lproc.lua'
no file '/opt/local/lib/lua/5.1/lproc/init.lua'
no file './lproc.so'
no file '/opt/local/lib/lua/5.1/lproc.so'
no file '/opt/local/lib/lua/5.1/loadall.so'
stack traceback:
[C]: in function 'require'
stdin:1: in main chunk
[C]: ?
It seems that the module did not get registered, what would I need to do from Lua? Time is short and I am doing something horrendously wrong, any direction would be welcome.
Thanks,
Sayan
Here is a complete and fully portable minimal example of building a C library for Lua (works in Lua 5.1-5.3 and LuaJIT, for any platform):
With this example.c:
#include <lua.h>
int example_hello(lua_State* L) {
lua_pushliteral(L, "Hello, world!");
return 1;
}
int luaopen_example(lua_State* L) {
lua_newtable(L);
lua_pushcfunction(L, example_hello);
lua_setfield(L, -2, "hello");
return 1;
}
Put this rockspec file in the same directory, named example-1.0-1.rockspec:
package = "example"
version = "1.0-1"
source = {
url = "." -- not online yet!
}
build = {
type = "builtin",
modules = {
example = "example.c"
}
}
Then, run luarocks make. It will build the C code with the correct flags for your platform.
Your module is now ready to use!
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> example = require("example")
> print(example.hello())
Hello, world!
>
The easiest way is to create a shared library and load your C module dynamically. This way avoids having to rebuild the Lua interpreter. There are several examples in http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/ and explanations in http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/install.html and http://lua-users.org/wiki/BuildingModules
Related
In reading the documentation for zig, I was under the impression that zig could compile both C and C++ code. Consequently, I thought you could import a C++ file's header via #cImport and have zig build succeed. However, I can't seem to get this to work for a C++ library integration.
I first create my project, zig init-lib and then add my import to src/main.zig via the #cImport directive. Specifically, I #cInclude("hooks/hooks.h") the C++ header file of this library. If I attempt to zig build at this point, the build fails, unable to find the header. I fix this by modifying build.zig to lib.addIncludeDir("/usr/include/library").
Since this C++ library is now being parsed and uses the C++ standard library, the next error I get when I zig build is that the stdexcept header is not found. To fix this, I modify build.zig to lib.linkSystemLibrary("c++").
Lastly, and the error I'm stuck on now, is an assortment of errors in /path/to/zig-linux-x86_64-0.9.1/lib/libcxx/include/<files>. I get stuff like unknown type name '__LIBCPP_PUSH_MACROS, unknown type name 'namespace', or unknown type name 'template'.
Googling this, the only thing of partial relevance that I could find was that this is due to clang's default interpretation of .h files is as C files which obviously don't have namespace or template keywords, but I don't know what to do with that knowledge. LLVM on MacOs - unknown type name 'template' in standard file iosfwd
Does anyone have any insight as to how to actually integrate with a C++ (not pure C) library through zig?
Specifically, I #cInclude("hooks/hooks.h") the C++ header file of this library.
#cImport() is for translating C header files into zig so they can be used without writing bindings. Unfortunately, it does not support C++ headers. To use a C++ library, you'll have to write C bindings for it and then #cImport() those headers.
// src/bindings.cpp
#include <iostream>
extern "C" void doSomeCppThing(void) {
std::cout << "Hello, World!\n";
}
// src/bindings.h
void doSomeCppThing(void);
// build.zig
const std = #import("std");
pub fn build(b: *std.build.Builder) void {
const target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("tmp", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkLibC();
exe.linkSystemLibrary("c++");
exe.addIncludeDir("src");
exe.addCSourceFile("src/bindings.cpp", &.{});
exe.install();
}
// src/main.zig
const c = #cImport({
#cInclude("bindings.h");
});
pub fn main() !void {
c.doSomeCppThing();
}
I'm new to lua, this might be something quite simple, but I couldn't figure it out. I did all night search, read some posts here, but are not quite what I'm looking for. I finally worked out a lame solution that i'm not happy with, so I'm here to ask for help.
I'm trying to embed lua inside c++, and this program will run as part of an app on the iPhone, as we know, every iPhone app has a resource bundle, and the lua scripts are distributed with the bundle.
// I printed out the bundle path:
bundle directory /var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app
Say I have two script files (main.lua, mylib.lua) in the same folder, I put them in my Xcode project, organized like this:
somefolder
|--main.lua
|--mylib.lua
and main.lua is as below:
--main.lua
print(package.path)
require("mylib")
obviously I want to use code from mylib.lua, however, I got error from lua vm:
/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua
PANIC: unprotected error in call to Lua API (...090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app/test.lua:5: module 'mylib' not found:
no field package.preload['mylib']
no file '/usr/local/share/lua/5.2/mylib.lua'
no file '/usr/local/share/lua/5.2/mylib/init.lua'
no file '/usr/local/lib/lua/5.2/mylib.lua'
no file '/usr/local/lib/lua/5.2/mylib/init.lua'
no file './mylib.lua'
no file '/usr/local/lib/lua/5.2/mylib.so'
no file '/usr/local/lib/lua/5.2/loadall.so'
no file './mylib.so')
When I add a line modifying package.path, I got it running correctly:
--main.lua modified
print(package.path)
package.path = package.path .. ";/var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app/?.lua"
require("mylib")
But this is an absolute path, which should definitely be avoided.
One way to solve this problem is to provide lua a function from c, which returns the full path of lua file in ipa bundle at runtime to lua script, and concatenate the package.path with that path, but I think that shouldn't be the "official" way of doing this.
I noticed "./?.lua" inside package.path variable, I just wonder why mylib.lua can't be found, isn't it for files within the same directory?
Sorry for the blah, so the question is: how do I do the "require" decently in iOS environment?
Okay, I finally find a good answer and the job is done, thank to this answer.
So, the solution is to modify the path within c++ code, add this function
#include <string>
int setLuaPath(lua_State* L, const char* path) {
lua_getglobal(L, "package");
lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1)
std::string cur_path = lua_tostring(L, -1); // grab path string from top of stack
cur_path.append(";"); // do your path magic here
cur_path.append(path);
lua_pop(L, 1); // get rid of the string on the stack we just pushed on line 5
lua_pushstring(L, cur_path.c_str()); // push the new one
lua_setfield(L, -2, "path"); // set the field "path" in table at -2 with value at top of stack
lua_pop(L, 1); // get rid of package table from top of stack
return 0; // all done!
}
and then, call this function when init lua_State:
// yourfile.cpp
void runLua() {
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
OCCaller oc_caller;
std::string bundlePath = oc_caller.get_ios_bundle_path();
bundlePath.append("/?.lua");
setLuaPath(L, bundlePath.c_str());
....
}
your oc_caller class might look like this:
// OCCaller.h
#ifndef __LuaThirdTry__OCCaller__
#define __LuaThirdTry__OCCaller__
#include <iostream>
class OCCaller {
public:
OCCaller();
~OCCaller();
std::string get_ios_bundle_path();
};
#endif
impl file:
// OCCaller.mm
#include "OCCaller.h"
#import <Foundation/Foundation.h>
OCCaller::OCCaller() { }
OCCaller::~OCCaller() { }
std::string OCCaller::get_ios_bundle_path() {
NSString *bundlePath = [[NSBundle mainBundle]resourcePath];
return std::string([bundlePath UTF8String]);
}
Most likely, "." is not the folder containing main.lua, but a working directory (such as where xcode runs from). The app that runs your script probably runs it via a path, like
lua /full/path/to/your/main.lua
So having ./?.lua in LUA_PATH does not help here. Instead, you should have the script run a command to determine where it is running from, and append that to package.path. This should be the path part of arg[0]. So you could try (not tested):
local scriptPath = arg[0]
local dir = string.match(scriptPath, '^.*/')
package.path = package.path .. ';' .. dir .. '?.lua'
The arg is automatically populated by the interpreter, see Section 6 of Lua ref man.
You definitely don't need C to do what you want.
This is a revision on Bryophyte's answer. To me, this was far too complex. I'm also not sure why he did all these extra classes and used C++ strings instead of NSStrings. Here is my revised and hopefully easier to understand iOS code based on this solution:
-(void)addBundlePathToLuaState:(lua_State*)L
{
lua_getglobal(L, "package");
lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1)
const char* current_path_const = lua_tostring(L, -1); // grab path string from top of stack
NSString* current_path = [NSString stringWithFormat:#"%s;%#/?.lua", current_path_const, [[NSBundle mainBundle]resourcePath]];
lua_pop(L, 1); // get rid of the string on the stack we just pushed on line 5
lua_pushstring(L, [current_path UTF8String]); // push the new one
lua_setfield(L, -2, "path"); // set the field "path" in table at -2 with value at top of stack
lua_pop(L, 1); // get rid of package table from top of stack
}
I have created a Wireshark dissector in Lua for an application over TCP. I am attempting to use zlib compression and base64 decryption. How do I actually create or call an existing c library in Lua?
The documentation I have seen just says that you can get the libraries and use either the require() call or the luaopen_ call, but not how to actually make the program find and recognize the actual library. All of this is being done in Windows.
You can't load any existing C library, which was not created for Lua, with plain Lua. It's not trivial at least.
*.so/*.dll must follow some specific standard, which is bluntly mentioned in programming in Lua#26.2 and lua-users wiki, code sample. Also similar question answered here.
There are two ways You could solve Your problem:
Writing Your own Lua zlib library wrapper, following those standards.
Taking some already finished solution:
zlib#luapower
lua-zlib
ffi
Bigger list #lua-users wiki
The same applies to base64 encoding/decoding. Only difference, there are already plain-Lua libraries for that. Code samples and couple of links #lua-users wiki.
NOTE: Lua module package managers like LuaRocks or
LuaDist MIGHT save You plenty of time.
Also, simply loading a Lua module usually consists of one line:
local zlib = require("zlib")
The module would be searched in places defined in Your Lua interpreter's luaconf.h file.
For 5.1 it's:
#if defined(_WIN32)
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
#define LUA_CPATH_DEFAULT \
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
#else
How do I actually create or call an existing c library in Lua?
An arbitrary library, not written for use by Lua? You generally can't.
A Lua consumable "module" must be linked against the Lua API -- the same version as the host interpreter, such as Lua5.1.dll in the root of the Wireshark directory -- and expose a C-callable function matching the lua_CFunction signature. Lua can load the library and call that function, and it's up to that function to actually expose functionality to Lua using the Lua API.
Your zlib and/or base64 libraries know nothing about Lua. If you had a Lua interpreter with a built-in FFI, or you found a FFI Lua module you could load, you could probably get this to work, but it's really more trouble than it's worth. Writing a Lua module is actually super easy, and you can tailor the interface to be more idiomatic for Lua.
I don't have zlib or a base64 C library handy, so for example's sake lets say we wanted to let our Lua script use the MessageBox function from the user32.dll library in Windows.
#include <windows.h>
#include "lauxlib.h"
static int luaMessageBox (lua_State* L) {
const char* message = luaL_checkstring(L,1);
MessageBox(NULL, message, "", MB_OK);
return 0;
}
int __declspec(dllexport) __cdecl luaopen_messagebox (lua_State* L) {
lua_register(L, "msgbox", luaMessageBox);
return 0;
}
To build this, we need to link against user32.dll (contains MessageBox) and lua5.1.dll (contains the Lua API). You can get Lua5.1.lib from the Wireshark source. Here's using Microsoft's compiler to produce messagebox.dll:
cl /LD /Ilua-5.1.4/src messagebox.c user32.lib lua5.1.lib
Now your Lua scripts can write:
require "messagebox"
msgbox("Hello, World!")
Your only option is to use a library library like alien. See my answer Disabling Desktop Composition using Lua Scripting for other FFI libraries.
I'm struggling to figure out how to structure and then use internal dependencies in a Lua library I'm writing.
I've defined my library like this:
./alib.lua
./alib/adependency.lua
And the code:
-- File: ./alib.lua
local ad = require "alib.adependency"
module( "alib")
return {}
-- File: ./alib/adependency.lua
module( "adependency" )
return {}
This works a treat:
$ lua alib.lua
<no output>
Now let's "add" this library into another app:
./anapp.lua
./lib/alib.lua
./lib/alib/adependency.lua
And the new code:
-- File: ./anapp.lua
local alib = require "lib.alib"
local print = print
module( "anapp")
print "Hello"
Try to run it:
$ lua anapp.lua
lua: ./lib/alib.lua:2: module 'alib.adependency' not found:
no field package.preload['alib.adependency']
no file './alib/adependency.lua'
no file '/usr/local/share/lua/5.1/alib/adependency.lua'
no file '/usr/local/share/lua/5.1/alib/adependency/init.lua'
no file '/usr/local/lib/lua/5.1/alib/adependency.lua'
no file '/usr/local/lib/lua/5.1/alib/adependency/init.lua'
no file '/usr/share/lua/5.1/alib/adependency.lua'
no file '/usr/share/lua/5.1/alib/adependency/init.lua'
no file './alib/adependency.so'
no file '/usr/local/lib/lua/5.1/alib/adependency.so'
no file '/usr/lib/x86_64-linux-gnu/lua/5.1/alib/adependency.so'
no file '/usr/lib/lua/5.1/alib/adependency.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './alib.so'
no file '/usr/local/lib/lua/5.1/alib.so'
no file '/usr/lib/x86_64-linux-gnu/lua/5.1/alib.so'
no file '/usr/lib/lua/5.1/alib.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
[C]: in function 'require'
./lib/alib.lua:2: in main chunk
[C]: in function 'require'
anapp.lua:2: in main chunk
[C]: ?
Oh dear. Now I make a manual edit inside the library:
-- File: ./lib/alib.lua
-- local ad = require "alib.adependency" -- Doesn't work
local ad = require "lib.alib.adependency" -- Works
module( "alib")
return {}
And it works:
$ lua anapp.lua
Hello
It seems that Lua's require() relates paths relative to the ultimate script being run by Lua, not the script in which the require() is called.
Surely you don't have to manually fix the internal paths require()d inside of a Lua library every time you add one to your project... And I don't see how this can work from a unit test perspective either. What am I doing wrong?
I think the cleanest solution is to leave your library as it was, and then make whomever is using your library responsible for configuring the package.path correctly. In your setup that means the application should add the lib folder to the path:
package.path = './lib/?.lua;' .. package.path
See also related questions like Is there a better way to require file from relative path in lua as well as the manual for more about the path.
I'm trying to use https://github.com/aptiva/TLC
I try:
$ echo $LUA_PATH; echo "====="; find .; echo "====="; luajit-2.0.0-beta10 examples/window.lua
I get:
?;?.lua;./?/init.lua
=====
.
./examples
./examples/talkingcomputer.lua
./examples/window.lua
./lst
./objc
./objc/BridgeSupport.lua
./objc/dispatch.lua
./objc/init.lua
./README.md
=====
luajit-2.0.0-beta10: error loading module 'objc' from file 'objc':
cannot read objc: Is a directory
stack traceback:
[C]: ?
[C]: in function 'require'
examples/window.lua:5: in main chunk
[C]: ?
My question: what am I doing wrong? How do I load in the objc module?
Thanks!
Add ./?/init.lua to LUA_PATH.
Some further explanation on why the accepted solution works.
When a module is required, Lua uses environment variable LUA_PATH to find the location of the required module. The special symbol '?' is a wildcard that matches any string, thus when require("module") and LUA_PATH="?;./?.lua", Lua will search for 'module' and 'module.lua' in the current directory.
In the question above LUA_PATH was originally defined as:
LUA_PATH="?;?.lua;"
Once the solution was posted, the user added ./?/init.lua at the end of LUA_PATH, however it didn't work. The reason why it didn't work was that when Lua tries to solve require('objc') objc matches the first entry in LUA_PATH (?), and objc is a directory, thus the error.
The solution is to add ./?/init.lua at the beginning of LUA_PATH:
LUA_PATH="./?/init.lua;?.lua;?;"
With regard to LUA_PATH, it's important to notice that unlike environment variable PATH, directories are separated by semicolon (";"). Another way of specifying what directories to search from, it's using Lua variable package.path (inside a Lua file):
package.path = "./?/init.lua;"..package.path
local objc = require("objc")