如何从c/c ++源代码获取Windows的python .pyd?(更新:现在在Python中快点,如果你想要的话)

Kob*_*ohn 10 c c++ python opencv

如何从C/C++扩展源代码获取到windows的pyd文件(或者我可以导入到Python的其他项目)?

编辑:我想要使​​用的特定库(BRISK)包含在 OpenCV 2.4.3中,因此我对此技能的需求暂时消失.如果你来这里寻找BRISK,这里是我发布的一个简单的Python演示中的 BRISK.


我有我想在我的python应用程序中构建和使用的Brisk源代码(下载).我得到了一个brisk.pyd文件...但它是0字节.如果有更好的/替代方法来瞄准brisk.pyd文件,那么我当然也对此持开放态度.

编辑:请忽略我在下面原始问题中的所有尝试,并查看我的答案,这是通过obmarg的详细演练实现的

我哪里错了?

  1. 没有库路径的Distutils:首先我尝试使用distutils和以下setup.py来构建源代码(我刚开始学习distutils,所以这是在黑暗中拍摄的).BRISK源代码的结构位于此问题的底部以供参考.

    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])
    
    Run Code Online (Sandbox Code Playgroud)

    这立刻给了我以下的行和构建文件夹中某处的0字节brisk.pyd.很近?

    running build
    running build_ext
    
    Run Code Online (Sandbox Code Playgroud)
  2. Distutils with library path: Scratch that attempt.所以我添加了上面setup.py中注释掉的两个库行.在我收到此链接错误之前,这似乎没问题:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 不受控制的flailing:我想也许需要构建库,所以我用cmake + mingw-mingw + vc ++ express 2010做了一个速成课程(很多崩溃),如下所示:

    • cmake gui: source:c:/ brisk,build:c:/ brisk/build
    • cmake gui:为Visual Studio 10配置
    • cmake gui:使用默认选项并生成(CMAKE_BACKWARDS_COMPATIBILITY,CMAKE_INSTALL_PREFIX,EXECUTABLE_OUTPUT_PATH,LIBRARY_OUTPUT_PATH)
    • VC++ Express 10:更改为发布并构建由cmake生成的解决方案,并获得大约20页的非严重警告,然后全部成功.注意 - 此处不会生成任何dll.它确实生成以下库,其大小与下载中包含的库类似:

      win32/lib/Release/
          agast_static.lib
          brisk_static.lib
      
      Run Code Online (Sandbox Code Playgroud)
  4. 进一步甩尾.

相关BRISK源文件结构供参考:

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
Run Code Online (Sandbox Code Playgroud)

obm*_*arg 12

你确定这个轻快的库甚至可以导出python绑定吗?我在源代码中看不到它的任何引用 - 它甚至似乎都没有导入python头文件.这肯定可以解释为什么到目前为止你没有取得多大成功 - 你不能只编译普通的C++代码并希望python与它接口.

我认为你的第二个distutils例子最接近正确 - 它显然是编译事物并进入链接器阶段,但是你遇到了这个错误.该错误只是意味着它无法找到名为initbrisk的函数,我猜这将是模块的顶级init函数.再次,这表明您正在尝试从不适合它的代码编译python模块.

如果您想自己将C++代码包装在python包装器中,您可以查看有关编写c/c ++扩展的官方文档.或者你可以看看boost :: python,SIPshiboken,它试图在某种程度上(或完全)自动化从C++代码制作python扩展的过程.

编辑:既然你似乎已经做了相当多的努力来自己解决问题,并发布了一个很好的问题,我已经决定就如何去做这个问题做出更详细的回应.

使用boost :: python包装C++库的快速教程

就个人而言,我只使用过boost :: python这样的东西,所以我会试着给你一个如何去做的好总结.我将假设您正在使用Visual C++ 2010.我还假设您已经安装了32位版本的python,因为我相信boost pro库只提供32位二进制文​​件.

安装boost

首先,您需要获取boost库的副本.最简单的方法是从boost pro网站下载安装程序.这些应该安装在Windows上使用boost c ++库所需的所有头文件和二进制文件.请注意您将这些文件安装到的位置,稍后您将需要它们 - 最好安装到没有空间的路径中.为了简单起见,我假设您将这些文件放在C:\ boost中,但您可以将其替换为您实际使用的路径.

或者,您可以按照这些说明从源代码构建增强功能.我不是百分百肯定,但可能是你要这样做才能获得与你安装的python版本兼容的boost :: python版本.

设置可视工作室项目

接下来,您将要为brisk.pyd设置visual studio项目.如果打开visual studio,请转到New - > Project,然后找到Win32 Project的选项.设置您的位置等,然后单击确定.在出现的向导中选择一个DLL项目类型,然后勾选空项目复选框.

