Вопрос по c++, c, python – Как получить Python .pyd для Windows из исходного кода c / c ++? (обновление: оживленный теперь в Python на тот случай, если вы этого хотите)

10
How to get from C/C++ extension source code to a pyd file for windows (or other item that I could import to Python)?

edit: Специальная библиотека, которую я хотел использовать (BRISK), была включена вOpenCV 2.4.3, поэтому моя потребность в этом умении ушла на время. Если вы пришли сюда в поисках BRISK, вот простойBRISK в демонстрации Python что я отправил.

у меня естьюркий исходный код (скачать), что я хотел бы построить и использовать в моем приложении Python. Я дошел до генерации файла brisk.pyd ... но это было 0 байтов. Если есть лучший / альтернативный способ нацеливания на файл brisk.pyd, то, конечно, я открыт для этого.

edit: Пожалуйста, игнорируйте все попытки в моем первоначальном вопросе ниже и посмотрите мой ответ, который стал возможен благодаря подробному прохождению obmarg.

Where am I going wrong?

Distutils without library path: First I tried to build the source as is with distutils and the following setup.py (I have just started learning distutils so this is a shot in the dark). The structure of the BRISK source code is at the bottom of this question for reference.

from distutils.core import setup, Extension
module1 = Extension('brisk',
    include_dirs = ['include', 'C:/opencv2.4/build/include', 'C:/brisk/thirdparty/agast/include'],
    #libraries = ['agast_static', 'brisk_static'],
    #library_dirs = ['win32/lib'],
    sources = ['src/brisk.cpp'])
setup (name = 'BriskPackage',
    ext_modules = [module1])

That instantly gave me the following lines and a 0 byte brisk.pyd somewhere in the build folder. So close?

running build
running build_ext

Distutils with library path: Scratch that attempt. So I added the two library lines that are commented out in the above setup.py. That seemed to go ok until I got this linking error:

creating build\lib.win32-2.7
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:win32/lib /LIB
PATH:C:\Python27_32bit\libs /LIBPATH:C:\Python27_32bit\PCbuild agast_static.lib brisk_static.lib /EXPORT:initbrisk build
\temp.win32-2.7\Release\src/brisk.obj /OUT:build\lib.win32-2.7\brisk.pyd /IMPLIB:build\temp.win32-2.7\Release\src\brisk.
lib /MANIFESTFILE:build\temp.win32-2.7\Release\src\brisk.pyd.manifest
LINK : error LNK2001: unresolved external symbol initbrisk
build\temp.win32-2.7\Release\src\brisk.lib : fatal error LNK1120: 1 unresolved externals
error: command '"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe"' failed with exit status 1120

Uncontrolled flailing: I thought maybe the libraries needed to be built, so I did a crash course (lots of crashing) with cmake + mingw - mingw + vc++ express 2010 as follows:

cmake gui: source: c:/brisk, build: c:/brisk/build cmake gui: configure for Visual Studio 10 cmake gui: use default options and generate (CMAKE_BACKWARDS_COMPATIBILITY, CMAKE_INSTALL_PREFIX, EXECUTABLE_OUTPUT_PATH, LIBRARY_OUTPUT_PATH)

VC++ Express 10: Change to Release and build the solution generated by cmake and get about 20 pages of what look like non-critical warnings followed by all succeeded. Note - no dlls are generated by this. It does generate the following libraries of similar size to the ones included with the download:

win32/lib/Release/
    agast_static.lib
    brisk_static.lib

Further flailing.

Relevant BRISK source file structure for reference:
build/ (empty)
include/brisk/
    brisk.h
    hammingsse.hpp
src
    brisk.cpp
    demo.cpp
thirdparty/agast/
    include/agast/
        agast5_8.h ....
        cvWrapper.h
    src/
        agast5_8.cc ...
    CMakeLists.txt
win32/
    bin/
        brisk.mexw32
        opencv_calib3d220.dll ...
    lib/
        agast_static.lib
        brisk_static.lib
