This code demonstrates a problem with our code using swig to call C++ code from lua. Using swig 2 we apply a hacky fix, which breaks functionality using swig 4.
We have several C++ libraries with lua bindings and want to be able to use them together. Several of these will have classes with the same name, living in different namespaces:
namespace A {
struct Foo;
}
namespace B {
struct Foo;
}
SWIG does not support this, but we have simple but hacky fix, by altering the way the registry gets populated from this:
/* add this all into the swig registry: */
lua_pushstring(L,"SWIG");
to this:
/* add this all into the swig registry: */
lua_pushstring(L,"swig2/DuplicateA.cc");
using a sed operation on the generated cc file before compiling it. With this fix in place our code works, but we need to migrate to swig 4 as we also have python bindings and we need to migrate to Python 3.
Several C++ base classes are used by other C++ classes, and we want to do the same in the respective lua classes that are generated by swig. This works by forward declaring them. This works when we use swig2:
FIXNAMESPACE=1 make clean build fwd2
swig2/lua fwd.lua
<KlazzA userdata: 1FCB448>
<KlazzB userdata: 1FCB368>
<KlazzA userdata: 1FCB4E8>
<KlazzB userdata: 1FCB168>
<KlazzA userdata: 1FCAF28>
<KlazzB userdata: 1FCB008>
by forward declaring them. When using the above hack with SWIG4 it breaks in this example code with this error:
FIXNAMESPACE=1 make clean build fwd4
swig4/lua fwd.lua
<userdata of type 'KlazzA *' at 0xa419d0>
userdata: 0xa501b8
swig4/lua: fwd.lua:7: attempt to index a userdata value
stack traceback:
fwd.lua:7: in main chunk
[C]: ?
make: *** [fwd4] Error 1
Without this fix the fwd lua code works in swig 4. Under swig 2 it works both and without the sed fix, this is a reproduction to show the issue we are having with swig 4. This means we cannot migrate to swig 4 as this fix is no longer working.
Another issue that is a problem in both swig 2 and swig 4 when we declare a class Foo in namespace A with another class Foo in namespace B with both having accessor functions that return a Foo from their own namespace and the other one. This fails in swig 2 and in swig 4, but in different ways, and with or without our fix. This demonstrates how the fix helps, as without it the lua code fails early on in the test code.
swig 2 without fix:
> make clean build dup2
swig2/lua dup.lua
swig2/lua: Error in Dup_dummy (arg 1), expected 'B::Dup *' got 'A::Dup *'
stack traceback:
[C]: in function 'dummy'
dup.lua:6: in main chunk
[C]: ?
make: *** [dup2] Error 1
swig 4 without fix:
> make clean build dup4
swig4/lua dup.lua
<userdata of type 'A::Dup *' at 0x10bd9d0> 1
swig4/lua: dup.lua:8: Error in Dup_dummy (arg 1), expected 'A::Dup *' got 'B::Dup *'
stack traceback:
[C]: in function 'dummy'
dup.lua:8: in main chunk
[C]: ?
make: *** [dup4] Error 1
swig 2 with fix:
> FIXNAMESPACE=1 make clean build dup2
swig2/lua dup.lua
<Dup userdata: 1294898> 1
<Dup userdata: 12948E8> 2
<Foo userdata: 1294998>
<Foo userdata: 129B0F8>
<Foo userdata: 129B1C8>
<Foo userdata: 1297D38>
<Foo userdata: 129B2C8>
swig2/lua: Error in Foo_getB (arg 1), expected 'B::Foo *' got 'A::Foo *'
stack traceback:
[C]: in function 'getB'
dup.lua:19: in main chunk
[C]: ?
make: *** [dup2] Error 1
swig 4 with fix:
> FIXNAMESPACE=1 make clean build dup4
swig4/lua dup.lua
<userdata of type 'A::Dup *' at 0x25f29d0> 1
<userdata of type 'B::Dup *' at 0x25f2440> 2
<userdata of type 'A::Foo *' at 0x25f3fd0>
<userdata of type 'B::Foo *' at 0x62375c>
swig4/lua: dup.lua:15: Error in Foo_getA (arg 1), expected 'A::Foo *' got 'B::Foo *'
stack traceback:
[C]: in function 'getA'
dup.lua:15: in main chunk
[C]: ?
make: *** [dup4] Error 1
How should this work, using swig? We think this should be possible, but swig 2 nor 4 support this, and the fix is needed in both cases.
To reproduce this please adjust the location of the lua headers and the swig binaries in the Makefile.
DuplicateA.h
DuplicateA.i
DuplicateB.h
DuplicateB.i
dup.lua
ForwardDeclA.h
ForwardDeclA.i
ForwardDeclB.h
ForwardDeclB.i
fwd.lua
header.h
main.1.cc
main.2.cc
Makefile
prefix.h