1

I'm currently trying some experiences with the SWIG tool for wrapping generation of C++ and Lua code.

After some fighting with SWIG (trying to set it up, learn how it works, etc...), I finally got a working example.

However, I've come up with an awkward result in one of my experiments.

I was trying to recover a Lua's userdata back to C++ and change some of it's values.

Here is what i got in my console results:

Console



C++: index.cpp
Lua: Foo.lua

C++: Constructor of 0xb2d9f0
Lua: Adress of lFoo = userdata: 0xb35048

C++: Set - Old = 12 New = 4
Lua: Foo->Value = 4

Lua: Bye World

C++: Lua's lFoo To C++
C++: Adress of lFoo = 0xb35048
C++: Foo->Value = 1
C++: Set - Old = 1 New = 44
C++: Popping Foo from Lua
C++: Closing lLuaState 
C++: Destructor of 0xb2d9f0
C++: Bye World

Before I state where things are getting confused to me, let me paste some of the other codes is this examples, so that the console output gets lesser abstract:

Foo.h


#ifndef FOO_H_
#define FOO_H_

#include <iostream>

class Foo
{
    public:
        Foo( int a_value );
        virtual ~Foo();

        int getValue(){ return m_value; }
        void setValue( int a_value )
        {
            std::cout << "C++: Set - Old = " << m_value << " New = " << a_value << "\n";
            m_value = a_value;
        }
    private:
        int m_value;
};

#endif /* FOO_H_ */

Foo.cpp


#include "Foo.h"

Foo::Foo( int a_value ) : m_value( a_value )
{
    std::cout << "C++: Constructor of " << this << "\n";
    //setValue( a_value );
}

Foo::~Foo()
{
    std::cout << "C++: Destructor of " << this << "\n";
}

index.cpp


#include <string>
#include <iostream>
#include <lua.hpp>

#include "Foo.h"

extern "C" int luaopen_Foo(lua_State* L); // declare the wrapped module

const std::string ctLuaFooFile = "Foo.lua";

int main( int argc, char * args[] )
{
    std::string lLuaFile = ctLuaFooFile;

    std::cout << "C++: index.cpp\n";

    lua_State *lLuaState;

    lLuaState = lua_open();

    luaL_openlibs( lLuaState );

    luaopen_Foo( lLuaState );

    Foo * lFoo;

    if ( luaL_loadfile( lLuaState, lLuaFile.c_str() ) == 0 ) // load and run the file
        {
        int lError = lua_pcall( lLuaState, 0, 0, 0 );

        if ( lError )
        {
            std::cout << "Lua Error: " << lua_tostring( lLuaState, -1 );
            lua_pop( lLuaState, 1 );  /* pop error message from the stack */
        }

        std::cout << "C++: Lua's lFoo To C++\n";

        lua_getglobal( lLuaState, "lFoo");

        lFoo = static_cast<Foo *>( lua_touserdata( lLuaState, -1 ) );

        std::cout << "C++: Adress of lFoo = " << lFoo << "\n";

        std::cout << "C++: Foo->Value = " << lFoo->getValue() << "\n";

        lFoo->setValue( 44 );

        std::cout << "C++: Popping Foo from Lua\n";
        //Is Foo's destructor invoked here? --No
        lua_pop( lLuaState, -1 );
    }
    else
    {
        std::cout << "unable to load" << lLuaFile << "\n";
    }

    std::cout << "C++: Closing lLuaState \n";
    //Foo's destructor getting invoked here!
    lua_close( lLuaState );

    std::cout << "C++: Bye World\n";

    if( lFoo )
    {
        delete lFoo;
    }

    return 0;
}

Now that things are a little clearer on how I got those console outputs, let me tell you where my questions lie:

1º - Why, when I got the reference from lFoo back to C++, in line lFoo = static_cast<Foo *>( lua_touserdata( lLuaState, -1 ) ); its address was 0xb35048 (which seems to be a specific Lua pointer) instead of 0xb2d9f0 (which appeared in the C++ side of the code)?

