Search code examples
pythonc++cpython

C++ extension in Python 'DLL load failed'


for a school project I need to connect a Intel Realsense (3D camera) with Python to use it with RoboDK and OpenCV. I'm doing this with MVS 2019. With superfastcode2 (C++) and RealsenseDistanceV3 (Python) set to 64-bit.

This tutorial I followed for creating a C++ extension and that works good.

Now I'm including the <librealsense2\rs.hpp> into the module.cpp code and everything compiles and works well. However, only in release mode. In debug mode I get these errors while compiling:

Error   LNK2019 unresolved external symbol __imp__invalid_parameter referenced in function "void * __cdecl std::_Allocate_manually_vector_aligned<struct std::_Default_allocate_traits>(unsigned __int64)" (??$_Allocate_manually_vector_aligned@U_Default_allocate_traits@std@@@std@@YAPEAX_K@Z)   superfastcode2  C:\Users\Gebruiker\source\repos\RealsenseDistanceV3\superfastcode2\module.obj

Error   LNK2019 unresolved external symbol __imp__CrtDbgReport referenced in function "void * __cdecl std::_Allocate_manually_vector_aligned<struct std::_Default_allocate_traits>(unsigned __int64)" (??$_Allocate_manually_vector_aligned@U_Default_allocate_traits@std@@@std@@YAPEAX_K@Z)    superfastcode2  C:\Users\Gebruiker\source\repos\RealsenseDistanceV3\superfastcode2\module.obj

When using a function (rs2::pipeline p;) from the Realsense library in the C++ code, the following error occurs. DLL load failed while importing superfastcode2: Kan opgegeven module niet vinden (English: cannot find module).

That is logical because when looking at the superfastcode2.log it says:

     Creating library C:\Users\Gebruiker\source\repos\RealsenseDistanceV3\Release\superfastcode2.lib and object C:\Users\Gebruiker\source\repos\RealsenseDistanceV3\Release\superfastcode2.exp
module.obj : error LNK2001: unresolved external symbol __imp__PyFloat_AsDouble
module.obj : error LNK2001: unresolved external symbol __imp__PyFloat_FromDouble
module.obj : error LNK2001: unresolved external symbol __imp__PyModule_Create2
C:\Users\Gebruiker\source\repos\RealsenseDistanceV3\Release\superfastcode2.pyd : fatal error LNK1120: 3 unresolved

Module.cpp (from superfastcode2):

#include <Python.h>
#include <Windows.h>
#include <cmath>
#include <librealsense2\rs.hpp> // Include RealSense Cross Platform API
#include <iostream>             // for cout

const double e = 2.7182818284590452353602874713527;

double sinh_impl(double x) {
    return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x));
}

double cosh_impl(double x) {
    return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x));
}

double askRealsenseDistance()
{
    return 5.25;
}

void connectRealsense()
{
    rs2::pipeline p;
}


PyObject* tanh_impl(PyObject*, PyObject* o) {
    double x = PyFloat_AsDouble(o);
    double tanh_x = sinh_impl(x) / cosh_impl(x);
    return PyFloat_FromDouble(tanh_x);
}

PyObject* askRealsenseDistance_impl(PyObject*, PyObject* o) {
    //double distance = askRealsenseDistance();
    double distance = PyFloat_AsDouble(o)/100;
    connectRealsense();
    return PyFloat_FromDouble(distance);
}


static PyMethodDef superfastcode2_methods[] = {
    // The first property is the name exposed to Python, fast_tanh, the second is the C++
    // function name that contains the implementation.
    { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
    { "askRealsenseDistance_py", (PyCFunction)askRealsenseDistance_impl, METH_O, nullptr },

    // Terminate the array with an object containing nulls.
{ nullptr, nullptr, 0, nullptr }
};



static PyModuleDef superfastcode2_module = {
    PyModuleDef_HEAD_INIT,
    "superfastcode2",                        // Module name to use with Python import statements
    "Provides some functions, but faster",  // Module description
    0,
    superfastcode2_methods                   // Structure that defines the methods of the module
};

PyMODINIT_FUNC PyInit_superfastcode2() {
    return PyModule_Create(&superfastcode2_module);
}

And RealsenseDitanceV3.py (from RealsenseDistanceV3):

from itertools import islice
from random import random
from time import perf_counter
from superfastcode2 import fast_tanh
from superfastcode2 import askRealsenseDistance_py

COUNT = 500000  # Change this value depending on the speed of your computer
DATA = list(islice(iter(lambda: (random() - 0.5) * 3.0, None), COUNT))

e = 2.7182818284590452353602874713527


def sinh(x):
    return (1 - (e ** (-2 * x))) / (2 * (e ** -x))


def cosh(x):
    return (1 + (e ** (-2 * x))) / (2 * (e ** -x))


def tanh(x):
    tanh_x = sinh(x) / cosh(x)
    return tanh_x


def test(fn, name):

    start = perf_counter()
    result = fn(DATA)
    duration = perf_counter() - start
    print('{} took {:.3f} seconds\n\n'.format(name, duration))

    for d in result:
        assert -1 <= d <= 1, " incorrect values"


#if __name__ == "__main__":
    #print('Running benchmarks with COUNT = {}'.format(COUNT))

    #test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')

    #test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)')

number = 8050
print('send: {} to cpp which divides it by 100'.format(number))
output = askRealsenseDistance_py(number)
print('received from cpp: {}'.format(output))

For clarification, if the line rs2::pipeline p; or if the line connectRealsense(); is removed from module.cpp, everything works fine. Somehow, I think the Realsense C++ functions are not recognised (or something) by the Python.h (CPython) library.

Hope you have some suggestions, thanks in advance!


Solution

  • Found the solution!! You need to copy the .dll file from the Realsense library in the output library.. After I found out, it seems pretty logical, but first I thought MVS will make the .dll file itself (from the whole code) to use in Python. It turns out, that that's not the case, instead the .dll file is only from the Realsenselibrary. Thanks for the help everyone! enter image description here