lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


All right. At last....

if anybody cares for an answer.... After so many tries I have ditched all efforts to get a C++ bridge to work. Instead I focused on the C API and managed to pass pointers in using a modified version of my init. So, to answer it, please let me write what I would have loved to read when starting those efforts.

/* NOT part of C API */
void inject_myclass(lua_State *L, MyClass *n_my_class) {

	/* store the pointer to MyClass in global registry */
lua_pushlightuserdata(L, (void *)&KeyMyClass ); /* push address is some static data. Could be anything */ lua_pushlightuserdata(L, n_my_class); /* push value */

	/* registry[&KeyMyClass] = ret */
	lua_settable(L, LUA_REGISTRYINDEX);
}

/* part of C API */
int myclass_foo() {

	/* retrieve the pointer to MyClass from registry */
	lua_pushlightuserdata(L, (void *)&KeyMyClass );  /* push address */
	lua_gettable(L, LUA_REGISTRYINDEX);              /* retrieve value */
MyClass * mc = (MyClass *)lua_topointer(L, -1); /* convert to pointer */
	mc->foo();
	return 0;
}


... wrap it all up in a C exposed API ...

And then, when using it:

	lua_State *L = luaL_newstate();
	luaL_openlibs(L);

// call the module open function manually that would have been called by require() // With doing so, you don't have to require() your module within your script
	// and still use all your C API
	// So your DLL only is loaded once and no overhead.
	luaopen_my_module(L);

	// just as an example, create your object
	MyClass *mc = new MyClass()

	// inject into your running context.
	// With doing so, you replace the need to create your object
	// inside the context but re-use it.
	inject_myclass(L, mc);

	if (luaL_dofile(L, "luatest_reuse.lua")) {
		std::cerr << "Lua program returned an error: \n";
		std::cerr << lua_tostring(L, -1);
		std::cerr << std::endl;
		lua_close(L);
	}

	// Your object is alive and well after that
	delete mc;

So your script can be as simple as that...

[[
mymodule.foo()
]]

...and will call foo() on your object, leaving it alive.

Concluding I would like to add that while this serves the purpose that I originally started with, it is hard for me to understand the hassle that comes with it. The use cases strikes me as one of the simplest things that I could do with an embedded language and I cannot believe how complicated it was and how much time it cost me to make this happen. And how much of a hack this seems to me. It just screams non-canonical. All this messing around with lightuserdata. The name itself... I don't know. Isn't that a standard use case for an embedded language to use things outside? Wouldn't it be better to offer one function that exposes the pointer inside the script and call it push_pointer() or some such understandable way? The three lines that do the trick in my example above say to me "I'm using that mechanism called lightuserdata although this is meant for something else."

Also, please let me add a tad criticism. When I look at the wiki page for language bindings ( http://lua-users.org/wiki/BindingCodeToLua ) I see no less than 22 projects and mechanisms that bind C++ for use inside Lua. After filtering out the projects that are dead, unmaintained or require an own library and therefore link dependency I ended up with a handful of candidates, three of which I pursued to a working implementation (including LuaJit ffi). And none worked with objects being passed into. Out of 22. Seriously? Sorry for sounding harsh but it seems preferable to me to have one working solution instead of 22. It may be because of MSVC90 here but it's not like that's a niche compiler that nobody really uses. Does the Lua community pursue any efforts in centralizing those projects and perhaps boil them down for direct inclusion into the distribution? Or maybe recommend one?
</rant>

Sorry for this, but sometimes it can be helpful to know how outsiders see a system.

In any case, thank you so much for your help. It was very interesting to get to know Lua. I'm gonna do some trials now and see how it performs and compares to other candidates.

Cheers,

Stephan