最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Python: ctypes.CDLL cannot load c++ compiled shared .dll file - Stack Overflow

programmeradmin1浏览0评论

I have written some functions within my C++ app and i compiled it to use it as .dll and so i can use those functions in python for a better performance. The .dll file works fine when i'm using it for another C++ application but when i want to load it in my python program it throws this error:

Traceback (most recent call last):
  File "e:\My Apps\Python\Telegram_Bots\Calculator\main.py", line 6, in <module>
    lib = CDLL("E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\KHATAM_PC\AppData\Local\Programs\Python\Python311\Lib\ctypes\__init__.py", line 376, in __init__
    self._handle = _dlopen(self._name, mode)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: Could not find module 'E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll' (or one of its dependencies). Try using the full path with constructor syntax.

I've quarterable checked the path and even used the full-path, never worked, been trying for a whole day, compiling the .dll again and again in different ways and methods but nothing came out of them, all of them yet worked in C++

.dll exportation command: g++ -DMATH_DLL_EXPORTS -shared -std=c++17 -o lib.dll lib.cpp

lib.hpp:

// #pragma once

#ifndef MATH_DLL_API
#define MATH_DLL_API

#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif

#include <iostream>
#include <vector>
extern "C" {
    DLL_EXPORT int precedence(char o);
    DLL_EXPORT float calc(float a, float b, char o);
    DLL_EXPORT void calculate(std::vector<float>& values, std::vector<char>& ops);
    DLL_EXPORT float evaluate(std::string e);
}
#endif // MATH_DLL_API

lib.cpp:

#include "lib.hpp"
#include <iostream>
#include <vector>
extern "C" {
    DLL_EXPORT int precedence(char o) { ... }
    DLL_EXPORT float calc(float a, float b, char o) { ... }
    DLL_EXPORT void calculate(std::vector<float>& values, std::vector<char>& ops) { ... }
    DLL_EXPORT float evaluate(std::string e) { ... }
}

And finaly, the python script:

from ctypes import c_char, c_int, c_float, c_char_p, c_void_p, CDLL, cdll, POINTER

lib = CDLL("E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll")

lib.evaluate.argtypes = [c_char_p]
lib.evaluate.restype = c_float

lib.calculate.argtypes = [POINTER(c_float), POINTER(c_char)]
lib.calculate.restype = c_void_p

lib.calc.argtypes = [c_float, c_float, c_char]
lib.calc.restype = c_float

lib.precedence.argtypes = [c_char]
lib.precedence.restype = c_int

Can anybody help please?

I have written some functions within my C++ app and i compiled it to use it as .dll and so i can use those functions in python for a better performance. The .dll file works fine when i'm using it for another C++ application but when i want to load it in my python program it throws this error:

Traceback (most recent call last):
  File "e:\My Apps\Python\Telegram_Bots\Calculator\main.py", line 6, in <module>
    lib = CDLL("E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\KHATAM_PC\AppData\Local\Programs\Python\Python311\Lib\ctypes\__init__.py", line 376, in __init__
    self._handle = _dlopen(self._name, mode)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: Could not find module 'E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll' (or one of its dependencies). Try using the full path with constructor syntax.

I've quarterable checked the path and even used the full-path, never worked, been trying for a whole day, compiling the .dll again and again in different ways and methods but nothing came out of them, all of them yet worked in C++

.dll exportation command: g++ -DMATH_DLL_EXPORTS -shared -std=c++17 -o lib.dll lib.cpp

lib.hpp:

// #pragma once

#ifndef MATH_DLL_API
#define MATH_DLL_API

#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif

#include <iostream>
#include <vector>
extern "C" {
    DLL_EXPORT int precedence(char o);
    DLL_EXPORT float calc(float a, float b, char o);
    DLL_EXPORT void calculate(std::vector<float>& values, std::vector<char>& ops);
    DLL_EXPORT float evaluate(std::string e);
}
#endif // MATH_DLL_API

lib.cpp:

#include "lib.hpp"
#include <iostream>
#include <vector>
extern "C" {
    DLL_EXPORT int precedence(char o) { ... }
    DLL_EXPORT float calc(float a, float b, char o) { ... }
    DLL_EXPORT void calculate(std::vector<float>& values, std::vector<char>& ops) { ... }
    DLL_EXPORT float evaluate(std::string e) { ... }
}

And finaly, the python script:

from ctypes import c_char, c_int, c_float, c_char_p, c_void_p, CDLL, cdll, POINTER

lib = CDLL("E:\My Apps\Python\Telegram_Bots\Calculator\lib.dll")

lib.evaluate.argtypes = [c_char_p]
lib.evaluate.restype = c_float

lib.calculate.argtypes = [POINTER(c_float), POINTER(c_char)]
lib.calculate.restype = c_void_p

lib.calc.argtypes = [c_float, c_float, c_char]
lib.calc.restype = c_float

lib.precedence.argtypes = [c_char]
lib.precedence.restype = c_int

Can anybody help please?

Share Improve this question asked Mar 13 at 11:25 user26649650user26649650 55 bronze badges 10
  • 1 The error is morst likely caused because a dependent of your dll is not found. See Loading shared libraries in the ctypes documentation. – OldBoy Commented Mar 13 at 11:41
  • I know it was in the description but my module seems so simple! i don't think if it has any dependecies also i tried using depends.exe but it hanged and crashed while trying to find dependencies to my dll – user26649650 Commented Mar 13 at 12:54
  • are there any command that'll build the .dll along with its dependencies?! – user26649650 Commented Mar 13 at 12:58
  • I do not know of any such application. If your library makes reference to external functions then the final dll will contain that reference, and the Windows loader should resolve it at load time. I have used my own DLLs in C/CPP programs with no problem but not tried with Python. – OldBoy Commented Mar 13 at 13:08
  • In my program i'm accepting references as parameters in those functions, maybe if they're pointers instead? or maybe i should completely avoid vectors? because u see.. i ONLY need that evaluation function, that function uses the other ones to function... does that change things? or u think i should try to combine all of them into one? – user26649650 Commented Mar 13 at 13:11
 |  Show 5 more comments

1 Answer 1

Reset to default 0
  • As the error text indicates, your library (or one of its dependent .dlls) is not found. For more details on .dll dependencies, check [SO]: Discover missing module using command-line ("DLL load failed" error) (@CristiFati's answer)

    • Once dependencies were identified, their locations must be added to the .dll search paths. Check [SO]: PyWin32 and Python 3.8.0 (@CristiFati's answer) for more details
  • [Python.Docs]: ctypes - A foreign function library for Python (as its name suggests), works with C not C++, therefore any STL stuff should be wrapped in C functions. Might also want to check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall when working with CTypes (calling functions)

I prepared a MCVE. Based on your build command, I assume you're using a Nix emulator - I am using MSYS2.

  • dll00.hpp:

    #pragma once
    
    #include <string>
    #include <vector>
    
    #include <cstdint>
    
    #if defined(_WIN32)
    #  if defined(DLL00_EXPORTS)
    #    define DLL00_EXPORT_API __declspec(dllexport)
    #  else
    #    define DLL00_EXPORT_API __declspec(dllimport)
    #  endif
    #else
    #  define DLL00_EXPORT_API
    #endif
    
    
    DLL00_EXPORT_API void calculate(std::vector<float> &values, std::vector<char> &ops);
    DLL00_EXPORT_API float evaluate(std::string s);
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    DLL00_EXPORT_API int precedence(char c);
    DLL00_EXPORT_API float calc(float f0, float f1, char c);
    DLL00_EXPORT_API void calculate_c(float *values, size_t v_size, char *ops, size_t o_size);
    DLL00_EXPORT_API float evaluate_c(const char *s);
    
    #if defined(__cplusplus)
    }
    #endif
    
  • dll00.cpp:

    #define DLL00_EXPORTS
    #include "dll00.hpp"
    
    #include <cstdio>
    
    
    int precedence(char c)
    {
        return c;
    }
    
    float calc(float f0, float f1, char c)
    {
        return f0 + f1 + c;
    }
    
    void calculate(std::vector<float> &values, std::vector<char> &ops)
    {
        for (size_t i = 0; i < values.size(); ++i)
            values[i] += ops[i % ops.size()];
    }
    
    float evaluate(std::string s)
    {
        return s.size() / 2;
    }
    
    void calculate_c(float *values, size_t v_size, char *ops, size_t o_size)
    {
        std::vector<float> vs;
        vs.reserve(v_size);
        for (size_t i = 0; i < v_size; ++i)
            vs.emplace_back(values[i]);
        std::vector<char> os;
        os.reserve(o_size);
        for (size_t i = 0; i < o_size; ++i)
            os.emplace_back(ops[i]);
        calculate(vs, os);
        for (size_t i = 0; i < v_size; ++i)
            values[i] = vs[i];
    }
    
    float evaluate_c(const char *s)
    {
        return evaluate(s);
    }
    
  • code00.py:

    #!/usr/bin/env python
    
    import ctypes as cts
    import os
    import sys
    
    
    DLL_NAME = "./libdll00_msys.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
    
    FloatPtr = cts.POINTER(cts.c_float)
    CharPtr = cts.POINTER(cts.c_char)
    
    
    def main(*argv):
        if argv:
            add = getattr(os, "add_dll_directory")
            if add:
                print("Add directory")
                add(argv[0])
        dll = cts.CDLL(DLL_NAME)
    
        precedence = dll.precedence
        precedence.argtypes = (cts.c_char,)
        precedence.restype = cts.c_int
    
        calc = dll.calc
        calc.argtypes = (cts.c_float, cts.c_float, cts.c_char)
        calc.restype = cts.c_float
    
        calculate = dll.calculate_c
        calculate.argtypes = (FloatPtr, cts.c_size_t, CharPtr, cts.c_size_t)
        calculate.restype = None
    
        evaluate = dll.evaluate_c
        evaluate.argtypes = (cts.c_char_p,)
        evaluate.restype = cts.c_float
    
        c = ord('A')
        print(f"\nprecedence: {precedence(c)}")
    
        print(f"\ncalc: {calc(0.9, -0.2, c)}")
    
        dim = 10
        vs = tuple(1 / i for i in range(1, dim + 1))
        cs = tuple(range(dim))
        print(f"\ncalculate\nops: {cs}\nvalues (initial): {vs}")
        v_arr = (cts.c_float * dim)(*vs)  # Create CTypes arrays from Python sequences
        c_arr = (cts.c_char * dim)(*cs)
        values = cts.cast(v_arr, FloatPtr)  # Cast arrays to pointers
        ops = cts.cast(c_arr, CharPtr)
        calculate(values, dim, ops, dim)
        print(f"values (final): {[values[i] for i in range(dim)]}")
    
        print(f"\nevaluate: {evaluate(b'20 chars long string')}")
    
    
    if __name__ == "__main__":
        print(
            "Python {:s} {:03d}bit on {:s}\n".format(
                " ".join(elem.strip() for elem in sys.version.split("\n")),
                64 if sys.maxsize > 0x100000000 else 32,
                sys.platform,
            )
        )
        rc = main(*sys.argv[1:])
        print("\nDone.\n")
        sys.exit(rc)
    

Output:

  • MSYS2 terminal:

    [cfati@cfati-5510-0:/e/Work/Dev/StackExchange/StackOverflow/q079506302]> ~/sopr.sh
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [064bit prompt]>
    [064bit prompt]> ls
    code00.py  dll00.cpp  dll00.hpp
    [064bit prompt]>
    [064bit prompt]> g++ -fPIC -shared -std=c++17 -o libdll00_msys.dll dll00.cpp
    [064bit prompt]>
    [064bit prompt]> ls
    code00.py  dll00.cpp  dll00.hpp  libdll00_msys.dll
    [064bit prompt]>
    [064bit prompt]> ldd ./libdll00_msys.dll
            ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7fff137f0000)
            KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7fff136c0000)
            KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7fff11030000)
            msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7fff12280000)
            msys-2.0.dll => /usr/bin/msys-2.0.dll (0x180040000)
            msys-gcc_s-seh-1.dll => /usr/bin/msys-gcc_s-seh-1.dll (0x5e8160000)
            msys-stdc++-6.dll => /usr/bin/msys-stdc++-6.dll (0x526840000)
            advapi32.dll => /c/WINDOWS/System32/advapi32.dll (0x7fff12930000)
            sechost.dll => /c/WINDOWS/System32/sechost.dll (0x7fff12170000)
            RPCRT4.dll => /c/WINDOWS/System32/RPCRT4.dll (0x7fff12660000)
            bcrypt.dll => /c/WINDOWS/System32/bcrypt.dll (0x7fff116c0000)
            CRYPTBASE.DLL => /c/WINDOWS/SYSTEM32/CRYPTBASE.DLL (0x7fff10750000)
            bcryptPrimitives.dll => /c/WINDOWS/System32/bcryptPrimitives.dll (0x7fff10f30000)
    

    As seen, the .dll depends on some MSYS2 .sos, which are not typically in (Win system) %PATH%, so they won't be available (from Cmd).

  • Cmd terminal:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079506302]> sopr.bat
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [prompt]>
    [prompt]> dir /b
    code00.py
    dll00.cpp
    dll00.hpp
    
    [prompt]>
    [prompt]> :: --- Build the .dll from a MSYS2 terminal ---
    [prompt]>
    [prompt]> dir /b
    code00.py
    dll00.cpp
    dll00.hpp
    libdll00_msys.dll
    
    [prompt]>
    [prompt]> :: Run normally
    [prompt]> python ./code00.py
    Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32
    
    Traceback (most recent call last):
      File "e:\Work\Dev\StackExchange\StackOverflow\q079506302\code00.py", line 65, in <module>
        rc = main(*sys.argv[1:])
      File "e:\Work\Dev\StackExchange\StackOverflow\q079506302\code00.py", line 20, in main
        dll = cts.CDLL(DLL_NAME)
      File "c:\Install\pc064\Python\Python\03.10\lib\ctypes\__init__.py", line 374, in __init__
        self._handle = _dlopen(self._name, mode)
    FileNotFoundError: Could not find module 'e:\Work\Dev\StackExchange\StackOverflow\q079506302\libdll00_msys.dll' (or one of its dependencies). Try using the full path with constructor syntax.
    
    [prompt]>
    [prompt]> :: Pass the MSYS2 .dlls path
    [prompt]> python ./code00.py f:\Install\pc064\MSYS2\MSYS2\Version\usr\bin
    Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32
    
    Add directory
    
    precedence: 65
    
    calc: 65.69999694824219
    
    calculate
    ops: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    values (initial): (1.0, 0.5, 0.3333333333333333, 0.25, 0.2, 0.16666666666666666, 0.14285714285714285, 0.125, 0.1111111111111111, 0.1)
    values (final): [1.0, 1.5, 2.3333332538604736, 3.25, 4.199999809265137, 5.166666507720947, 6.142857074737549, 7.125, 8.11111068725586, 9.100000381469727]
    
    evaluate: 10.0
    
    Done.
    
发布评论

评论列表(0)

  1. 暂无评论