embedding und extending an c++ beispiel

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Ich hoffe, ich fange nicht an euch zu nerven.


Ich habe mir überlegt wie ich in einem C++ Python aufrufen kann. Ich habe ein minimales Beispiel, das ich aus verschiednen Sourcen zusammengemergt habe, gemacht (ich weiß dass längerer Code nicht so beliebt ist). Also ich hoffe er ist nicht zu lange.

Das "embedding" funktioniert ja schon mal:

Code: Alles auswählen

//g++ main.cc -o simple `pkg-config gtkmm-2.4 --cflags --libs` -I/usr/include/python2.6  -lpython2.6

#include <iostream>
#include <gtkmm.h>
#include <gtkmm/main.h>
#include <gtkmm/messagedialog.h>

#include "Python.h"

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  void on_button_info_clicked();

  //Child widgets:
  Gtk::VButtonBox m_ButtonBox;
  Gtk::Button m_Button_Info;
};

ExampleWindow::ExampleWindow()
: m_Button_Info("Show Info MessageDialog")
{
  set_title("Gtk::MessageDialog example");

  add(m_ButtonBox);

  m_ButtonBox.pack_start(m_Button_Info);
  m_Button_Info.signal_clicked().connect(sigc::mem_fun(*this,
              &ExampleWindow::on_button_info_clicked) );

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_info_clicked()
{
  
  Py_Initialize();
  PyRun_SimpleString("import sys; import os;");
  PyRun_SimpleString("sys.path.append(os.getcwd())");  
  PyObject* main_module =
     PyImport_AddModule("__main__");

  // Get the main module's dictionary
  // and make a copy of it.
  PyObject* main_dict =
     PyModule_GetDict(main_module);
  PyObject* main_dict_copy =
     PyDict_Copy(main_dict);

  // Execute two different files of
  // Python code in separate environments
  FILE* file_1 = fopen("file1.py", "r");
  PyRun_File(file_1, "file1.py",
             Py_file_input,
             main_dict, main_dict);

  FILE* file_2 = fopen("file2.py", "r");
  PyRun_File(file_2, "file2.py",
             Py_file_input,
             main_dict_copy, main_dict_copy);
  Py_Finalize();
  
  
  Gtk::MessageDialog dialog(*this, "This is an INFO MessageDialog");
  dialog.set_secondary_text(
          "And this is the secondary text that explains things.");

  dialog.run();
}

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}
Was ich jetzt möchte, ist von (momentan ist eine print anweisung in file1.py und file2.py):

Dass ich einem "this" pointer mitgeben kann. im Python script sagt er dann (pseudo code):

Code: Alles auswählen

import examplewindow
examplewindow. m_Button_Info.set_label("neu")
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

So, das habe ich hinbekommen. Ein wenig Suchen hilft dann doch weiter. ;)
Mein Code ist wirklich sehr experimentell und daher poste ich den hier jetzt nicht mehr (zu lange wär es auch):
Python Docs und das kde Programm SuperKaramba haben mich weitergebracht, falls es jmd. interessiert.

Entscheidend sind jedenfalls:
Auszüge aus meinem Code:

Code: Alles auswählen


// deklaration

PyObject* py_createBar(PyObject *self, PyObject *args);
PyObject* py_deleteBar(PyObject *self, PyObject *args);

// eine python funktion

PyObject* py_createBar(PyObject *, PyObject *args)
{
    long widget, x, y, w, h;
    char *text;
    if (!PyArg_ParseTuple(args, (char*)"lllll|s", &widget, &x, &y, &w, &h, &text))
        return NULL;

    return (Py_BuildValue((char*)"l", (long)1234));
}

// export tabelle

static PyMethodDef mainwindow_methods[] =
{

  // Bar - bar_python.cpp
  {(char*)"createBar", py_createBar, METH_VARARGS, (char*)"Create new Bar."},
  {(char*)"deleteBar", py_deleteBar, METH_VARARGS, (char*)"Delete Bar."},
    {NULL, NULL, 0 , NULL}
};