2º - Even if those pointers are on different addresses, they both appear to be pointing to the same Foo object (or at least, to "a" Foo object), except that when I check C++ lFoo->getValue() I get 1 instead of 4. Why is that?

I consided that i could be getting an second Foo object, but his constructor was never called.

3º - Also, am I doing something wrong when I get my Foo's reference back to C++? Is there a better way of doing it?

4º - And finally, when I call lua_close( lLuaState );, Foo's Destructor is getting called. Is there a way for me to change the responsability of destroying this object in the C++ side? I think i read something about it in the SWIG docs but I can't seen to remember where.


For those willing to try my experiment, I will leave here the Foo.i interface file, used by the SWIG tool to create Foo_wrap.cxx, as well as the console commands used by my Eclipse, SWIG and g++ compiler:

Foo.i


/* File : example.i */
%module Foo

%{
#include "Foo.h"
%}

/* Let's just grab the original header file here */
%include "Foo.h"

Console commands


**** Build of configuration Debug for project SwigDemo ****

make pre-build main-build 
Criando wrappers para lua
swig -c++ -lua ../Foo.i

Building file: ../Foo.cpp
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Foo.d" -MT"Foo.d" -o"Foo.o" "../Foo.cpp"
Finished building: ../Foo.cpp

Building file: ../Foo_wrap.cxx
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Foo_wrap.d" -MT"Foo_wrap.d" -o"Foo_wrap.o" "../Foo_wrap.cxx"
Finished building: ../Foo_wrap.cxx

Building file: ../index.cpp
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"index.d" -MT"index.d" -o"index.o" "../index.cpp"
Finished building: ../index.cpp

Building target: SwigDemo
Invoking: GCC C++ Linker
g++ -L/usr/lib -L"/home/bruno/Programas/eclipse/workspace/SwigDemo/Debug" -o"SwigDemo"  ./Foo.o ./Foo_wrap.o ./index.o   -llua5.1
Finished building target: SwigDemo

Ps: I'm sorry for the long post. If there is a ways to improve it, I'd be more than happy to listen about it.

Canella
  • 444
  • 4
  • 15
  • @Emile: Yeah, I think I own you some apologise. Fixed the greeting and I'm sorry for that. It won't repeat again ma'am. ;) – Canella Apr 02 '11 at 16:14
  • FYI, `Emile` is a masculine French name. `Emilie` is the feminine form. But don't worry about that; I realize that `Emile` looks feminine to people not familiar with French names. People here mistake my gender all the time. :-) – Emile Cormier Apr 02 '11 at 16:18
  • @Emile: lol, sorry about that Bro ;x – Canella Apr 02 '11 at 16:30

1 Answers1

1

1) Since the pointer value lFoo that you print out on the C++ side is different from any Foo that has been constructed, we can conclude that lFoo does not point to a Foo object.

2) lFoo->getValue() does not return the 4 that was stored in the Foo object, because the data at lFoo is not a Foo, but a wrapper.

3) Here is one way: in index.cpp read in the contents of the Foo module (and don't link to it anymore):

#include "foo_wrap.cxx"

Replace

lFoo = static_cast<Foo*>(lua_touserdata(lLuaState, -1));

with

void* ptr;
SWIG_ConvertPtr(
    lLuaState, -1, &ptr, SWIGTYPE_p_Foo, SWIG_POINTER_DISOWN);
lFoo = static_cast<Foo*>(ptr);

4) Pass 0 instead of SWIG_POINTER_DISOWN, if you don't want to take ownership of the Foo value.

antonakos
  • 8,261
  • 2
  • 31
  • 34
  • Thank you so much. It worked like a charm. Also, got all my doubts answered. I'd vote up more times if I could. <3 – Canella Apr 03 '11 at 14:18