现在您已经创建了项目,您需要设置包含和库路径以允许您使用python,boost :: python和brisk.lib文件.

在Visual Studios解决方案资源管理器中,右键单击您的项目,然后从显示的菜单中选择属性.这应该打开项目的属性页面.转到链接器 - >常规部分,然后查找"其他库目录"部分.你需要填写.libboost,python和你的文件路径brisk_static.lib.通常,这些都可以在您安装库的任何地方的lib(或libs)子目录中找到.路径用分号分隔.我附上了以下设置的屏幕截图:

其他库目录设置

接下来,您需要让visual studio链接到.lib文件.这些部分可以在属性的链接器 - >输入部分的附加依赖关系字段中找到.它再次是以分号分隔的列表.您应该为python添加库(在我的情况下,这是python27.lib因为版本会有所不同)和brisk_static.lib.这些不需要在前一阶段添加的完整路径.再次,这是一个截图:

其他依赖项设置

可能还需要添加boost_python库文件,但我认为 boost使用一些头文件魔术来为您省去麻烦.如果我不正确,那么看看你为一个名为的类似的文件增加库路径boost_python-vc100-mt.lib并添加它.

最后,您需要设置包含路径以允许项目包含相关的C++头文件.要使相关设置显示在项目属性中,您需要将.cpp文件添加到项目中.右键单击解决方案资源管理器中的源文件文件夹,然后转到添加新项目.选择一个C++文件(.cpp)并将其命名为main.cpp(或您想要的任何其他内容).

接下来,返回项目属性并转到C/C++ - > General.在其他库目录下,您需要为brisk,python和boost添加包含路径.再次,分隔符用分隔符,再次在这里是截图:

在此输入图像描述

我怀疑您可能需要更新这些设置以包含opencv2和agast库,但我会将其作为一项任务让您弄清楚 - 它应该是相同的过程.

使用boost :: python包装现有的c ++类.

现在有点棘手的一点 - 实际上编写C++来将你的轻快库包装在boost python中.你可以在这里找到这方面的教程,但我会试着稍微讨论一下.

这将发生在main.cpp您之前创建的文件中.首先,在文件顶部添加您需要的相关include语句:

#include <brisk/brisk.h>
#include <Python.h>
#include <boost/python.hpp>
Run Code Online (Sandbox Code Playgroud)

接下来,您需要声明您的python模块.我假设你想要这个被称为轻快,所以你做这样的事情:

BOOST_PYTHON_MODULE(brisk)
{
}
Run Code Online (Sandbox Code Playgroud)

这应该告诉boost :: python创建一个名为的python模块brisk.

接下来,它只是一个遍历所有要包装的类和结构并用它们声明boost python类的情况.类的declerations都应该包含在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 );
}
Run Code Online (Sandbox Code Playgroud)

在这里,我已经包装了cv :: BriskPatternPoint结构和cv :: BriskScaleSpace类.一些快速解释:

class_< cv::BriskPatternPoint >( "BriskPatternPoint" )告诉boost :: python使用cv::BriskPatternPointC++类声明一个类,并BriskPatternPoint在python中公开它.

.def_readwrite("y", &cv::BriskPatternPoint::y)为类添加可读和可写属性BriskPatternPoint.该属性名为y,将映射到BriskPatternPoint::yc ++字段.

class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )声明另一个类,这次BriskScaleSpace还提供了一个接受uint8_t的构造函数(一个无符号字节 - 它应该只映射到python中的一个整数,但是我要小心不要传入一个大于255字节的字节 - 我不是知道那种情况会发生什么)

以下.def行只是声明了一个函数 - boost :: python应该(我认为)能够自动确定函数的参数类型,因此您不需要提供它们.

值得注意的是,我实际上没有编译任何这些例子 - 它们可能根本不起作用.

无论如何,为了让它在python中完全运行,它应该只是为你想从python访问的每个结构,类,属性和函数做类似的事情 - 这可能是一个非常耗时的任务!

如果你想看到另一个这样的例子,我在这里做了这个以结束这个类

构建和使用扩展

Visual Studio应该负责构建扩展 - 然后使用它只是一个获取.DLL并将其重命名为.pyd的情况(你可以让VS为你做这个,但我会把它留给你).

然后你只需要将你的python文件复制到你的python路径上的某个地方(site-packages例如),导入它并使用它!

import brisk

patternPoint = brisk.BriskPatternPoint()
....    
Run Code Online (Sandbox Code Playgroud)

无论如何,我花了一个小时左右写出来 - 所以我要停在这里.如果我遗漏了任何东西或者有什么不清楚的话,我会道歉,但我主要是从记忆中做到这一点.希望它对你有所帮助.如果您需要澄清任何内容,请发表评论或提出其他问题.