如何从 c/c++ 源代码获取适用于 Windows 的 python .pyd? (更新:现在在 Python 中轻快,以防万一这是你想要的)

2024-03-11

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

edit:我想使用的特定库(BRISK)包含在OpenCV http://opencv.org/2.4.3 所以我暂时不需要这个技能了。如果您来这里寻找 BRISK,这里有一个简单的Python 演示中的 BRISK http://github.com/kobejohn/python_brisk_demo我发布的。


我有Brisk http://www.asl.ethz.ch/people/lestefan/personal/BRISK源代码 (download http://www.asl.ethz.ch/people/lestefan/personal/BRISK/brisk.zip)我想在我的 python 应用程序中构建和使用它。我已经生成了 brisk.pyd 文件...但它是 0 字节。如果有更好/替代的方法来瞄准 brisk.pyd 文件,那么我当然也对此持开放态度。

edit:请忽略下面我原来问题中的所有尝试,并查看我的答案,这是通过 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])
    

    这立即给了我以下几行和一个0 字节 轻快.pyd构建文件夹中的某个位置。很近?

    running build
    running build_ext
    
  2. Distutils 与库路径:放弃那个尝试。所以我添加了上面 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
    
  3. 不受控制的挥舞:我想也许需要构建这些库,所以我用 cmake + mingw - mingw + vc++ express 2010 做了一个速成课程(很多崩溃),如下所示:

    • cmake 图形用户界面:来源:c:/brisk,构建:c:/brisk/build
    • cmake 图形用户界面:针对 Visual Studio 10 配置
    • cmake 图形用户界面:使用默认选项并生成(CMAKE_BACKWARDS_COMPATIBILITY、CMAKE_INSTALL_PREFIX、EXECUTABLE_OUTPUT_PATH、LIBRARY_OUTPUT_PATH)
    • VC++ Express 10:更改为 Release 并构建由 cmake 生成的解决方案,并获得大约 20 页看起来像是非关键警告的内容,然后全部成功。注意 - 这不会生成 dll。它确实会生成以下与下载中包含的库大小相似的库:

      win32/lib/Release/
          agast_static.lib
          brisk_static.lib
      
  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

您确定这个轻快的库甚至导出 python 绑定吗?我在源代码中看不到任何对它的引用——它甚至似乎没有导入 python 头文件。这肯定可以解释为什么到目前为止您还没有取得太大成功 - 您不能只编译纯 C++ 代码并期望 python 与其交互。

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

如果你想自己将 C++ 代码包装在 python 包装器中,你可以看看关于编写 c/c++ 扩展的官方文档 http://docs.python.org/extending/extending.html。或者你可以看看提升::蟒蛇 http://www.boost.org/doc/libs/1_49_0/libs/python/doc/, SIP http://www.riverbankcomputing.co.uk/software/sip/intro or shiboken http://www.pyside.org/docs/shiboken/它试图在某种程度上(或完全)自动化从 C++ 代码创建 python 扩展的过程。

编辑:由于您似乎已经付出了相当大的努力来自己解决问题,并且发布了一个很好的问题,因此我决定就如何去做这件事给出更详细的答复。

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

就我个人而言,我只使用过 boost::python 来完成类似的事情,所以我将尝试为您提供一个关于如何做到这一点的很好的总结。我将假设您使用的是 Visual C++ 2010。我还将假设您安装了 32 位版本的 python,因为我相信 boost pro 库仅提供 32 位二进制文​​件。

安装升压

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

或者,您可以按照这些说明 http://www.boost.org/doc/libs/1_49_0/more/getting_started/windows.html#or-build-binaries-from-source从源头打造提升。我不是 100% 确定,但情况可能是这样need这样做是为了获得与您安装的 python 版本兼容的 boost::python 版本。

设置视觉工作室项目

接下来,您需要为 brisk.pyd 设置一个 Visual Studio 项目。如果您打开 Visual Studio,请转到“新建”->“项目”,然后找到“Win32 项目”选项。设置您的位置等,然后单击“确定”。在出现的向导中选择 DLL 项目类型,然后勾选空项目复选框。

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

在 Visual Studio 解决方案资源管理器中,右键单击您的项目,然后从出现的菜单中选择属性。这应该会打开您的项目的属性页。转到链接器 -> 常规部分并查找其他库目录部分。您需要用到的路径填写此内容.libboost、python 和你的文件brisk_static.lib。一般来说,这些可以在lib (or libs) 的子目录 无论您在何处安装了库。路径用分号分隔。我在下面附上了我的设置的屏幕截图:

接下来,您需要让 Visual Studio 链接到 .lib 文件。这些部分可以在属性的链接器 -> 输入部分的附加依赖项字段中找到。这又是一个以分号分隔的列表。您应该需要添加 python 库(在我的例子中是python27.lib但这会因版本而异)和brisk_static.lib。这些不需要您在上一阶段添加的完整路径。再次,这是一个屏幕截图:

You may还需要添加 boost_python 库文件,但我thinkboost 使用一些头文件魔法来省去你的麻烦。如果我不正确,那么请查看您的 boost 库路径中是否有一个名为类似于的文件boost_python-vc100-mt.lib并将其添加进去。

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

接下来,返回项目属性并转到 C/C++ -> 常规。在附加库目录下,您需要添加 brisk、python 和 boost 的包含路径。同样,分隔符用分号,这里还是一个屏幕截图:

我怀疑您可能需要更新这些设置以包括 opencv2 和 agast 库,但我将把它作为一项任务留给您来解决 - 它应该是大致相同的过程。

使用 boost::python 包装现有的 C++ 类。

现在出现了稍微棘手的一点 - 实际上编写 C++ 将你的 brisk 库包装在 boost python 中。你可以找到这方面的教程here http://www.boost.org/doc/libs/1_49_0/libs/python/doc/tutorial/doc/html/index.html但我也会尝试稍微回顾一下。

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

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

接下来,您需要声明您的 python 模块。我假设您希望将其称为“轻快”,因此您可以执行以下操作:

BOOST_PYTHON_MODULE(brisk)
{
}

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

接下来,只需检查要包装的所有类和结构并用它们声明 boost 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::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 个字节 - 我不知道会发生什么)的构造函数情况)

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

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

不管怎样,为了让这个在Python中完全工作,应该对你想要从Python访问的每个结构、类、属性和函数做类似的事情——这可能是一项相当耗时的任务!

如果你想看看另一个实际的例子,我做了这里 https://raw.github.com/obmarg/syncro/develop/Syncro%20Server/libsyncro/pysyncro/pysyncro.cpp结束这个班 https://github.com/obmarg/syncro/blob/develop/Syncro%20Server/libsyncro/include/libsyncro/connection.h

构建和使用扩展

Visual Studio 应该负责构建扩展 - 然后使用它只是获取 .DLL 并将其重命名为 .pyd(您可以让 VS 为您完成此操作,但我将把它留给您)。

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

import brisk

patternPoint = brisk.BriskPatternPoint()
....    

不管怎样,我花了一个小时左右的时间来写这篇文章——所以我就到这里为止。如果我遗漏了任何内容或者有任何不清楚的地方,我深表歉意,但我主要是凭记忆做的。希望对您有所帮助。如果您需要澄清任何内容,请发表评论,或提出其他问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 c/c++ 源代码获取适用于 Windows 的 python .pyd? (更新:现在在 Python 中轻快,以防万一这是你想要的) 的相关文章

