2016-11-18 4 views
2

Ich muss Datenstrukturzeiger in meinem Hauptprogramm, wo ich Lua-Zustand definiert haben, zu dem dynamisch geladenen Lua-Modul durch das Einwickeln eines C++ - Codes mit SWIG erstellt.teilen Datenzeiger zwischen c und lua Modul kompiliert mit SWIG

Dies ist mein Codebeispiel:

in SimpleStruct.h:

#pragma once 
struct SimpleStruct 
{ 
    int a; 
    double b; 
}; 

in exmaple.h (dieses mit SWIG kompiliert wird) zu Lua Bibliothek:

#pragma once 

#include "SimpleStruct.h" 
#include <iostream> 

class TestClass 
{ 

public: 
    TestClass() 
    { 
     std::cout<<"TestClass created"<<std::endl; 
    } 

    ~TestClass() {} 


    void ReadSimpleStruct(void * tmp) 
    { 

     std::cout<<"reading pointer: "<<std::endl; 

     SimpleStruct * pp = reinterpret_cast< SimpleStruct * >(tmp); 

     std::cout<<"Simple Struct: " << pp->a << " " << pp->b << std::endl; 
    } 

}; 

in example.cpp nur:

#include "example.h" 

und das ist mein Hauptprogramm (LuaTest.cpp):

extern "C" 
{ 
    #include <lua.h> 
    #include <lauxlib.h> 
    #include <lualib.h> 
} 


#include <iostream> 
#include "SimpleStruct.h" 



int main(int argc, char ** argv) 
{ 

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

SimpleStruct * ss = new SimpleStruct(); 
ss->a = 1; 
ss->b = 2; 

lua_pushlightuserdata(L,ss); 
lua_setglobal(L, "myptr"); 


int s = luaL_dostring(L, "require('example')"); 
s = luaL_dostring(L, "mc = example.TestClass()"); 
s = luaL_dostring(L, "mc:ReadSimpleStruct(myptr)"); 

if(s) 
{ 
    printf("Error: %s \n", lua_tostring(L, -1)); 
    lua_pop(L, 1); 
} 

lua_close(L); 

std::cout<<"done"<<std::endl; 

return 0; 
} 

example.i (von Lua Beispiele in SWIG kopiert):

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

%{ 
#include "example.h" 
%} 

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

und ich kompilieren alles wie folgt:

swig -c++ -lua example.i 
g++ -c -fpic example.cpp example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/ 
g++ -shared example.o example_wrap.o -o example.so 
g++ LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/ -Wall 

auf Ubuntu 16.04 (und auf OSX, mit verschiedenen Pfaden und dem gleichen Ergebnis).

In der letzten Zeile des Lua-Skripts habe ich Segmentierungsfehler (wenn ich versuche, auf pp-> a in "mc: ReadSimpleStruct (myptr)") zuzugreifen.

Also meine Frage ist: Wie kann ich einen Zeiger auf C++ - Objekt auf die geladene Lua-Bibliothek mit Lua Light userdata bereitstellen?

Im Allgemeinen: Ich habe in meinem Hauptprogramm eine Klasse mit Spielparametern und Objekten, und ich möchte einen Zeiger auf diese Klasse zu anderen geladenen Lua-Bibliotheken bereitstellen, die mit einem SWIG kompiliert werden.

+0

Können Sie das machen ein echtes, vollständiges minimales Beispiel, das es zeigt? Etwas, das ich verstehen kann - wir müssen wissen, wie die "andere geladene Lua-Bibliothek" funktioniert. – Flexo

+0

