Wie schiebe ich eine Instanz einer C ++ Klasse mit swig auf einen lua Stapel gewickelt?

StackOverflow https://stackoverflow.com/questions/613282

  •  03-07-2019
  •  | 
  •  

Frage

Ich habe eine Klasse, die mit swig gewickelt ist, und mit lua registriert. Ich kann eine Instanz dieser Klasse in einem Lua Script erstellen, und es funktioniert gut.

Aber sagen, ich habe eine Instanz einer Klasse gemacht in meinem c ++ Code mit einem Aufruf zu neuen X, und ich habe la lua_state L mit einer Funktion darin, die ich nennen will, die ein Argument akzeptiert, eine Instanz von X ... Wie rufe ich diese Funktion. Hier ist (etwas) des Codes in Frage (ich die Fehlerbehandlung Sachen weggelassen haben):

main.cpp

class GuiInst;
extern "C"
{
    int luaopen_engine (lua_State *L);
}

int main()
{
    GuiInst gui=new GuiInst;
    lua_State *L=luaL_newstate();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);
    lua_getglobal(L,"Init");
    //Somehow push gui onto lua stack...
    lua_pcall(L, 1, 0, 0));
    lua_close(L);
}

mainmenu.lua

function Init(gui)
    vregion=gui:CreateComponent("GuiRegionVertical");
end

Im Moment alles, was ich gefunden habe, die funktionieren kann, ist, einige Funktionen aus der swig erzeugt CPP-Datei zu belichten, und das nennen. Das ist schlecht für ein paar Gründe ... Es wird nicht funktionieren, wenn ich mehrere modulles haben und ich hatte die Standardverknüpfungsvorschrift in der swig Datei zu ändern (mit -DSWIGRUNTIME =).

Ich fügen Sie folgendes Main.cpp

extern "C"
{
    struct swig_module_info;
    struct swig_type_info;
    int luaopen_engine (lua_State *L);
    swig_module_info *SWIG_Lua_GetModule(lua_State* L);
    void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
    swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);

Das bringt einen Zeiger auf das Modul, dann einen Zeiger auf den Typ, dann ruft Schlucke funktionieren sie registrieren. Es war eine unvernünftige Sache zu haben, in eine Datei zu graben, die nicht angenommen haben, menschlich lesbar sein (so heißt es am Anfang der Datei) und ist nur MESSY! (Aber es funktioniert!)

Theres sicherlich eine bessere Art und Weise zu tun, was ich zu tun werde versuchen.

PS von einem hohen Niveau pov, was ich will, ist lua hat nicht die GUI-Komponenten refcount, die von der Object-Fabrik in GuiInst erstellt werden, falls ich werde über diese falsch. Dies ist das erste Mal in einer Skriptsprache abgesehen von einigen sehr einfach (und nicht-swig) Python-Modulen Belichtungs Funktionalität, so bin ich bereit, Ratschläge zu nehmen.

Vielen Dank für jeden Hinweis!


Antwort auf einen Kommentar von RBerteig

GuiInst der contructor ist privat #defined wenn swig lua zu verhindern, läuft Instanzen davon konstruieren, so dass nicht für mich arbeiten. Was ich versuchte war die folgende (in lua) zu verhindern:

r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())

, welche nennen würde „g = new guibutton“, dann registrieren Sie es mit dem GuiRegionVertical (die einen Zeiger aus verschiedenen Gründen speichern muss), dann rufen Sie „löschen g“ und die GuiRegionVertical ist links mit einem baumelnden Zeiger auf g.

vermute ich, was muss wirklich geschehen ist, dass GuiRegionVertical :: Add (guibutton *) sollte der Verweiszähler des guibutton * erhöht, und dann GuiRegionVertical Destruktor sollte die Refcounts aller seiner Inhalte verringern, obwohl ich nicht sicher bin, wie dies sollte mit swig erfolgen.

Das würde die Notwendigkeit für die privaten Konstrukteure, die Gui Object Factory und die fiesen externs entfernen.

Bin ich über diese gehen falsch?

Danke.

War es hilfreich?

Lösung

Es gibt eine einfache und direkte Antwort, die nicht die effizienteste Lösung sein kann. SWIG produziert Wrapper für Objekte aus der Skriptsprache Seite zu manipulieren. Für Objekte, synthetisiert es auch einen umhüllten Konstruktor. So ist die direkte Lösung nur die Lua-Interpreter aufrufen Konstruktor SWIG lassen das neue Objekt zu erstellen.

