LINUX.ORG.RU

libboost-python 2.7 -> 3.x Видимость модулей созданных в си-коде

 , ,


1

3

Есть некий проект, использующиий libboost-python, который в си++-рантайме создает питоновский модуль, и потом запускает питоновский скрипт который этот модуль импортирует и использует. Сделано это было на питоне 2.7. Случился принудительный переход на питон 3.* и мне так и не удалось заставить это работать в новых условиях.

Может быть кто-то более опытный в ембеденье питона может подсказать как правильно сделать.

Как было (упрощенный вариант):

test_module.py

import _hello_provider

test_var = 42

def hello_static():
        return "Hello world static"

def hello_provided():
        return _hello_provider.provide_hello()

test27.cpp

#include <boost/python.hpp>
 
std::string provide_hello() {
    return "hello world provided";
}
 
BOOST_PYTHON_MODULE(_hello_provider) {
    using namespace boost::python;
    def("provide_hello", &provide_hello);
}


int main()
{
  Py_InitializeEx(0);
  try {
    boost::python::object modImp = boost::python::import("imp");
    init_hello_provider();


    PyImport_AddModule("test_module");

    modImp.attr("load_source")("test_module", "test_module.py");

    boost::python::exec("print(test_var)", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_static())", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_provided())", boost::python::import("test_module").attr("__dict__"));
  }
  catch (const boost::python::error_already_set&)
  {
    PyErr_Print();
  }


  Py_Finalize();
}

На Debian Stretch собираем так:

g++  test27.cpp  -I /usr/include/x86_64-linux-gnu/python2.7 -I /usr/include/python2.7 -lboost_python -lboost_system -lpython2.7

Все работает последний вывод через питоновский модуль дергает си++ную функцию из добавленного в рантайме модуля _hello_provider.

А вот когда я пытаюсь сделать это по аналогии на современном дебиане:

#include <boost/python.hpp>
 
std::string provide_hello() {
    return "hello world provided";
}

BOOST_PYTHON_MODULE(_hello_provider) {
    using namespace boost::python;
    def("provide_hello", &provide_hello);
}


int main()
{
  Py_InitializeEx(0);
  try {
    boost::python::object modImp = boost::python::import("imp");
    PyInit__hello_provider();

    PyImport_AddModule("test_module");

    modImp.attr("load_source")("test_module", "test_module.py");

    boost::python::exec("print(test_var)", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_static())", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_provided())", boost::python::import("test_module").attr("__dict__"));
  }
  catch (const boost::python::error_already_set&)
  {
    PyErr_Print();
  }


  Py_Finalize();
}

С тем же самым питоновским файлом, собирая все на, Debian Bullseye командой

g++ test3x.cpp  -I /usr/include/x86_64-linux-gnu/python3.9 -I /usr/include/python3.9 -lpython3.9  -lboost_python39 -lboost_system

То все собирается, но при запуске ругается:

Traceback (most recent call last):
  File "/usr/lib/python3.9/imp.py", line 169, in load_source
    module = _exec(spec, sys.modules[name])
  File "<frozen importlib._bootstrap>", line 613, in _exec
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "test_module.py", line 1, in <module>
    import _hello_provider
ModuleNotFoundError: No module named '_hello_provider'

Т.е. в таком исполнении оно модуль _hello_provider не видит, и моей квалификации не хватает для того чтобы понять как это сделать чтобы да. Есть кто-то более опытный способный подсказать?

★★★

В новом делается через PyImport_AppendInittab("module", &PyInit_module)) перед инициализацией питона

O02eg ★★★★★
()
Ответ на: комментарий от O02eg

В новом делается через PyImport_AppendInittab(«module», &PyInit_module)) перед инициализацией питона

Великая синхронизация. Примерно в 09:30 я таки осилил это найти сам!

Но спасибо!!!

shaplov ★★★
() автор топика

Как правильно сказал @O02eg это делается через PyImport_AppendInittab

Я сам параллельно таки нашел это вот в этом примере: https://github.com/TNG/boost-python-examples/tree/main/10-Embedding (прикольный набор примеров к стати)

Суммарно, программа собираемая с обеими питонами выглядит теперь так:

#include <boost/python.hpp>

std::string provide_hello() {
    return "hello world provided";
}

BOOST_PYTHON_MODULE(_hello_provider) {
    using namespace boost::python;
    def("provide_hello", &provide_hello);
}

int main()
{
#if PY_MAJOR_VERSION >= 3
  PyImport_AppendInittab((char*)"_hello_provider", PyInit__hello_provider);
#else
  PyImport_AppendInittab((char*)"_hello_provider", init_hello_provider);
#endif
  Py_InitializeEx(0);

  try {
    boost::python::object modImp = boost::python::import("imp");
    PyImport_AddModule("test_module");

    modImp.attr("load_source")("test_module", "test_module.py");

    boost::python::exec("print(test_var)", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_static())", boost::python::import("test_module").attr("__dict__"));
    boost::python::exec("print(hello_provided())", boost::python::import("test_module").attr("__dict__"));
  }
  catch (const boost::python::error_already_set&)
  {
    PyErr_Print();
  }
  Py_Finalize();
}

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 1)
Ответ на: комментарий от O02eg

@O02eg: Offtopic

Теперь известный тебе goblin-camp успешно собирается с третьим питоном, но правда при выходе из программы падает с резолюцией corrupted size vs. prev_size in fastbins где-то в недрах SDL…

Прям даже не знаю с какой стороны к этому подступиться…

shaplov ★★★
() автор топика
Ответ на: комментарий от shaplov

Собирать с отладочной инфой, естественно, и пробовать отладчик. Ещё можно санитайзеры включить.

O02eg ★★★★★
()
Ответ на: комментарий от O02eg

Любите ли вы санитайзеры так, как люблю их я…

Так в результате оказалось что новый libtcod тащил в таблицу динамической линтовки SDL2 а я собирал с SDL1. Они по именам функций – пересекаются. Получалась помесь ежа с ежом второй версии…

Еще из интересного было вот это https://stackoverflow.com/questions/73159490/boost-python3-program-crashes-on-exit

Но я вроде все в первом приближении победил. Готовлю релиз…

shaplov ★★★
() автор топика
Ответ на: комментарий от O02eg

B доке от 1.55 буста вообще незамысловато рекомендовали просто не делать PyFinalize()

shaplov ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.