Ich denke, das ist ein volles reales Beispiel: Ich kompiliere TestClass mit SWIG als eine lua-Bibliothek namens 'example' (und das ist 'meine andere lua-Bibliothek'), danach lade ich diese Bibliothek im Hauptprogramm (durch 'require example')). Als nächstes erstelle ich eine Instanz der SimpleClass-Struktur und erstelle leichte Benutzerdaten mit einem Zeiger auf diese Instanz. Und schließlich möchte ich in der Lage sein, Daten von diesem Zeiger durch eine Methode des TestClass-Objekts zu lesen ('mc: ReadSimpleStruct (myptr)). Nichts mehr, dies wird mir ermöglichen, Zugang zu globalen Parametern von meiner eigenen, mit SWIG erstellten, Lua-Bibliothek zu haben. – beastian

+0

Der Code in Ihrer Frage hat viele '....'. Es sagt nicht einmal, auf welche Plattform Sie ausgerichtet sind. Es gibt eine Datei, die Sie SimpleStruct.h genannt haben, aber Sie fügen TestClass.h hinzu. Es gibt keine .i-Datei. Ich kann nicht einmal anfangen, deine Frage zu beantworten, bis ich all die fehlenden Teile schreibe, die du nicht aufgenommen hast. Ich weiß nicht, auf welche Version von Lua Sie abzielen. – Flexo

Antwort

0

Mit Hilfe eines Debuggers (oder einfach nur ein wenig extra in TestClass::ReadSimpleStruct drucken) können wir zumindest die oberflächliche Ursache des segfault ziemlich schnell sehen. Der Wert des tmp Arguments für Ihre Funktion ist 0x20 bei meiner Testkonfiguration. Das ist eindeutig nicht richtig, aber zu verstehen, warum und wie man es beheben kann, erfordert ein wenig mehr Nachforschungen.

Als Ausgangspunkt habe ich einen weiteren Aufruf an luaL_dostring(L, "print(myptr)") hinzugefügt und einen Debugger verwendet, um zu überprüfen, dass die globale Variable wie intad funktioniert. Für eine gute Maßnahme habe ich nach jedem Aufruf einige Assert-Anweisungen an luaL_dostring hinzugefügt, weil Sie eigentlich nur den Rückgabewert des letzten überprüfen, obwohl das hier eigentlich keinen Unterschied machte.

Nachdem ich nicht viel Lua in meinem Leben geschrieben habe, habe ich die Dokumentation für 'Light userdata' angeschaut, die ich gesehen habe, die du benutzt hast, aber nicht wusstest was es war. Es klingt ideal:

Ein Licht userdatum ein Wert ist, der einen C-Zeiger darstellt (das heißt, einen void * Wert)

Das Problem aber, dass, wenn wir die erzeugte example_wrap inspizieren.Cxx-Datei können wir sehen, dass SWIG eigentlich versucht, schlauer als das zu sein, und wenn wir den Code für arg2 vor dem generierten Aufruf an (arg1)->ReadSimpleStruct(arg2) verfolgen, können wir sehen, dass es SWIG_ConvertPtr (die schließlich ruft SWIG_Lua_ConvertPtr) ruft, was dann tut:

lua_touserdata(L, index); 
    //... Some typing stuff from the macro 
    *ptr=usr->ptr; // BOOM! 

Ie was Sie tun, ist nicht, was SWIG erwartet, für void * zu sehen, SWIG erwartet, sie alle durch sein Schreibsystem als Rückgabewerte von anderen Funktionen oder von SWIG gehandhabten globalen zu handhaben. (Ich bin etwas überrascht, dass SWIG dies bis zu einem segfault ohne einen Fehler zu erhöhen, aber ich denke, es ist, weil void* ist etwas speziell verkleidet)

Diese alte Frage diente als ein ziemlich schönes Beispiel, um mein Verständnis zu bestätigen von lua_pushlightuserdata. Im Grunde müssen wir unsere eigene typeMap schreiben, damit dieses Funktionsargument so gehandhabt wird, wie Sie es benutzen wollen (wenn Sie SWIG wirklich nicht verwalten wollen?). Was wir machen wollen, ist sehr einfach. Der Anwendungsfall ist hier auch im Wesentlichen ähnlich dem Beispiel, das ich verlinkt habe, außer dass die Variable, die wir suchen, wenn wir lua_touserdata aufrufen, ein Funktionsargument ist. Das heißt, es ist ein positiver Offset in den Stack, kein negativer. SWIG kann uns sogar sagen, was der Offset innerhalb unseres typeMape mit der $input Ersetzung ist, also arbeitet unsere typemap nicht nur für das 1. Argument zu einer Mitgliedsfunktion.

Also unsere typemap, die dies für jedes Funktionsargument tut void * tmp in unserem modifizierten example.i Datei wird:

%module example 

%{ 
#include "example.h" 
%} 

%typemap(in) void * tmp %{ 
    $1 = lua_touserdata(L, $input); 
%} 

%include "example.h" 

Und das kompiliert dann und läuft mit:

swig -c++ -lua example.i 
g++ -fPIC example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/ -shared -o example.so && g++ -Wall -Wextra LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/ 
./luatest 
TestClass created 
userdata: 0x11d0730 
reading pointer: 0x11d0730 
Simple Struct: 1 2 
done