Für die eingewickelt engine.GuiInst Klasse, man kann fast sicher so etwas wie:

int main()
{
    lua_State *L=lua_open();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);

    luaL_dostring(L, "Init(engine.new_GuiInst())");

    lua_close(L);
}

Für einen One-Shot-Fall wie Skript Start, die Strafe von einem String-Konstante durch luaL_dostring läuft () ist überhaupt nicht schlecht. Ich würde härter aussehen es in einem Ereignisrückruf zu vermeiden oder zu einer inneren Schleife, aber.

Es scheint, als gäbe es sollte ein Weg, um einen Zeiger direkt in ein verpacktes Objekt zu konvertieren, ich bin Spek es nicht in meiner eigenen Hand voll SWIG generierte Wrapper.

Edit: Natürlich kann die Lua-Fragment-API-Aufrufe zerlegt wird, dass die Motor Tabelle auf dem Stapel global erhalten, extrahiert daraus das new_GuiInst Mitglied, es nennt, dann den globalen Init nennen, aber die wenig Effizienz geht auf Kosten einiger Klarheit.

Wie bei Umgang mit Objekten, die nicht zufällig in Benutzercode konstruiert werden sollen, wie die geklärte Frage zeigt, mein erster Impuls wäre, die Konstruktorfunktion zu lassen SWIG erzeugen, eine private Referenz behalten, wenn später benötigt, und entfernen Sie es vom Tisch. Selbst ein C-Modul (in der Regel) nur eine Tabelle, deren Mitglieder Funktionswerte enthalten. sie schreibgeschützt nicht machen, es sei denn zusätzlicher Aufwand in C umgesetzt wird genommen.

So können Sie immer den Wert von engine.new_GuiInst abrufen und in dem Registry Park (siehe luaL_ref() und die Diskussion in Abschnitt 3.5 der Lua Referenz Manuelles der pseudo-Index LUA_REGISTRYINDEX für die Details) für die spätere Verwendung. Dann, bevor jeder Benutzer Code laufen zu lassen, tun einfach das Äquivalent von engine.new_GuiInst = nil. Ich sollte für die C-Datentypen beachten Sie, dass ich mit zuletzt gespielt haben, SWIG zwei Konstruktoren für jeden Typ erstellt, mit dem Namen new_TYPE und TYPE. Beide waren sichtbar in der Tabelle des Moduls, und Sie würden wollen beide Namen festlegen nil. Wenn viel weniger Erfahrung mit SWIG Verpackung C ++ Klassen, und das Ergebnis kann sich unterscheiden ...

Vielleicht möchten Sie den gesamten Inhalt der engine Tabelle zurück von SWIG, und erstellen Sie ein Proxy-Objekt überprüfen und zu überprüfen, die nur die Methoden enthält, die Sie Ihren Benutzern zur Verfügung möchten. Sie können auch die ändern Umgebung vom Benutzer Skript gesehen, so dass es nur hat der Proxy zur Verfügung, und die Namen sowie die Proxy engine. Es hat eine ganze Menge Diskussion von Sandbox Benutzer Skripte auf dem Lua-Liste und auf der lua-Benutzer wiki .

Andere Tipps

Besser spät als nie, und diese Lösung wird andere Menschen helfen.

void handle_web_request(WebRequest *request, WebResponse *response)
{
  lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
  SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
  SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
  lua_call(rackam->lua_state, 2, 0);
}

Dieser Code muss in% {}% Blöcke in Ihrer .i-Datei sein, weil SWIGTYPE_p_WebRequest ist

#define SWIGTYPE_p_WebResponse swig_types[6]

und swig_types [6] ist

static swig_type_info *swig_types[12];

Das bedeutet, dass swig_types ist nur zugänglich von der C ++ Datei, aus der sie definiert ist.

Dieses spezielle Snippet wird in zwei meiner wrappered Zeiger zu senden, so handle_web_request (Request, Response) von der C ++ Seite der Dinge Aufruf wird die globale lua-Funktion „handle_web_request“ und geben es meine zwei Zeiger, mit der SWIG Magie laufen angewendet .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top