I have been using a wrapper for a c++-class for exporting functions to python for a while on linux. Now I wanted to make this available to my coworkers using windows. However, I fail to create a usable boost_python dll for this in cygwin. The problem arises when trying to link a dependent module in another dll, if I instead compile the dependent source into the same dll it works as expected.
I have a created a minimal example displaying the problem:
The setup:
moduleB/moduleB.cpp # The boost wrapper code
#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 # The submodule containing the c++ class
#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 # The c++ class definition
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;
}
}
First we compile submodule into a shared library by the following two commands:
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
And the we compile the actual wrapper code and link it into a boost_python dll that we should be able to import from python (verified that the included example works find on 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
In ubuntu this module can be used as is after removing the cyg
-prefix from the .so
file and making sure that the submodule.so
is in the LD_LIBRARY_PATH
. However, cygwin shows the classic import error:
>>> import moduleB
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No such file or directory
Examining the differences of ldd
on the working moduleB between cygwin and Ubuntu one can see that the boost and python dlls have beeen replaced by question marks in the output from moduleB.dll
.
moduleB on cygwin:
# 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)
moduleB on Ubuntu:
# 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)
Any idea as to why moduleB fails to identify itself as a boost_module in cygwin, and why g++
fails to include the appropriate dependency information?
boost_python was installed using the package in cygwin.
UPDATE: In addition to the correct answer below, two things should be noted that obfuscated the correct solution:
ldd
on cygwin does not give the same output as on ubuntu
and instead of <library>.dll => not found
it only displays something like ? => ? (<address>)
boost
module in python on cygwin that depends on a dll
not in path we do not get a message that a dll is missing, only that the boost module can not be found.Are you a Python developer with a C or C++ library you’d like to use from Python? If so, then Python bindings allow you to call functions and pass data from Python to C or C++, letting you take advantage of the strengths of both languages.
After spending some time at searching, we decided to include the Boost libraries, due to the large set of utilities they offer. Most of the C++ Boost libraries are header-only; they consist entirely of header files, and require no separately-compiled library binaries. However, there are some libraries that need to be built separately.
The Boost libraries includes a really nice build system, which we are definitely going to use it. The build system is triggered from the command line. First we have to open the cmd window and navigate into the root folder of the Boost library. Then we have to initialize the build system by running the bootstrap.bat file.
To build the Python bindings, you need to call .compile (): This wraps things up by generating the .c file, .o file, and the shared library. The invoke task you just walked through can be run on the command line to build the Python bindings:
The following changes must be made:
g++
. moduleB.dll
there should be a line that says BOOST_PYTHON_MODULE(moduleB)
in there somewhere.sys.path
, and all its dependencies should be in the windows %PATH%
(or in the current directory, or wherever Windows allows to put dependent DLLs). LD_LIBRARY_PATH
doesn't work in Cygwin the way it works in real Unix systems.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With