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

Can not bind GDNative compiled with CMakeLists in 3.3 and 3.x via Mingw-w64 (Windows)

Open Banderi opened this issue 3 years ago • 1 comments

Repo branch: 3.3 (and a few others) Godot version: 3.3.stable

After lots of trial and errors, comparing multiple guides, docs, tutorials, different versions, different toolchains and different C++ standards I managed to make godot-cpp compile and generate the required files & bindings on Windows with the 3.3 (and some others) branches by using the included CMakeLists.txt instead of SCons, and the linked commits of godot-headers; the GDNative project also compiles successfully, and generates a .dll. However, no matter what I try, trying to bind the dll in Godot results in the extremely obnoxious Windows "Error 126" which doesn't give back any kind of hint as to why.

This is the error as appears in one of my projects, https://github.com/Banderi/EMWaves/tree/master/CLionCPP and compiled on CLion with Mingw-w64 9.0/GCC 11.2.0 on C++14:

ERROR: Can't open dynamic library: E:/Godot/Projects/EMWaves/Godot/gdnative_cpp/windows/libwavescpp.dll, error: Error 126: The specified module could not be found.

.
   At: platform/windows/os_windows.cpp:2425
ERROR: get_symbol: No valid library handle, can't get symbol from GDNative object
   At: modules/gdnative/gdnative.cpp:502
ERROR: init_library: No nativescript_init in "res://gdnative_cpp/windows/libwavescpp.dll" found
   At: modules/gdnative/nativescript/nativescript.cpp:1479

