Pybind11: How do I truly fix missing DLL error?

61 Views Asked by At

So I was trying to learn Pybind11 with a simple project, but like always, something went wrong and I ran into this error when trying to import the module itself though the Python Shell or File.

ImportError: DLL load failed while importing test_module: The specified module could not be found.

The pybind Module itself includes a function that prints "Hello World".

#include <iostream>
#include <pybind11/pybind11.h>


void sayHello() {
  std::cout << "Hello World!\n"; 
}


PYBIND11_MODULE(test_module, m) {
  m.doc() = "This is momumental!";
  m.def("sayHello", &sayHello, "Function that prints Hello World");
}

The CMake file work without problems as well.

cmake_minimum_required(VERSION 3.10)
project("test_module")

set(EXECUTABLE_OUTPUT_PATH "../")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_subdirectory(".extern/pybind11")

pybind11_add_module("test_module" main.cpp)
target_compile_options("test_module" PRIVATE "-static-libgcc" "-static-libstdc++")

At the time, I didn't know what to do and was frustrated as I had to deal with another "black box" situation again. I've posted the project on github if you want to take a closer look on how the code is structured. https://github.com/ProarchwasTaken/pybind_test

What I tried.

After some angry searching one the internet I figured out one way I could fix the issue. It was thanks to this thread in the pybind repo: https://github.com/pybind/pybind11/issues/2010

Judging from the thread, apparently the error means that some DLLs which my pybind module needs are missing, and the way I could fix it is add the path to the DLLs that my module was missing.

>>> import os
>>> os.add_dll_directory("C:\\MinGW\\bin") # The path where DLLs the customized pybind module needs are locating.
<AddedDllDirectory('C:\\MinGW\\bin')>
>>> import example
>>> example.add(1, 2)
3

I tried doing this in the Python Shell, and it worked... I played around for a bit by setting up a small package with a init.py file, and created a stub file so my LSP and Type Checker would know the function exists and not complain.

The Main Issue.

While the solution does work, there's still one problem. It's not really portable. While my DLL directory is located at: "C:/msys64/mingw64/bin", not everyone is gonna have their's located at the same place. Yet alone even have mingw64.

The module would only work for my computer. What if I want to distribute what I'm making? If anyone else wants to use it, they would have to edit the code themselves for download something they wouldn't want to.

The only way I could see of fixing the issue is finding the DLLs the module is missing, and statically link them to the module binary itself. That way, no one has to deal with the add_dll_directory nonsense.

I tried tracking down what DLLs could be missing by using a dependency walker, but the only clue I could find on what it could be is: "ext-ms-win-oobe-query-l1-1-0.dll". However I think that clue is irrelevant as the module imports just fine when I added the DLL directory in test.py. So I could only deduce that whatever DLL the module was missing is in that directory.

Like I said, I'm frustrated that I seem to be the one of the only people who seem to be having this issue. I was wondering if any of y'all had a solution to my problem.

1

There are 1 best solutions below

0
Tyler On

Okay everybody, I've found the solution to my problem! Apparently, the DLL file that the module needs was "libwinpthread-1.dll". Once I knew that, all I had to do is statically link it in the cmake file. Although, just to be safe, you may want to also link "static-libgcc" and "static-libstdc++".

target_link_libraries("test_module" PRIVATE -static -lpthread -static-libgcc -static-libstdc++)

Once I did that, and compiled the module file, I was able to import the module without needing to use "os.add_dll_directory"! Finally I could move on to something else!