CMakeLists.txt
FindOpenCV.cmake
Makefile
У последнего не было ни ответов, ни комментариев, поэтому я его удалю. Этот более конкретный, так что, надеюсь, кто-то может указать место, где я ошибся. Чтобы было понятно всем, кто видит это, первым текстом этого вопроса была ссылка на оригинальный пост. Я не пытался подкрасться к другому. KobeJohn
@Joe Согласен, хотя. Я должен был просто полностью переделать первый вместо того, чтобы сделать новый. Спасибо за мета-ссылку. KobeJohn
Не отправлять повторно:meta.stackexchange.com/questions/7046/… Joe

Ваш Ответ

1   ответ
12

что эта оживленная библиотека экспортирует даже привязки Python? Я не вижу никакой ссылки на него в исходном коде - кажется, что он даже не импортирует заголовочные файлы python. Это, безусловно, объясняет, почему вы до сих пор не добились большого успеха - вы не можете просто скомпилировать простой код C ++ и ожидать, что Python будет взаимодействовать с ним.

Я думаю, что ваш второй пример distutils наиболее близок к правильному - он явно компилирует вещи и достигает стадии компоновщика, но затем вы сталкиваетесь с этой ошибкой. Эта ошибка просто означает, что она не может найти функцию с именем initbrisk, которая, как я предполагаю, будет функцией инициализации верхнего уровня для модуля. Опять же, это говорит о том, что вы пытаетесь скомпилировать модуль Python из кода, который не предназначен для него.

Если вы хотите обернуть код C ++ в оболочку Python самостоятельно, вы можете взглянуть наофициальная документация по написанию расширений c / c ++, В качестве альтернативы вы можете посмотреть вповышение :: питона, ГЛОТОК или жеshiboken которые пытаются (частично или полностью) автоматизировать процесс создания расширений Python из кода C ++.

РЕДАКТИРОВАТЬ: Поскольку вы, кажется, приложили немало усилий для самостоятельного решения проблемы и опубликовали хороший вопрос, я решил дать более подробный ответ о том, как это сделать.

Quick Tutorial On Wrapping C++ Libraries Using boost::python

Лично я только когда-либо использовал boost :: python для подобных вещей, поэтому я попытаюсь дать вам краткое изложение того, как это сделать. Я собираюсь предположить, что вы используете Visual C ++ 2010. Я также собираюсь предположить, что у вас установлена 32-битная версия python, так как я полагаю, что библиотеки boost pro предоставляют только 32-битные двоичные файлы.

Installing boost

Сначала вам нужно будет получить копию библиотеки надстроек. Самый простой способ сделать это - загрузить установщик сбуст про сайт, Они должны установить все заголовочные и двоичные файлы, необходимые для использования библиотеки boost c ++ в windows. Запомните, куда вы устанавливаете эти файлы, так как они понадобятся вам позже - может быть, лучше всего установить путь без пробела. Для простоты я собираюсь предположить, что вы поместили эти файлы в C: \ boost, но вы можете заменить его на путь, который вы фактически использовали.

Кроме того, вы можете следоватьэти инструкции создать импульс от источника. Я не уверен на 100%, но, возможно, выneed сделать это, чтобы получить версию boost :: python, совместимую с версией python, которую вы установили.

Setting up a visual studio project

Затем вы захотите настроить визуальный студийный проект для brisk.pyd. Если вы открываете визуальную студию, перейдите в New - & gt; Проект, затем найдите вариант для Win32 Project. Укажите свое местоположение и т. Д. И нажмите ОК. В открывшемся мастере выберите тип проекта DLL и установите флажок пустого проекта.

Теперь, когда вы создали свой проект, вам нужно настроить include & amp; пути к библиотекам, позволяющие использовать python, boost :: python и файл brisk.lib.