随机推荐

  • 如何使用系统对话框图标加载图像列表

    如何加载TCustomImageList对话框中 Windows 使用的所有系统图标 标准图标 如警告 错误 信息 确认 我想找到一个适用于 Windows XP 及更高版本的解决方案 See LoadImage https msdn mi
  • Perl 中的 $dxyabc 和 ${dxyabc} 有什么区别?

    字符串定义有什么区别 dxyabc和字符串 dxyabc 在 Perl 中 嗯 这取决于上下文 例如 foo dxyabcdef bar dxyabc def foo将具有以下价值 dxyabcdef代替 dxyabc附加有def 这是的值
  • 在字符串内使用带有 LESS 的函数

    我搜索了文档和 SO 但找不到我的查询的答案 使用 LESS 将函数结果包含在字符串中的正确方法是什么 例如 我定义了一个变量 并希望将其变亮以形成盒子阴影 例如 这就是我想做的事情 box shadow inset 0 1px 1px r
  • AngularJS:如何模拟注入范围内的 FormController?

    我在控制器内部发生了一些验证逻辑 我想对该逻辑进行单元测试 问题是我不知道如何模拟自动注入范围的表单控制器 任何想法 AFAIK 你可以尝试两种方法 use the compile服务 并使用适当的方法编译您的模板 scope 别忘了所有
  • 使用 knitr 制作动画 rgl 图表

    我想加入动画rgl我的图表 Rnw文档通过knitr 这是我的 MWE documentclass article lt lt label setup include FALSE gt gt opts chunk set fig path
  • 如何根据视图边界在Cesium Map中向左或向右旋转

    想要模仿 CesiumJS 应用程序中的左右箭头键 类似于 Google 地球导航 按向右或向左箭头键应分别向右或向左旋转地球约 5 的视图边界 如果缩小 则旋转较大范围 而放大则旋转较小范围 已经查看了文档Viewer https ces
  • C# 延迟初始化 && 竞争初始化?

    After about LazyInitializer那是 它提供了另一种具有多线程的初始化模式 竞赛初始化 这是一个示例 Expensive expensive public Expensive Expensive get Impleme
  • flex-direction 列属性不起作用

    我有一个ul标记为display flex 我需要按列排序flex direction column 但它不起作用 容器的 CSS nav li four columns ul sub menu width 600px display fl
  • Emacs:与 TAB 的键绑定会破坏迷你缓冲区中的自动完成功能

    简而言之 我只是在 TAB 键上设置了键绑定 但是现在当我将 TAB 推入迷你缓冲区以自动完成命令时 它会失败并显示以下消息 The mark is not set now so there is no region 换句话说 当我的光标位
  • 任务“:audioplayers:compileDebugKotlin”执行失败

    当我尝试将我的 Flutter 应用程序编译到 Android 模拟器中时 我遇到了这个讨厌的错误 这是错误日志 太长 无法完整粘贴 在调试模式下在 sdk gphone x86 上启动 lib main dart 运行 Gradle 任务
  • 将 Sqlite 数据导入 Google App Engine

    我有一个相对广泛的 sqlite 数据库 我想将其导入到我的 Google App Engine python 应用程序中 我使用 appengine API 创建了模型 该模型与现有架构很接近 但并不完全相同 我编写了一个导入脚本来从 s
  • 将一个 UIView 的绘制内容复制到另一个 UIView

    我想采用 UITextView 并允许用户在其中输入文本 然后触发将内容复制到石英位图上下文上 有谁知道我如何执行此复制操作 我应该重写drawRect方法并调用 super drawRect 并且then获取生成的上下文并复制它 如果是这
  • 是否可以在 phpmyadmin 中分页浏览视图? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 运行 phpmyadmin 版本 3 4 8 我刚刚注意到 显示视图时没有 分页 按钮 可以让您像浏览表格一样跳转到下一页或最后一页 我知
  • Mvc Api 从请求中获取凭据

    我花了很长时间才找到这方面的东西 尽管我认为这很简单 我正在使用 NET MVC 4 5 开发 API 我希望最终用户能够发送类似 PowerShell 的请求 webclient new object System Net WebClie
  • 如何解决AdjustCapsLockLEDForKeyTransitionHandling问题?

    我正在尝试使用KeyListener输入信息 例如使用箭头键在平面上移动对象 但是一旦我按下第一个键 就会抛出以下错误 2021 05 20 09 55 35 400 java 36269 3330310 TSM AdjustCapsLoc
  • SwiftUI TabView PageTabViewStyle 阻止更改选项卡?

    我有一个TabView在 SwiftUI 中PageViewTabStyle这样我就可以从一页滑动到另一页 我想要一个设置来 锁定 当前视图 这样用户就无法滑动 谷歌搜索和阅读文档并没有给我带来任何明显的结果 所以我希望 SO 上的专家可以
  • setTimeout 的最小毫秒值是多少?

    我想把 var minValue 0 if typeof callback function setTimeout callback minValue 当我用 JavaScript 实现回调函数时 这段代码 但我发现现代浏览器和一些旧浏览器
  • /TSAWARE 链接器标志对 PE 可执行文件有什么作用?

    将 TSAWARE 链接器标志添加到我的一个项目 Visual Studio 6 后 我惊讶地发现 PE 文件 idata 中出现了一个新部分 如果我不设置该标志 导入将合并到 rdata 中 为了说明 问题 我们从一个简单的控制台程序开始
  • 地理编码器“等待服务器响应超时”

    我正在尝试将纬度和经度转换为地址 当我使用 WIFI 时 我得到了正确的答案 但当我尝试使用 3G LTE 时 出现错误 等待服务器响应超时 我在调试模式下发现了这一点 但为什么 我使用相同的信息 纬度 经度 我该如何修复它 这是我的功能
  • 如何从 c/c++ 源代码获取适用于 Windows 的 python .pyd? (更新:现在在 Python 中轻快,以防万一这是你想要的)

    如何从 C C 扩展源代码获取 Windows 的 pyd 文件 或我可以导入到 Python 的其他项目 edit 我想使用的特定库 BRISK 包含在OpenCV http opencv org 2 4 3 所以我暂时不需要这个技能了