Search code examples
pythonc++interopiostream

When Importing a dll to python using ctypes, istream and ostream can be found, but not iostream. Why?


When Importing c.dll to python using ctypes, and iostream has been included in a.cpp, I encounter the following error:

Could not find module 'C:\Test\foo.dll' (or one of its dependencies). 
Try using the full path with constructor syntax.

As explained at bugs.python.org this is an ambiguous error, indicative of a deeper issue.

A few quick notes to be thorough:

  • the path is correct and using exists(path) reveals as much.
  • istream, ostream, and cmath all link without issue.
  • Looking at the contents of iostream, the only file that iostream includes other than istream and ostream is bits/c++config.h. However, cmath also includes bits/c++config.h and I am still able to load the .dll in python with cmath included.
  • I am using Windows 10 x64, ample storage space, relatively new m.2 drive with no reported errors.
  • Python version is 3.10.8
  • I have tried switching c++ standards (tried all of them) and recompiling.
  • I have tried linking using the method and flags recommended here.
  • I have tried using extern "C"__declspec(dllexport) instead of extern "C"
  • I am compiling using g++ from mingw64
  • Dependency walker shows nearly 100 missing dependencies, which doesnt make to me, given that it compiles and runs without iostream.

The contents of my files for reproduction is as follows:

a.cpp

#include <ostream>
extern "C" void Print()
{
    printf("Hello!");
}

b.py

from ctypes import *

core = cdll.LoadLibrary("C:/Test/c.dll")
core.Print()

makefile

main:
    g++ -shared -o .c.dll .a.cpp
    python3 -B b.py

If I compile this using make it works perfectly, as it should.

However, if I change a.cpp to the following and compile, I receive the above noted error:

a.cpp

#include <iostream>
extern "C" void Print()
{
    printf("Hello!");
}

As far as I can tell, the linker cannot find a dependency that I cannot see in the mingw64 version of iostream, but that is as much as I can discern.

Does anyone else encounter this error using the above files? Any thoughts?


Solution

  • at this moment for python 3.10 the solution for this is to statically link against both libgcc and libstdc++ (or copy them from mingw/bin folder to your dll folder), this doesn't seem to be the case for versions of python prior to 3.10

    g++ -shared -o c.dll a.cpp -static-libstdc++ -static-libgcc
    

    it seems like python 3.10 currently doesn't look for those dlls in your PATH.

    Edit: according to this stack overflow answer, you have to add the dlls path manually using os.add_dll_directory, alternatively you can use CDLL winmode parameter to allow windows to search for dlls in your PATH, but it is discouraged, and linking them statically is the best solution to run the dll on systems that don't have mingw installed or on PATH.

    core = CDLL(r"c.dll",winmode=0x8)