0

I have a problem and I need help finding a solution.

What I'm currently doing

I'm trying to use PyBind11 to send a several variables from C++ to Python (Which is then used to log sql data, but that's besides the point). I am am to do this using the following process:

SQL_Service.cpp:

namespace py = pybind11;
PYBIND11_PLUGIN(sqlserv)
{
    py::module m("sqlserv", "pybind11 sql plugin");

    m.attr("bet_player") = BET_PLAYER;
    m.attr("total_winnings") = TOTAL_WINNINGS;

    return m.ptr();
}

py::object import(const std::string& module, const std::string& path, py::object& globals)
{
    py::dict locals;
    locals["module_name"] = py::cast(module);
    locals["path"] = py::cast(path);

    py::eval<py::eval_statements>(
        "import imp\n"
        "new_module = imp.load_module(module_name, open(path), path, ('py', 'U', imp.PY_SOURCE))\n",
        globals,
        locals);

    return locals["new_module"];
}

int SQL_Service::Log_SQL()
{
    try
    {
        Py_Initialize();
        pybind11_init();

        py::object main = py::module::import("__main__");
        py::object globals = main.attr("__dict__");
        py::object module = import("sqlserv", "py_sql_service.py", globals); //name of the python file used

        return 0;
    }
    catch (const py::error_already_set&)
    {
        std::cerr << ">>> Error! Uncaught exception:\n";
        PyErr_Print();
        return 1;
    }

}

This is all well and fine, and I am able to get those two variables (bet_player and total_winnings) into python and process them.

I'd like to create another "PYBIND11_PLUGIN(somethingelse)" that is associated uses different variables and is associated with a different python script.

Problems arise when I try to define another PYBIND11_PLUGIN. Namely:

namespace py = pybind11;
PYBIND11_PLUGIN(sqlserv)
{
    py::module m("sqlserv", "pybind11 sql plugin");

    m.attr("bet_player") = BET_PLAYER;
    m.attr("total_winnings") = TOTAL_WINNINGS;

    return m.ptr();
}
PYBIND11_PLUGIN(somethingelse)
{
    py::module m("somethingelse", "pybind11 sql plugin");

    m.attr("bet_player2") = BET_PLAYER2;
    m.attr("total_winning2s") = TOTAL_WINNINGS2;

    return m.ptr();
}


//This gives me the following error
Error   C2084   function 'PyObject *pybind11_init(void)' already has a body 

What I'm hoping to accomplish

I want to use my class (SQL_Service) to define various functions that will receive data from elsewhere in my program to be packaged up and sent to different python scripts, each one only getting the data it needs. (See Process_Baccarat(...){...} in my full example below).

What's Tripping me Up

I have relied on various tutorials that give small snippets of code, or that demonstrate slightly different ways of doing things with PyBind. As such, I don't really know how to get exactly what I'm looking for.

I'm not sure it's namespaces, or maybe I just can't have 2 of those functions. Perhaps there is another way to approach this problem entirely that would be better.

I'm also not too happy about having to use global variables (again, I'm having some namespace confusion) so if there's a way this can all be wrapped up nicely, that is what I'm looking for. Working example code would be greatly appreciated.

Here's my complete (working) SQL_Service.cpp file for reference:

#include "SQL_Service.hpp"

#include "Pybind\include\pybind11\pybind11.h"
#include "Pybind\include\pybind11\eval.h"

#include <string>
#include <iostream>


//G_VARS
int BET_PLAYER = 0;
int TOTAL_WINNINGS = 0;


SQL_Service::SQL_Service()
{

}

SQL_Service::~SQL_Service()
{

}

namespace py = pybind11;
PYBIND11_PLUGIN(sqlserv)
{
    py::module m("sqlserv", "pybind11 sql plugin");

    m.attr("bet_player") = BET_PLAYER;
    m.attr("total_winnings") = TOTAL_WINNINGS;

    return m.ptr();
}


py::object import(const std::string& module, const std::string& path, py::object& globals)
{
    py::dict locals;
    locals["module_name"] = py::cast(module);
    locals["path"] = py::cast(path);

    py::eval<py::eval_statements>(
        "import imp\n"
        "new_module = imp.load_module(module_name, open(path), path, ('py', 'U', imp.PY_SOURCE))\n",
        globals,
        locals);

    return locals["new_module"];
}

//I Want to make all sorts of different kinds of these functions.
void SQL_Service::Process_Baccarat(int bet_player, int total_winnings)
{
    BET_PLAYER = bet_player;
    TOTAL_WINNINGS = total_winnings;

    Log_SQL();
}

//And more of these too, if needed.
int SQL_Service::Log_SQL()
{
    try
    {
        Py_Initialize();
        pybind11_init();

        py::object main = py::module::import("__main__");
        py::object globals = main.attr("__dict__");
        py::object module = import("sqlserv", "py_sql_service.py", globals); //name of the python file used

        return 0;
    }
    catch (const py::error_already_set&)
    {
        std::cerr << ">>> Error! Uncaught exception:\n";
        PyErr_Print();
        return 1;
    }

}
ekcell
  • 105
  • 2
  • 11

1 Answers1

0

You need to put PYBIND11_PLUGIN in separate compilation units. In your case that would mean splitting your code among: sqlserv.cpp and somethingelse.cpp.

However, I'm not sure if it's the best solution altogether. Maybe different classes with static members within same module?

Jakub Jeziorski
  • 173
  • 2
  • 10