|
Roberto Ierusalimschy wrote:
In Windows, blocks created by a dll cannot be free in a different dll (is that right?), even if both dlls contain exactly the same code. So, to avoid problems in Windows, the "correct" way to use loaded objects is to make Lua itself a dll loaded by the main program, so that the main program, Lua, and any extra module all share a single copy of Lua.
The problem is global data. The C runtime has globals, such as to track the free space arena. If you link the C runtime statically to the exe (which is an option), and dynamically to a DLL (which is always the case, AFAIK), then you end up with two free space managers. Freeing a block allocated from one in the other causes trouble.
The solution is to always link the C runtime dynamically (i.e. against MSVCRT.DLL), also in the main exe. Then, the same arene gets used for all allocations. There can be more globals which cause trouble (strftime used to be a trouble spot, IIRC).
Lua itself could be linked in statically, even on Windows AFAIK (but they still need to have dllexport, and you still need an import lib). On most Unix systems that also works (that's what -E / -export-dynamic is about). This is called "back-linking", i.e. a shared lib will resolve against what is already loaded. It doesn't work on all systems, and even on Windows I understand that it's tricky to get this right. With shared libs which are loaded at run time, this is controlled by the RTLD_GLOBAL flag on Unix.
So the easiest way out is to put common code such as Lua in a shared lib, and have both the main exe and all shared libs which do lua_* calls linked to it dynamically. Here's an old picture:
http://www.equi4.com/old/extuse1.gifIt all works fine that way (as Python has proven for years: Python builds as a shared lib on Windows, and as an exe on systems such as Linux, Solaris, etc). Not sure about AIX.
But it remains tricky. The other approach is a COM-like dispatch as in Tcl >= 8.1: set up a call vector and pass it to the called shared lib, which then issues calls *back* into the main app. It requires a lot of footwork to make this work (Tcl's "stubs", which re-routes all Tcl_* calls via a bunch of generated #define's), but it completely resolves all such issues. It simplifies extensions greatly, because they need not be linked to any particular version/location of (in this case) a lua shared lib and can continue to work with newer releases. In essence, the calling party hands over a jump vector to the shared lib with *all* the calls it can do (i.e. lua_* calls). No need for shared lua libs, nor even for LD_LIBRARY_PATH, since the shared lib no longer has unresolved externals (other than the standard C runtime).
-jcw