godot-cpp icon indicating copy to clipboard operation
godot-cpp copied to clipboard

Usage of included functions resulting in `.dll` not being found

Open S3B4S opened this issue 5 years ago • 4 comments

The issue

Hey, I hope I'm in the right place with this, I've followed the example in the docs for c++: https://docs.godotengine.org/en/stable/tutorials/plugins/gdnative/gdnative-cpp-example.html. This went all right, my next step was to include opencv, so I modified SConstruct to look as following:

# make sure our binding library is properly includes
env.Append(CPPPATH=[
    # cpp bindings
    '.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/',
    # opencv library
    OPENCV_DIR + "../../include/"
])
env.Append(LIBPATH=[
    # cpp bindings
    cpp_bindings_path + 'bin/',
    # opencv library
    OPENCV_DIR + "lib/"
])
env.Append(LIBS=[cpp_library, "opencv_world430d"]) # Have to omit ".lib", it gets appended in runtime

When my code only includes the opencv libraries, it will compile and run fine in Godot;

// This will run fine
 
#include "gdexample.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
 
using namespace godot;
using namespace cv;
 
void GDExample::_register_methods() { ... }
 
GDExample::GDExample() { ... }
 
GDExample::~GDExample() { ... }
 
void GDExample::_init() {
    // initialize any variables here
    time_passed = 0.0;
    time_emit = 0.0;
    amplitude = 10.0;
 
    // Mat image = Mat::zeros(300, 600, CV_8UC3);
}

// other unrelated code