В обозревателе решений Visual Studios щелкните правой кнопкой мыши свой проект и выберите в появившемся меню свойства. Это должно открыть страницы свойств для вашего проекта. Перейти к компоновщику - & gt; Общий раздел и найдите раздел Дополнительные каталоги библиотек. Вам нужно будет заполнить это путями к.lib файлы для повышения, Python и вашbrisk_static.lib, Обычно их можно найти вlib (или жеlibs) подкаталоги везде, где вы установили библиотеки. Пути разделяются точками с запятой. Я добавил скриншот с моими настройками ниже:

Additional library directories settings

Затем вам нужно получить Visual Studio для ссылки на файлы .lib. Эти разделы можно найти в поле «Дополнительные зависимости» компоновщика - & gt; Входной раздел свойств. Опять же, это список, разделенный точкой с запятой. Вы должны добавить в библиотеки для Python (в моем случае этоpython27.lib но это будет зависеть от версии) иbrisk_static.lib, Они не требуют полного пути, как вы добавили его на предыдущем этапе. Опять же, вот скриншот:

additional dependencies settings

Выmay также необходимо добавить файл библиотеки boost_python, но яthink boost использует некоторую магию заголовочных файлов, чтобы избавить вас от хлопот. Если я не прав, взгляните на ваш путь к библиотеке, чтобы найти файл, похожий наboost_python-vc100-mt.lib и добавить это в.

Наконец, вам нужно настроить пути включения, чтобы ваш проект мог включать соответствующие заголовочные файлы C ++. Чтобы соответствующие параметры отображались в свойствах проекта, вам необходимо добавить файл .cpp в свой проект. Щелкните правой кнопкой мыши папку с исходными файлами в обозревателе решений и перейдите к добавлению нового элемента. Выберите файл C ++ (.cpp) и назовите его main.cpp (или как хотите).

Затем вернитесь к свойствам вашего проекта и перейдите к C / C ++ - & gt; Генеральный. Под каталогом дополнительных библиотек вам нужно добавить пути включения для brisk, python и boost. Снова точки с запятой для разделителей и снова скриншот:

enter image description here

Я подозреваю, что вам может потребоваться обновить эти настройки, чтобы включить opencv2 & amp; Кроме того, библиотеки agast, но я оставлю это как задачу, которую вы должны выяснить - процесс должен быть почти таким же.

Wrapping existing c++ classes with boost::python.

Теперь немного сложнее - на самом деле писать C ++, чтобы обернуть вашу оживленную библиотеку в Boost Python. Вы можете найти учебник для этогоВот но я попытаюсь немного пройтись по нему.

Это будет происходить вmain.cpp файл, который вы создали ранее. Сначала добавьте соответствующие операторы включения, которые вам понадобятся, вверху файла:

#include <brisk/brisk.h>
#include <Python.h>
#include <boost/python.hpp>

Затем вам нужно объявить свой модуль python. Я предполагаю, что вы хотите, чтобы это называлось оживленным, поэтому вы делаете что-то вроде этого:

BOOST_PYTHON_MODULE(brisk)
{
}

Это должно сказать boost :: python для создания модуля python с именемbrisk.

Затем это всего лишь пример прохождения всех классов & amp; структуры, которые вы хотите обернуть и объявить над ними классы повышения Python. Все описания классов должны содержаться в brisk.h. Вы должны только обернуть общедоступных членов класса, а не каких-либо защищенных или частных членов. В качестве быстрого примера, я сделал пару структур здесь:

BOOST_PYTHON_MODULE(brisk)
{
    using namespace boost::python;

    class_< cv::BriskPatternPoint >( "BriskPatternPoint" )
         .def_readwrite("x", &cv::BriskPatternPoint::x)
         .def_readwrite("y", &cv::BriskPatternPoint::y)
         .def_readwrite("sigma", &cv::BriskPatternPoint::sigma);

    class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )
         .def( "constructPyramid", &cv::BriskScaleSpace::constructPyramid );
}

