【问题标题】:Linking c++-class for boost_python in cygwin在 cygwin 中为 boost_python 链接 c++ 类
【发布时间】:2017-06-15 22:04:43
【问题描述】:

一段时间以来,我一直在使用 c++ 类的包装器在 linux 上将函数导出到 python。现在我想使用 Windows 将它提供给我的同事。但是,我无法在 cygwin 中为此创建可用的 boost_python dll。尝试将依赖模块链接到另一个 dll 中时会出现问题,如果我将依赖源编译到同一个 dll 中,它会按预期工作。

我创建了一个显示问题的最小示例:

设置:

moduleB/moduleB.cpp # boost 封装代码

#include <python2.7/Python.h>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

#include "submodule.hpp"

using namespace boost::python;
using namespace testspace;
using namespace std;

struct cModuleB : public SubModuleClass {
    cModuleB(string name, bool boolVar) : SubModuleClass(name,     boolVar) {
    }

    void printFunc(string strVar, list listVar, int nIntVar=-1) {
        vector<int> vecList;
        for (int l=0; l < len(listVar); l++) {
            vecList.push_back(extract<int>(listVar[l]));
        }
        bool bMoreThanHalf = subModuleFunction(vecList);
        if (bMoreThanHalf) {
            cout << "More than half elements are more than 1";
        }
        return;
    }
};

BOOST_PYTHON_MODULE(moduleB)
{
    class_<cModuleB>("cModuleB", init<std::string, bool>())
      .def("printFunc", &cModuleB::printFunc);
}

submodule/submodule.hpp # 包含c++类的子模块

#include <vector>
#include <string>

using namespace std;

namespace testspace {

   class SubModuleClass {

     public:
            SubModuleClass(string name = "", bool bIsGreat = false);
            ~SubModuleClass();

            bool subModuleFunction(vector<int> & myVec);
   };
}
  • submodule/submodule.cpp #c++类定义
using namespace std;

#include "submodule.hpp"

using namespace testspace;

SubModuleClass::SubModuleClass(string name, bool bIsGreat)
{       
}

SubModuleClass::~SubModuleClass()
{               
}   

bool SubModuleClass::subModuleFunction(vector<int> & myVec)
{
    int nCounter = 0;
    for (vector<int>::iterator vi = myVec.begin(); vi != myVec.end(); vi++) {
        if (*vi > 1) nCounter++;
    }
    if (nCounter*2 > (int)myVec.size()) {
        return true;
    }
    else {
        return false;
    }
}

首先我们通过以下两个命令将子模块编译成共享库:

g++ -MMD -MP -ffloat-store -m64 -O0 -ggdb -DDEBUG -D_DEBUG \
     -c submodule/submodule.cpp -o submodule/submodule.o

g++ -m64 -shared -Wl,-soname=cygsubmodule_for_moduleB.dll \
    -Wl,--whole-archive submodule/submodule.o -Wl,--no-whole-archive \
    -Wl,--out-implib,./libsubmodule_for_moduleB.dll.a \
    -Wl,--export-all-symbols -Wl,--enable-auto-import \
    -o submodule/cygsubmodule.dll

我们编译实际的包装器代码并将其链接到我们应该能够从 python 导入的 boost_python dll(验证包含的示例在 ubuntu 上可以找到)。

g++ -MMD -MP -ffloat-store -m64 -O0 -ggdb -fPIC  \
    -Isubmodule -I/usr/include/python2.7 -DDEBUG -D_DEBUG \
    -c moduleB/moduleB.cpp -o moduleB/moduleB.o

g++ -m64 -shared -Wl,-soname=cygmoduleB.dll \
    -Wl,--whole-archive moduleB/moduleB.o -Wl,--no-whole-archive \
    -Wl,--out-implib,./libmoduleB.dll.a -Wl,--export-all-symbols \
    -Wl,--enable-auto-import -Lsubmodule -lsubmodule -lstdc++ 
    -lboost_python -lpython2.7 -o moduleB/cygmoduleB.dll