// aufruf der python scripts

PyRun_SimpleString((char*)"import sys");
snprintf(pypath, 1023, "sys.path.insert(0, '%s')", theme.path.c_str());
PyRun_SimpleString(pypath);
PyRun_SimpleString((char*)"sys.path.insert(0, '')");
PyImport_AddModule((char*)"mainwindow");
Py_InitModule((char*)"mainwindow", mainwindow_methods);
std::string script = theme.scriptModule;
pName = PyString_FromString(script.erase(script.length() - 3, 3).c_str());
pModule = PyImport_Import(pName);

Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Ich habe eine Antwort von Krusader Entwickler bekommen. Er sieht es auch so, dass kross (oder SIP) dafür geeigent wären.

Was ich mir nicht vorstellen kann, ist wie man SIP, SWIG oder Boost Python für so ein Plugin System verwenden kann, da es nur eine Binding ("statt" dem Aufruf in puren C(++) darstellen soll).

Also in der Art

import mywrappedcfunction
mywrappedcfunction...

Das heisst, es wird nicht von C(++) heraus aufgerufen, sondern ist in einem völlig eigenen Python Programm untergebracht.

Aber nicht in der Art:

App
C++:
provide modules
call Python script (Pyrun...)

Python:
import AppC++ScriptWrapper
AppC++ScriptWrapper...

Kann mir vielleicht noch jmd. Hinweise geben, ob und wie das mit SWIG, Boost Python, SIP mit embedding/extending in einem funktionieren sollte? Ich blick da nicht ganz durch. Oder habe ich da etwas misverstanden?

Für verschiedene Anwendungen habe ich gesehen.

gnome: PyMethodDef
karamba: PyMethodDef oder kross (Aufrufparamter entscheidet über die Verwendung)
ktorrent: kross

Also in gtk Programme (eigentlich habe ich nur gedit angesehe, das jedoch nicht in C++, sondern in C (gtk) geschrieben ist) habe ich eigentlich nichts anders gesehen als den "herkömmlichen" Weg mit PyMethodDef für diese Art von embedding/extending.

Eine kleine Zusatzfrage noch. Es scheint, als wären die Wrapper in gedit mit einem Tool erzeugt worden, ich habe jedoch noch nicht herausbekomen, wie:

Auszug:
/* -- THIS FILE IS GENERATED - DO NOT EDIT *//* -*- Mode: C; c-basic-offset: 4 -*- */
#line 24 "geditcommands.override"
static PyObject *
_wrap_gedit_commands_load_uri (PyObject *self, PyObject *args, PyObject *kwargs)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Francesco hat geschrieben:Eine kleine Zusatzfrage noch. Es scheint, als wären die Wrapper in gedit mit einem Tool erzeugt worden, ich habe jedoch noch nicht herausbekomen, wie:

Auszug:
/* -- THIS FILE IS GENERATED - DO NOT EDIT *//* -*- Mode: C; c-basic-offset: 4 -*- */
#line 24 "geditcommands.override"
static PyObject *
_wrap_gedit_commands_load_uri (PyObject *self, PyObject *args, PyObject *kwargs)
Aus welcher Datei hast du das denn?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Aus gedit 2.28.3
(Es gibt anscheinend noch neuere)

gedit-2.28.3/plugin-loaders/python/bindings/geditutils.c
gedit-2.28.3/plugin-loaders/python/bindings/geditcommands.c
gedit-2.28.3/plugin-loaders/python/bindings/gedit.c
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Also Makefile.am sagt dass dort PYGTK_CODEGEN verwendet wird. PYGTK_CODEGEN scheint aus der pygtk-codegen-2.0.in zu kommen (Teil von PyGTK), die wiederrum auf pygobject-codegen-2.0 verweist. Das ist dann wohl das hier.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

aha, danke für die Antwort. Jetzt wäre es noch schön, wenn noch jmd. auf meine vorigen "Basisfragen" noch eine Antwort wüsste. :)
Antworten