The problem is, a "require" keyword clears all global variables defined in the same file.
I am working on a project in c++. I use lua 5.3. The lua scripting style is:
1 all lua codes contains 1 common library file, and several small files each acting as a function.
2 when program start, the lua common library is compiled and executed, leave its global variables in the lua state. Then the small files are compiled not executed.
3 when program come to some point, relevant small lua file will be called(just as I say, every small file is a function). The global functions and variables defined in the common library will be used in the small lua file. That's why I compile and execute the common library when program start.
4 I'm very sure I only use 1 lua_State.
It worked fine, until I decide to split common library to multiple files, And use "require" in the main file. When program start, the main file will be compiled and executed.
Not a single code changed, just add come "require". Strange thing happened: All global variables and global functions are missing. When global function is called in small lua file, a "called a nil value" error raises.
I then make a experiment, I delete all "require" lines in the main library file, and it turns out that the global functions defined in the main library worked very well. I then require a empty file "simple.lua", the global functions defined in the main library was missing, cannot be called from the small lua file.
How to explain this? How can a "require" keyword clears all global variables defined in the same file?
in lua library:
require("simple")
function foo()
return 1+1
end
in lua small file
return foo()
result: attempt to call a nil value (global 'foo')
after delete "require", lua library:
function foo()
return 1+1
end
result: no error happens, 2 is returned
the c++ side code:
lua common library compile and excute:
int code = luaL_loadbuffer(L, s, strlen(s), "commonlib");
if(code != 0) {
std::string error = lua_tostring(L, -1);
lua_pop(L, 1);
return error;
}
code = lua_pcall(L, 0, 0, 0);
if(code > 0)
{
std::string ret = lua_tostring(L, -1);
lua_pop(L, 1);
return ret;
}
else
return ""; //empty string means no error
lua small function file compile:
int code = luaL_loadbuffer(L, s, strlen(s), "RULE1");
if(code != 0) {
std::string error = lua_tostring(L, -1);
lua_pop(L, 1);
return error;
}
else
{
return ""; //return empty means no error
}
The L in both code is the same lua state (or it won't work when "require" is removed). After compile, the small file function at the stack top is saved in global register with a reference variable "ref".
When call lua small file, the ref is pushed in the stack, a lua_pcall is used, nothing special.
Resolved the problem by myself.
Because of a duplicated copy/paste, the lua vm is created the second time afterwards. It's rather confusing because if there is no "require", everything is alright. It is a total coincidence.
All I learnt from this is: always double check the copy/paste code.
Related
I'm currently learning using LUA in C++ code. And I came to a point where I cannot figure out how to use C++ function in LUA's code.
I want to create simple function in c++ and then use it in LUA.
My approach is as follows (taken from some tutorials):
In main.cpp:
void write(const char* str) {
std::cout<<str<<std::endl;
}
static int l_write(lua_State* L) {
const char* str = lua_tostring(L, 1); // get function argument
write(str); // calling C++ function with this argument...
return 0; // nothing to return!
}
int main(){
lua_State* L = luaL_newstate();
luaL_openlibs(L); // load default Lua libs
if (luaL_loadfile(L, "test.lua")) {
std::cout<<"Error loading script"<<std::endl;
}
lua_pushcfunction(L, l_write);
lua_setglobal(L, "write"); // this is how function will be named in Lua
lua_pcall(L, 0, 0, 0); // run script
}
and in test.lua I've got:
write("Hello, world!")
write("The square root of 2 is "..math.sqrt(2))
x = 42
write("We can use variables too, x = "..x)
The problem appears in the very beginning of this code: I cannot even a load script luaL_loadfile(L, "test.lua") returns value 7 (which is as I checked NIME_AGAIN 7 /* temporarily out of resources */).
Everything else works just fine do provided I don't use my custom c++ functions. I can load values from LUAs file normally, can execute function ect.
I suppose that LUA after reading file already compiles it and then finds out name of function that does not exist, namely "write" and returns error in case of reading this file, is it possible? And if so how to resolve this problem, and how to use this feature correctly?
Mhm, guys. It is strange but I did lua_pop(L, 1) once, run and then delete it and now its working just fine O.o
I spent few hours trying to make it work without success. I have a C++ program with function exposed to Lua script. Lua script uses it like this:
setData('type', {a=1, b=2, c=3})
So first argument is string and second is table.
My current and best version of C++ setData function looks like this:
string sType;
map<string, uint8_t> mOptions;
int nArgs = lua_gettop(i_pState);
if (nArgs == 2)
{
if (lua_isstring(i_pState, 1) != 0)
sType = lua_tostring(i_pState, 1);
if (lua_istable(i_pState, 2) != 0)
{
lua_pushnil(i_pState);
while(lua_next(i_pState, 2))
{
uint8_t nValue = uint8_t(lua_tonumber(i_pState, -1));
string sKey = lua_tostring(i_pState, -2);
mOptions[sKey] = nValue;
lua_pop(i_pState, 1);
}
lua_pop(i_pState, 1);
}
}
return 0;
It works fine but causes "program.exe has triggered a breakpoint" error afterwards at the end when lua_close() function called.
What is wrong with this code?
UPD1. I'm not getting error without handling second argument.
UPD2. My code behaves very strangely. I think it could be issue of mixing extern "C" and C++ code.
UPD3. Turns out this is heap corruption. I can't understand where is cause. Probably this is not related to lua at all.
Finally! Recompilation of Lua code as C++ code didn't work (positive thing is I don't have to worry about extern "C" anymore). But I found two redundant lua_pop() calls. I removed them and now it works fine.
I didn't expect Lua to be so dangerous!
Good afternoon,
I am working on a LUA/C++ application, from which i need lua to be able to call other lua code recursively, e.g: C++ calls lua function, lua function calls another lua function from another string that is loaded using a registered C function that runs at the start of the first lua function;
here are the steps i am following:
lua_State* state = luaL_newstate();
luaL_openlibs(state);
lua_register(state, "secondLua", secondLua);
lua_getfield( _luaState, LUA_GLOBALSINDEX, "init" );
lua_pcall( _luaState, 0, 0, 0 );
int secondLua(lua_State* state){
char* myString[128] = "function init2()\n io.write(\"hello\")\n end";
luaL_loadstring(pLuaState, myString);
lua_getfield(pLuaState,LUA_GLOBALSINDEX, "init2"); // function init2 declared on myString
lua_pcall(pLuaState, 0, LUA_MULTRET, 0);
//getting "attempt to call a nil value" here
return 0;
}
Any help is appreciated, and second, i would like to know if there is a way i can name the second function "init" as well as the first one;
PS: I am using C++14 and lua 5.1 on LUAJIT, and i cant use lua's dofile;
lua_loadstring() compiles supplied source and puts Lua chunk on stack. It won't execute it though, so init2() still not defined when you expect that.
Replace lua_loadstring() with luaL_dostring() to actually run that chunk and define new lua functions. Or call lua_pcall() right after lua_loadstring(). Actually, luaL_dostring() does exactly that - lua_loadstring() followed by lua_pcall().
I have a Visual Studio 2008 C++03 application that uses Lua 5.2.1. I would like to extend Lua with a module called "foo", but when I call require("foo") in my Lua script, I get the error:
foo_test.lua:1: module 'foo' not found:
no field package.preload['process']
no file '!\lua\process.lua'
no file '!\lua\process\init.lua'
no file '!\process.lua'
no file '!\process\
My Lua script:
foo.bar()
My lua_foo.h file:
#include <lua.h>
extern "C" int luaopen_foo( lua_State* L );
My lua_foo.cpp file:
#include "lua_foo.h"
#include <lua.hpp>
static int l_bar( lua_State *L )
{
puts( "in bar()" );
return 1;
}
int luaopen_foo( lua_State *L )
{
static const luaL_Reg foo[] = {
{ "bar", l_bar },
{ NULL, NULL }
};
luaL_newlib( L, foo );
return 1;
}
These are compiled in to a static library "lua_foo.lib" which is statically linked to my main Lua executable.
Can anybody help me understand where I'm going wrong? thanks. I would prefer to avoid c++ wrappers (for now) and I do not want to package this library as a separate DLL from the main Lua engine.
EDIT
The issue was in the lua engine code. I added the luaL_requiref per #NicolBolas 's suggestion.
lua_State* L = luaL_newstate();
if( NULL != L )
{
luaL_openlibs( L );
luaL_requiref( token.get(), "foo", luaopen_foo, 1 );
luaL_dofile( L, "foo_test.lua" );
lua_close( L );
}
It's important to understand how the require machinery works and therefore why your code doesn't.
require is designed to look for Lua scripts in the file system and DLLs. Static libraries are not DLLs; indeed, as far as C/C++ is concerned, once you've finished linking, static libraries are no different than compiling those .c/.cpp files into your application directly.
When require finds a DLL with the appropriate name, it loads it and attempts to find a function named luaopen_<modname>, where <modname> is the name of the module. When it does, it will execute this function and store the value it returns in an internal database of loaded modules.
Calling require for a module will return whatever this function returned; if the module has already been loaded, then the return value is pulled from the database and returned directly.
Simply calling luaopen_foo will not do any of this. Indeed, simply calling this function is a bad idea; it is a Lua function and needs to be called as a Lua function (ie: you need to push it onto the Lua stack with lua_pushcfunction and call it with lua_call and so forth).
If you want to create a local module (one not in a Lua script or DLL, but exposed from your code), then you need to use the Lua facilities to do that. Specifically, use luaL_requiref:
luaL_requiref(L, "foo", luaopen_foo, 0);
Call this instead of calling luaopen_foo directly. This will automatically register the return value from luaopen_foo with require's internal database of loaded modules. Thus, subsequent calls to require "foo" will return this table.
One more thing: do is a keyword in Lua; you should not use keywords for Lua table key names. You can, but you always have to quote them (ie: your script must do foo["do"](...) to call it).
luaopen_foo creates a table with one function in it, but it doesn't expose it to Lua in any way. You need to assign it to something your scripts can access if you want to access it. You can do this with the package mechanism, or just assign it to a global (which is what Lua's built-in libraries do).
You have a field named do, which is problematic if you want to use foo.do syntax, because do is a keyword.
The return value of a Lua function tells Lua how many values you left on the stack. Your l_do function lies with its return value.
In the case of luaopen_foo, since you're calling it directly and ignoring it's return value, there's no need for it to return anything at all.
Change your code to this:
static int l_bar( lua_State *L )
{
puts("l_bar called.");
return 0;
}
void luaopen_foo( lua_State *L )
{
static const struct luaL_Reg foo[] = {
{ "bar", l_bar },
{ NULL, NULL }
};
luaL_newlib( L, foo ); // create table containing `bar`
lua_setglobal(L, "foo"); // assign that table to global `foo`
}
And change your script to this:
foo.bar()
I'm attempting to call a function inside of a lua file called test2.lua
This is the contents of test2.lua:
function abc(path)
t = {}
table.insert(t, "a")
return t
end
As you can see it takes a single input and returns a string.
Here is my C code. It's pretty simple. However my call getglobal in order to call that function does not work... lua_getglobal says it isn't a function when I test it... Any reason why this is? Shouldn't abc be a global function returnable inside of the source file? Why then does it only find nil for this global?
L = lua_open();
luaL_openlibs(L);
luaL_loadfile(L, "src/test2.lua");
lua_getglobal(L, "abc");
lua_pushstring(L, "coollll");
int error = 0;
if ((error = lua_pcall(L, 1, 1, 0)) == 0)
{
std::cout << "cool";
}
EDIT:
calling lua_getglobal is causing my program to break control regardless of using loadfile or dofile... any idea why?
lua_getglobal crashing program
The function luaL_loadfile() reads, parses, and compiles the named Lua file. It does not execute any of its content. This is important in your case because the statement function abc(path)...end has no visible effect until it is executed. The function keyword as you've used it is equivalent to writing
abc = function(path)
t = {}
table.insert(t, "a")
return t
end
In this form, it is clearer that the variable named abc is not actually assigned a value until the code executes.
When luaL_loadfile() returns, it has pushed an anonymous function on the top of the Lua stack that is the result of compiling your file. You need to call it, and lua_pcall() will do the trick. Replace your reference to luaL_loadfile() with this:
if (luaL_loadfile(L, "src/test2.lua") || lua_pcall(L, 0, LUA_MULTRET, 0)) {
// do something with the error
}
At this point, test2.lua has been executed and any functions it defined or other global variables it modified are available.
This is a common enough idiom, that the function luaL_dofile() is provided to load and call a file by name.
There is a second, more subtle issue in your code as presented. The function abc() uses a variable named t, but you should be aware that t as used is a global variable. You probably meant to write local t = {} at the top of abc().
It's not enough to call luaL_loadfile: this puts a chunk onto the stack. Either follow up with luaL_[p]call to execute the chunk (thus making the function available), or use luaL_dofile.