在 ubuntu 中,在从 .so 文件中删除 cyg 前缀并确保 submodule.soLD_LIBRARY_PATH 中后,可以按原样使用此模块。但是,cygwin 显示经典的导入错误:

>>> import moduleB
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No such file or directory

在 cygwin 和 Ubuntu 之间检查工作模块 B 上 ldd 的差异可以看到,在 moduleB.dll 的输出中,boost 和 python dll 已被问号替换。

cygwin 上的模块B:

# ldd moduleB.dll
ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x778b0000)
kernel32.dll => /cygdrive/c/Windows/system32/kernel32.dll (0x77470000)
KERNELBASE.dll => /cygdrive/c/Windows/system32/KERNELBASE.dll (0x7fefdfd0000)
SYSFER.DLL => /cygdrive/c/Windows/System32/SYSFER.DLL (0x75090000)
??? => ??? (0x4f3d00000)

Ubuntu 上的模块B:

# ldd moduleB.so
linux-vdso.so.1 =>  (0x00007fff55b73000)
libsubmodule.so => libsubmodule.so (0x00007fee4f9d7000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fee4f6a8000)
libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007fee4f144000)
libboost_python-py27.so.1.55.0 => /usr/lib/x86_64-linux-gnu/libboost_python-py27.so.1.55.0 (0x00007fee4eef7000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fee4ece1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee4e91b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fee4ddbf000)
/lib64/ld-linux-x86-64.so.2 (0x000055f47c1a6000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fee4dba0000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fee4d987000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fee4d783000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fee4d580000)

知道为什么 moduleB 无法在 cygwin 中将自己标识为 boost_module,以及为什么 g++ 无法包含适当的依赖信息吗?

boost_python 是使用 cygwin 中的包安装的。


更新: 除了下面的正确答案之外,还有两件事混淆了正确的解决方案:

  1. cygwin 上的ldd 不会提供与ubuntu 相同的输出,而不是&lt;library&gt;.dll =&gt; not found它只显示类似? =&gt; ? (&lt;address&gt;) 的内容
  2. 在 cygwin 上的 python 中加载依赖于dll 不在路径中的 boost 模块时,我们没有收到缺少 dll 的消息,只是找不到 boost 模块。

【问题讨论】:

  • 用 g++ 链接 c++ 模块,句号。谁说 gcc 或其他任何东西都应该起作用?不管怎样,显示你的实际构建命令,就像 make 调用的那样。
  • @n.m.我已经用一个完整的工作示例更新了帖子。
  • 您的模块名和文件名不匹配。您构建 cyfmoduleB.dll 但它应该被称为 moduleB.dll。我复制了你的步骤,将 cygmoduleB.dll 重命名为 moduleB.dll,结果是一个与 Python 完美兼容的模块(gcc 5.4.0,cygwin 今天更新)。
  • 奇怪。这对我不起作用,并且仍然只有来自 ldd 的问号。此外,命名要求在 linux 端也是如此,因此已经有一个复制命令将 [lib/cyg]moduleB.[so|dll] 移动到 moduleB.[so|dll]。我还使用了 gcc 5.4.0。非常感谢您的尝试!关于我们的两个案例之间可能有什么不同的任何其他想法?
  • 您的环境中的某些东西弄乱了您的模块。打开一个新的 shell,创建一个新的目录,取消设置除了必要的 PATH 之外的大多数环境,复制源代码和编译命令来自这篇文章,然后重试。

标签: python c++ boost g++ cygwin


【解决方案1】:

必须进行以下更改:

  1. 使用 g++ 链接 C++ 程序和库。
  2. Python 模块名称必须与文件名匹配,因此如果文件名为 moduleB.dll,则应在某处显示BOOST_PYTHON_MODULE(moduleB) 的行。
  3. 为了实际加载模块,它应该在 Python 的 sys.path 中,并且它的所有依赖项都应该在 windows %PATH% 中(或者在当前目录中,或者在 Windows 允许放置依赖 DLL 的任何地方)。 LD_LIBRARY_PATH 在 Cygwin 中的工作方式与在真实 Unix 系统中的工作方式不同。

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多