Здесь я обернул структуру cv :: BriskPatternPoint и класс cv :: BriskScaleSpace. Несколько быстрых объяснений:

class_< cv::BriskPatternPoint >( "BriskPatternPoint" ) говорит boost :: python объявить класс, используяcv::BriskPatternPoint Класс C ++, и выставить его какBriskPatternPoint в питоне.

.def_readwrite("y", &cv::BriskPatternPoint::y) добавляет читаемый & amp; свойство записи вBriskPatternPoint учебный класс. Свойство называется y и будет отображаться наBriskPatternPoint::y поле с ++.

class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() ) объявляет другой класс, на этот разBriskScaleSpace но также предоставляет конструктор, который принимает uint8_t (неподписанный байт - который должен просто отображаться на целое число в python, но я буду осторожен, чтобы не передать один больше чем 255 байтов - я не знаю, что произойдет в этом ситуация)

Следующие.def В строке просто объявляется функция - boost :: python должен (я думаю) иметь возможность автоматически определять типы аргументов функций, поэтому вам не нужно их предоставлять.

Вероятно, стоит отметить, что я на самом деле не скомпилировал ни один из этих примеров - они вполне могут не работать вообще.

В любом случае, чтобы это полностью работало в python, нужно просто выполнить аналогичные действия для каждой структуры, класса, свойства & amp; функция, которую вы хотите сделать доступной из python - это потенциально довольно трудоемкая задача!

Если вы хотите увидеть еще один пример этого в действии, я сделалэто здесь упаковатьэтот класс

Building & using the extension

Visual Studio должна позаботиться о создании расширения - тогда использовать его - это просто случай взять .DLL и переименовать его в .pyd (вы можете заставить VS сделать это за вас, но я оставлю это на ваше усмотрение).

Тогда вам просто нужно скопировать ваш файл Python куда-нибудь на вашем пути Python (site-packages например), импортируйте и используйте!

import brisk

patternPoint = brisk.BriskPatternPoint()
....    

Во всяком случае, я потратил примерно час на то, чтобы написать это, поэтому я собираюсь на этом остановиться. Извиняюсь, если я что-то пропустил или что-то не понятно, но я делаю это в основном по памяти. Надеюсь, это помогло вам. Если вам нужно что-то разъяснить, пожалуйста, оставьте комментарий или задайте другой вопрос.

@kobejohn Нет проблем! Я только что написалmassive редактировать с некоторыми более подробной информацией - надеюсь, это поможет.
Вот Это Да! Хорошо, пожалуйста, дайте мне время пройти через это. Похоже, именно то, что мне нужно. KobeJohn
Спасибо за предложения. У меня много чтения и практики. KobeJohn
Ваш первый абзац заставил меня думать, что вы знаете, о чем говорите, а также понимаете, что мне не хватает большего понимания, чем я думал :) На самом деле я уже прочитал документацию по расширению и не смог подключить ее к тому, что я пытаюсь сделать. Я расширяю сам Python? Я думал нет. Включая Python в C-код? Я думал нет. Я никогда не видел что-то похожее на то, что я пытаюсь сделать, но я, вероятно, просто неправильно понял. Кажется, мне нужно будет шаг за шагом пройтись по всему, что написано на C ++, до тех пор, пока у меня не получится описать все части. KobeJohn
Нужно остановиться на сегодня, но это должен быть правильный путь (или один правильный путь), чтобы оживленно работать. Спасибо. Наконец я добрался до точки, где я смог построить проект (только точка шаблона в вашем примере), и он генерировал файлы .exp, .pyd, .lib, .pdb. Однако, когда я импортирую Brisk.pyd, я получаю & quot; ImportError: Ошибка загрузки DLL: указанный модуль не найден. & Quot; Я посмотрю на это завтра (ходок по зависимостям? .., который я также использовал последние годы и годы назад). У вас есть быстрые предложения? KobeJohn

Похожие вопросы