This error is extremely deceiving and frustrating because it's a generic error message that Windows throws when the .dll fails to load, NOT (necessarily) because the file is not found; it appears many many times over various threads on Discord, Reddit, Github, the forums etc. and it's incredibly rare to find a solution for it because it can happen for a multitude of different reasons. (e,g, https://github.com/godotengine/godot-cpp/issues/540 https://github.com/godotengine/godot-cpp/issues/403 https://github.com/godotengine/godot-cpp/issues/232 https://github.com/godotengine/godot-cpp/issues/14)

Here's what I made 100% sure of, in my project's case:

  • The files and folder structures are correct All the files, the folders, the paths and file permissions have been quadruple checked and there's no issues with spaces, capitals, slashes etc. anywhere that I can see; the C99 GDNative ones in my repo also work fine.
  • The .gdns and .gdnlib files are all set up correctly I've taken the files as have been presented from the sample files and just changed the details inside. I've also tried making new ones from inside Godot, to the same results; the C99 GDNative ones work correctly.
  • The Godot project's code (gdscript) for setting up GDNative is correct I've used the same code as the sample files, as well as my own from https://github.com/Banderi/GDNativeExample to the same effect. The C99 GDNative version works correctly, but the others do not. The error is the exact same that appears all the time as I mentioned in that repo's Readme, which is gdscript failing on the <library res here>.new() line with Attempt to call function 'new' in base 'NativeScript' on a null instance. error -- this is the gdscript equivalent of the abovementioned Error 126: The specified module could not be found. message; it appears when the .dll fails to load, under any circumstance, without a way to get any more clues about it.
  • There is no issue with the binds naming, the Class Name or the symbol prefix The nativescript_init error above is another huge misdirect, as the issue has nothing to do with the init function being not found, invalid, etc. To confirm this, here's the actual error that appears when the init function export is missing, incorrect, or the symbol lookup fails (e.g. if the symbol prefix is incorrect):
    RROR: Can't resolve symbol godot_gdnative_init, error: 127.
      At: platform/windows/os_windows.cpp:2445
    RROR: initialize: Failed to obtain godot_gdnative_init symbol
      At: modules/gdnative/gdnative.cpp:361
    RROR: get_symbol: No valid library handle, can't get symbol from GDNative object
      At: modules/gdnative/gdnative.cpp:502
    RROR: init_library: No nativescript_init in "res://gdnative_cpp/windows/libwavescpp.dll" found
      At: modules/gdnative/nativescript/nativescript.cpp:1479
    
  • The GDNative code is correct I've used the exact same code of the sample files, as well my own to see if something went wrong or the example code was outdated, to no avail. Some other misc/useful information from testing things:
    • The Godot app stops when reaching the error if ran from the Godot editor, but if ran from inside the C++ IDE (CLion) it just continues as normal so long as the GDNative library isn't further used in scripts.
    • 3.x fails only when the API calls inside the init exports such as Godot::gdnative_init(o); or Godot::gdnative_terminate(o); are present, while 3.3 branch fails as soon as either #include <Godot.hpp> or #include <Reference.hpp> are present. Even if the godot-cpp generated libs (libgodot-cpp.windows.release.64.a) aren't linked inside the 3.3 .dll, it will fail.
    • In 3.x, if the init exports are correct but empty (no API calls in the code) the library will bind correctly without the Error 126, but gdscript will still throw the Attempt to call function 'new' in base 'NativeScript' on a null instance. and fail as normal.
    • Compiling in debug or release mode, as well as compiling the bindings with or without the -g flag under GODOT_COMPILE_FLAGS doesn't have any effect.
    • Mingw-w64 6.00/GCC 8.1.0 fails to compile either godot-cpp or the GDNative project.
    • I've heard some people say using the MSVC toolchain fixed similar issues, unfortunately I do not have Visual Studio and couldn't make the VSBuildTools work with CLion... yet.
    • Using different C++ standards (e.g. C++17 or C++20) made no difference.
    • The example from https://github.com/BastiaanOlij/gdnative_cpp_example also fails in the same manner as 3.x.
    • The 3.3-stable branch from May (https://github.com/godotengine/godot-cpp/tree/godot-3.3-stable) behaves exactly as 3.3, however it initially fails to compile in CMake due to forward slashes. I temporarily fixed it on my end by using:
      et(SOURCES_FILE_LIST_GOOD )
      et(HEADERS_FILE_LIST_GOOD )
      
       file(TO_CMAKE_PATH "${SOURCES_FILE_LIST}" SOURCES_FILE_LIST_GOOD)
       file(TO_CMAKE_PATH "${HEADERS_FILE_LIST}" HEADERS_FILE_LIST_GOOD)
      
       # Define our godot-cpp library
       add_library(${PROJECT_NAME}
            ${SOURCES}
            ${SOURCES_FILE_LIST_GOOD}
            ${HEADERS}
            ${HEADERS_FILE_LIST_GOOD}
       )
      

As I notice 3.x is the closest to being working, I suppose that's the one I should focus on if there's anything else to try. Here's my full project with all the files: https://github.com/Banderi/EMWaves It contains both the C++ attempts (CLionCPP) and a plain C one (CLion) which loads and works as intended.

Just to be safe, here's the steps I took to build the repos & libraries:

  • Download godot-cpp of the branch selected in the dropdown menu as well as the linked godot-headers
  • Put the godot-headers files inside the predisposed "godot-headers" folder in the root
  • Removed the -g flag from GODOT_COMPILE_FLAGS to reduce the library size
  • Generated the C++ bindings and compiled the godot-cpp repo successfully with Mingw-w64 9.0/GCC 11.2.0
  • Created a new C++ GDNative project in CLion, added the following folders to the inclusions:
    • <godot-cpp repo>/include/core --> <gdnative project>/include/core
    • <godot-cpp repo>/cmake-build-release/include/gen --> <gdnative project>/include/gen
    • <godot-cpp repo>/godot-headers --> <gdnative project>/include/godot-headers
    • as well as the root <gdnative project>/include/ in the list of inclusions
  • Linked the GDNative project against the previously generated static lib (libgodot-cpp.windows.release.64.a)
  • Compiled the GDNative project successfully with Mingw-w64 9.0/GCC 11.2.0 into a .dll file
  • Pointed the .gdns/.gdnlib boilerplates to resulting .dll
  • Loaded up the files in gdscript

Also I partially followed this handy guide: https://aleksandrbazhin.github.io/godot/2021/06/25/GDNative-cpp-in-2k21.html

Any clue as to what could be the cause of all these issues? Maybe I made some obvious, dumb mistake in the above steps, but I genuinely wouldn't know. As far as I can tell, the libraries all compile correctly... that's the extent of my knowledge.

Banderi avatar Dec 23 '21 14:12 Banderi

I am in a similar shoes. I would like to use a GDNative module compiled by GCC of MingGW, but the DLL fails to load. When compiling with MSVC, it loads successfully. I am using Godot v3.4.2.stable.official [25eaa2daf] with godot-cpp godot-3.4.2-stable and godot-headers godot-3.4.2-stable.

The error message in Godot is the following:

E 0:00:00.635   open_dynamic_library: Can't open dynamic library: C:/Users/pinting/Dropbox/ipc-test/godot-integration/project/gdnative/windows.mingw64/msys-gdrackclient.dll, error: Error 126: The specified module could not be found.
.
  <C++ Error>   Condition "!p_library_handle" is true. Returned: ERR_CANT_OPEN
  <C++ Source>  platform/windows/os_windows.cpp:2353 @ open_dynamic_library()

Both DLL have the following export functions, but the MingGW one have a bunch of others too (see the attached MINGW64 build export functions.txt file).

godot_gdnative_init
godot_gdnative_terminate
godot_nativescript_init

Google Drive link with the built DLLs

SConstruct of the top module.txt SConstruct of the godot-cpp submodule.txt Installed packages.txt MINGW64 build export functions.txt MSVC build export functions.txt

pinting avatar Feb 17 '22 16:02 pinting

Closing as fixed in 3.5 via godotengine/godot#62173 . Please leave a comment if you are still encountering this issue after updating godot-cpp to the latest 3.5 branch so we can reopen it in case.

Faless avatar Jan 12 '23 12:01 Faless