Reputation: 31186
I have been at this for hours. I have a simple hello-world .dll compiled using gcc on Cygwin with Clion.
I have a Python script running from an anaconda install (that is the interpreter) in Pycharm located in the Cygwin directory.
The .dll file name is "cygextension_test_c.dll."
I move the .dll to the python project directory, and run the following code, in various configurations listed below (all of which were various solutions in the last decade of questions asked on this topic that I could find this afternoon--I am working off of the following website for sending ndarrays to C code):
import numpy as N
from numpy.ctypeslib import load_library
from numpyctypes import c_ndarray
import ctypes
import os
print(ctypes.windll.kernel32);
mydll = load_library('cygextension_test_c.dll',r'C:\cygwin64\home\...\extension_test_c\cmake-build-debug');
mydll = ctypes.WinDLL(r'same path, essentially--this time pointing to working directory\cygextension_test_c.dll')
mydll = ctypes.CDLL(r'ditto')
mydll = ctypes.cdll.LoadLibrary('...')
mydll = ctypes.windl.LoadLibrary('...')
myarray = N.zeros((3,13),dtype=N.double)
c_myarray = c_ndarray(myarray,dtype=N.double,ndim=2)
I have also stepped through the code, and noticed that the path and file is getting accessed. If I change the path to be something incorrect (or the file name, etc.) I get a different error earlier in the chain. This somehow pertains to the .dll itself. However, virtually all the questions get the (apparently) same error I get, and it has nothing to do with the actual .dll in their cases. They just get magic solutions by switching up the way they import the .dll with ctypes.
So, once again, I am using a windows anaconda install (python 3.5) on pycharm in a Cygwin directory on a (obviously) windows computer. The c++ code is compiled using gcc in Clion with the following settings in the CMakeLists file (per the instructions in the link above):
cmake_minimum_required(VERSION 3.6)
project(extension_test_c)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -ansi -pedantic -Wall -pedantic -std=c++0x")
set(SOURCE_FILES extension_test_c.cpp extension_test_c.h ndarray.h)
add_library(extension_test_c SHARED ${SOURCE_FILES})
The code I compile in my extension_test_c.cpp
is just a function which prints out which numbers the stride array has in a 2-d numpy ndarray (this pertains to the code from the link), and the code in the header is even simpler; however, I have commented out std
lines, since I ran into another answer on one of the earlier questions pertaining to whether the library accesses other libraries (as that could cause ctypes imports to fail).
extension_test_c.cpp
#include "extension_test_c.h"
//#include <iostream>
#include "ndarray.h"
extern "C" {
int hello(numpyArray<double> array) {
Ndarray<double,2> a(array);
//std::cout << "shape 0: " << array.shape[0] << "; shape 1: " <<
// array.shape[1] << "; stride 0: " << array.strides[0]
// << "; strides 1: " << array.strides[1] << std::endl;
return 1;
}
}
And the header file:
#ifndef EXTENSION_TEST_C_LIBRARY_H
#define EXTENSION_TEST_C_LIBRARY_H
#include "ndarray.h"
extern "C" {
int hello(numpyArray<double> array);
}
#endif
ndarray.h
can be found at the link on the website above.
I have no idea what I could be doing wrong; am totally out of ideas. Here is the error for load_library
:
Traceback (most recent call last):
File "C:/cygwin64/home/chris/CygwinMachineLearning/Assignment 1/DecisionTree/extension_test_python/wrapper.py", line 9, in <module>
mydll = load_library('cygextension_test_c.dll',r'C:\cygwin64\home\chris\CygwinMachineLearning\Assignment 1\DecisionTree\extension_test_c\cmake-build-debug');
File "C:\Anaconda3\envs\tensorflow\lib\site-packages\numpy\ctypeslib.py", line 150, in load_library
return ctypes.cdll[libpath]
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 422, in __getitem__
return getattr(self, name)
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 417, in __getattr__
dll = self._dlltype(name)
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 347, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
The error for ctypes.CDLL(...)
:
Traceback (most recent call last):
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\pydevd.py", line 1596, in <module>
globals = debugger.run(setup['file'], None, None, is_module)
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\pydevd.py", line 974, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "C:/cygwin64/home/chris/CygwinMachineLearning/Assignment 1/DecisionTree/extension_test_python/wrapper.py", line 9, in <module>
mydll = ctypes.CDLL('cygextension_test_c.dll',r'C:\cygwin64\home\chris\CygwinMachineLearning\Assignment 1\DecisionTree\extension_test_c\cmake-build-debug');
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 347, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
And, for WinDLL
, it is the same.
For the cdll.LoadLibrary
version, it is pretty much the same (exact same final error) with different trace:
Traceback (most recent call last):
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\pydevd.py", line 1596, in <module>
globals = debugger.run(setup['file'], None, None, is_module)
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\pydevd.py", line 974, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "C:\Program Files (x86)\JetBrains\PyCharm 2016.3.2\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "C:/cygwin64/home/chris/CygwinMachineLearning/Assignment 1/DecisionTree/extension_test_python/wrapper.py", line 9, in <module>
mydll = ctypes.cdll.LoadLibrary(r'C:\cygwin64\home\chris\CygwinMachineLearning\Assignment 1\DecisionTree\extension_test_c\cmake-build-debug');
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 425, in LoadLibrary
return self._dlltype(name)
File "C:\Anaconda3\envs\tensorflow\lib\ctypes\__init__.py", line 347, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
Upvotes: 2
Views: 1804
Reputation: 66
After hours of trying the solution for me was to add '-static' to the gcc linker command. From the Gcc Link Options:
-static
On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other systems, this option has no effect.
The [WinError 126] suggests some dependent dll couldn't be found. The hint was when the same dll loaded on a different Windows system. Having WSL installed might make it work too but the static linking fixed it for the machine without WSL.
Upvotes: 1
Reputation: 779
For ctypes.CDLL the library should be without the .dll extension.
so
myDLL = ctypes.CDLL("myPath/MyDLL")
not
myDLL = ctypes.CDLL("myPath/MyDLL.dll")
Upvotes: 1