But when I do want to use a method from the imported code (so it's the exact same code snippet as above, but the Mat image = Mat::zeros(300, 600, CV_8UC3); line is uncommented), I run into the following error:

ERROR: get_symbol: No valid library handle, can't get symbol from GDNative object
   At: modules/gdnative/gdnative.cpp:483
debugger-agent: Unable to listen on 7020
ERROR: terminate: No valid library handle, can't terminate GDNative object
   At: modules/gdnative/gdnative.cpp:388
ERROR: _update_placeholder: Condition "!script_data" is true.
   At: modules/gdnative/nativescript/nativescript.cpp:92
Running: D:\Program Files (x86)\Godot\Godot_v3.2.1-stable_mono_win64.exe --path C:/Users/kevin/Development/contextproject/Godot --remote-debug 127.0.0.1:6007 --allow_focus_steal_pid 9776 --position 768,420
Godot Engine v3.2.1.stable.mono.official - https://godotengine.org
OpenGL ES 3.0 Renderer: AMD Radeon RX 5700 XT

Mono: Logfile is: C:\Users\kevin\AppData\Roaming/Godot/mono/mono_logs/2020_05_10 21.36.40 (14996).txt
ERROR: Can't open dynamic library: C:/Users/kevin/Development/contextproject/Godot/bin/win64/libgdexample.dll, error: Error 126: The specified module could not be found.
.
   At: platform/windows/os_windows.cpp:2269
ERROR: get_symbol: No valid library handle, can't get symbol from GDNative object
   At: modules/gdnative/gdnative.cpp:483
ERROR: init_library: No nativescript_init in "res://bin/win64/libgdexample.dll" found
   At: modules/gdnative/nativescript/nativescript.cpp:1506

I'm honestly confused by the fact that it's saying it cannot find libgdexample.dll anymore, whereas all of that would be fine if I were to not use the line Mat image = Mat::zeros(300, 600, CV_8UC3);. The file does exist on the disk in the right place.

I'm new to this kind of stuff, so I'm not sure if I've overlooked something or that this is unexpected behaviour.


Additional information in case it's needed

Here's the full SConstruct. Here's my .gdns file:

[gd_resource type="NativeScript" load_steps=2 format=2]

[ext_resource path="res://bin/gdexample.gdnlib" type="GDNativeLibrary" id=1]

[resource]
resource_name = "gdexample"
class_name = "GDExample"
library = ExtResource( 1 )

Here's my .gdnlib file:

[general]

singleton=false
load_once=true
symbol_prefix="godot_"
reloadable=false

[entry]

X11.64="res://bin/x11/libgdexample.so"
Windows.64="res://bin/win64/libgdexample.dll"
OSX.64="res://bin/osx/libgdexample.dylib"

[dependencies]

X11.64=[  ]
Windows.64=[  ]
OSX.64=[  ]

The project setup is almost identical to what can be found here: https://github.com/BastiaanOlij/gdnative_cpp_example.

S3B4S avatar May 10 '20 19:05 S3B4S

Some more information as I had 2 teammates reproduce the error, one is on MacOS, the other is on Windows. The person on MacOS is not able to reproduce the error, they follow the same steps I did and it's successfully working for them. They've also cloned the project that I was working on and that is also still working for them. The other person on Windows does run into the same error that I do. So I'm starting to think it might have to with either the environment or build tools.

So some information regarding this environment;

  • I've been using the terminal of Visual Studio Community 2019 to run scons platform=windows. Setting the environment to x64.
  • Using SCons 3.1.2
  • Using OpenCV 4.3.0

S3B4S avatar May 14 '20 09:05 S3B4S

By now I've attempted to do this with CMake, but that unfortunately results in the exact same issue as described above.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1...3.15)

if(${CMAKE_VERSION} VERSION_LESS 3.12)
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()

# set the project name
project(TouchThaBomb  VERSION 0.1
                      DESCRIPTION "Defuse bomb game with hand tracking"
                      LANGUAGES CXX)


# https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure 
find_package(OpenCV 4.3 EXACT REQUIRED PATHS /OpenCV/opencv-4.3.0-vc16/)
include_directories(AFTER "${OpenCV_INCLUDE_DIRS}" "include")
link_libraries(${OpenCV_LIBS})

link_libraries("../godot-cpp/bin/libgodot-cpp.windows.debug.64")

# create the .dll
#file(GLOB source_list "src/*.h" "src/*.cpp")
add_library(libgdexample SHARED "../src/gdexample.cpp" "../src/gdlibrary.cpp")

include_directories(
  "../godot-cpp/godot_headers/"
  "../godot-cpp/include/"
  "../godot-cpp/include/core/"
  "../godot-cpp/include/gen/"
  "../godot-cpp/bin/"
)

When my code only includes the opencv libraries, it will compile and run fine in Godot; But when I do want to use a method from the imported code (so it's the exact same code snippet as above, but the Mat image = Mat::zeros(300, 600, CV_8UC3); line is uncommented), I run into the following error:

Remains the exact same, the error is as follows:

ERROR: Can't open dynamic library: C:/Users/kevin/Development/contextproject/Godot/bin/win64/libgdexample.dll, error: Error 126: The specified module could not be found.
.
   At: platform/windows/os_windows.cpp:2269
ERROR: get_symbol: No valid library handle, can't get symbol from GDNative object
   At: modules/gdnative/gdnative.cpp:483
ERROR: init_library: No nativescript_init in "res://bin/win64/libgdexample.dll" found
   At: modules/gdnative/nativescript/nativescript.cpp:1506
ERROR: _update_placeholder: Condition "!script_data" is true.
   At: modules/gdnative/nativescript/nativescript.cpp:92
ERROR: _update_placeholder: Condition "!script_data" is true.
   At: modules/gdnative/nativescript/nativescript.cpp:92
Running: D:\Program Files (x86)\Godot\Godot_v3.2.1-stable_mono_win64.exe --path C:/Users/kevin/Development/contextproject/Godot --remote-debug 127.0.0.1:6007 --allow_focus_steal_pid 5300 --position 768,420
Godot Engine v3.2.1.stable.mono.official - https://godotengine.org
OpenGL ES 3.0 Renderer: AMD Radeon RX 5700 XT

Mono: Logfile is: C:\Users\kevin\AppData\Roaming/Godot/mono/mono_logs/2020_05_18 19.09.43 (9464).txt
ERROR: Can't open dynamic library: C:/Users/kevin/Development/contextproject/Godot/bin/win64/libgdexample.dll, error: Error 126: The specified module could not be found.
.
   At: platform/windows/os_windows.cpp:2269
ERROR: get_symbol: No valid library handle, can't get symbol from GDNative object
   At: modules/gdnative/gdnative.cpp:483
ERROR: init_library: No nativescript_init in "res://bin/win64/libgdexample.dll" found
   At: modules/gdnative/nativescript/nativescript.cpp:1506

S3B4S avatar May 18 '20 17:05 S3B4S


TL;DR:

Windows may not be finding one of the dependencies of libgdexample.dll (I assume opencv_world430d.dll).

Try putting opencv_world430d.dll in the same directory as your project.godot file or exported .exe file.


Prologue

On GitHub, the pre-rendered text of the command output you included gets truncated in such a way that it's not obvious that there's some important included output not visible.

At first glance only this text is visible:

ERROR: Can't open dynamic library: C:/Users/kevin/Development/contextproject/Godot/bin/
.

But the full width of the output is actually:

ERROR: Can't open dynamic library: C:/Users/kevin/Development/contextproject/Godot/
bin/win64/libgdexample.dll, error: Error 126: The specified module could not be found.
.

Exactly what could not be found?

The key text seems to be "The specified module..." because we're probably assuming "the specified module" refers to the just listed libgdexample.dll but that may not be the case...

A web search for "LoadLibraryExW" "Error 126: The specified module could not be found." returned these potentially helpful results:

(Aside: How did I know to include LoadLibraryExW as a search term? Well, one of my many hobbies includes reading Godot's cross-platform dynamic library loading code :D and I noticed the reference in the error message to the error message originating at platform/windows/os_windows.cpp:2269 which is where we find the reference to our new and dear friend LoadLibraryExW:

p_library_handle = (void *)LoadLibraryExW(path.c_str(), NULL, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + ".");

)

A potential solution

From reading the posts linked above it seems like Windows may not be finding opencv_world430d.dll where it expects and/or searches for it. It seems there's a variety of approaches to solving the issue.

But after reading the entire OS_Windows::open_dynamic_library() method I'm going to guess that (depending on your Windows version) you can probably start with putting the opencv_world430d.dll file in the base "executable" directory--now, where's that?

If you've exported your Godot project, that'll be next to the .exe file[1]--if you haven't exported your project I think it'll be the directory with your project.godot file in it.

[1] Note: Based on your .gdnlib file listed earlier you'll also need to add opencv_world430d.dll to the [dependencies] section to be included in the export.

If that doesn't work you could try one of the other options suggested in the Stack Overflow links above.

An alternate troubleshooting approach

If the "Google & Hope" troubleshooting approach hadn't worked, I'd probably have suggested trying a tool that logs all the file accesses that occur so you could see exactly what filepath Windows was looking for--there were some tools from SysInternals, I think, but they might be official tools by now.

follower avatar Jun 09 '20 14:06 follower

I can confirm "Move all the .dll to the base project dir" works! I simply move all the .dll files to the same location with the project.godot file. This is somewhat messy, since I have to mention that im using a third party library, and its dlls are mixed up with mine. Nevertheless, after nearly 3 days of getting this error and scratching my head I found this issue, and "follower" above fixed it. Thanks!

3ddelano avatar Jan 10 '22 03:01 3ddelano