1

I am writing a nodejs addon that depends on OpenGL (glfw). It compiles successfully but when I try and use it in node I get the error The specified module could not be found.

This is the problematic part of the addon C++ code:

#include <glfw/glfw3.h>

if(glfwInit()) {
    printf("glfw init success");
}
else {
    printf("glfw init failed");
}

With this in the addon, it compiles but causes the error in node. Without this it compiles and runs without issue.

Here is my binding.gyp:

{
  "targets": [
    {
      "target_name": "engine",
      "sources": [
        "addon/addon.cc"
      ],
      "libraries": [
            "<(module_root_dir)/addon/lib/gl/glfw3dll.lib"
        ],
      "include_dirs": [
        "addon/lib",
        "<!@(node -p \"require('node-addon-api').include\")"
      ],
      'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
    }
  ]
}

And the addon file structure:

addon
  lib
    glfw
      glfw3.dll
      glfw3.h
      glfw3.lib
      glfw3dll.lib
      glfw3native.h
      opengl32.lib
  addon.cc

Edit: New binding.gyp:

{
  "targets": [
    {
      "target_name": "engine",
      "sources": [
        "addon/addon.cc"
      ],
      "libraries": [
        "-lglfw3dll",
        "-lopengl32",
        "-L<module_root_dir)/lib/glfw",
        "-Wl,-rpath,\$$ORIGIN/../../lib",
        ],
      "include_dirs": [
        "addon/lib",
        '<!@(node -p "require(\'node-addon-api\').include")'
      ],
      'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
    }
  ]
}
chrispytoes
  • 1,714
  • 1
  • 20
  • 53
  • how do you try to use it in node? – bmacnaughton Dec 02 '19 at 02:25
  • @bmacnaughton Just as an addon module, with `const engine = require('bindings')('engine');`. It works without including any external libraries. – chrispytoes Dec 02 '19 at 03:21
  • is the file there or not? `ls -R build` in the package root directory? – bmacnaughton Dec 02 '19 at 15:55
  • @bmacnaughton Sorry, I probably should have clarified. I am not having trouble getting an addon to run. I got the addon compiling and running. It only started breaking when I added OpenGL. – chrispytoes Dec 02 '19 at 15:59
  • it can be a bit tricky to get a library loaded from a local location. i'll try to provide an example as an answer - it might or might not solve your issue. but i'm presuming it is only once you tried loading `glfw3dll.lib` that it started failing. – bmacnaughton Dec 02 '19 at 16:09
  • Does this answer your question? [Error: The specified module could not be found](https://stackoverflow.com/questions/41253450/error-the-specified-module-could-not-be-found) – Константин Ван Dec 12 '22 at 15:47

3 Answers3

0

I'm not sure this is your issue but it can be a bit tricky to convince the loader to load a specific library in a local directory. I added this section to my the targets array in binding.gyp.

The trick is to tell the linker look for the library relative to $ORIGIN(where the addon is). Because the addon is in build/Release then $ORIGIN is build/Release and ../../ gets you back to the module root.

It just took trial and error to find the right way to specify $ORIGIN via binding.gyp and the linker's quoting rules. \$$ORIGIN resulted in $ORIGIN being embedded in the node addon.

'conditions': [
    ['OS in "linux"', {
    # includes reference glfw3dll/glfw3dll.h, so
    'include_dirs': [
      '<!@(node -p "require(\'node-addon-api\').include")',
        '<(module_root_dir)/'
    ],
    'libraries': [
        '-lglfw3dll',
        '-L<(module_root_dir)/dir-for-glfw3dll/',
        '-Wl,-rpath-link,<(module_root_dir)/dir-for-glfw3dll/',
        '-Wl,-rpath,\$$ORIGIN/../../dir-for-glfw3dll/'
    ],
    }]
]

(I changed the name of my file to your file and put it in a directory directly under the module_root_dir.)

bmacnaughton
  • 4,950
  • 3
  • 27
  • 36
  • I posted my new binding.gyp according to my project structure, not sure if it's entirely correct. I get the error: `cannot open file 'glfw3dll.lib'` at build time. I also tried it with `-lglfw3` instead and I get the same thing. – chrispytoes Dec 03 '19 at 03:14
  • maybe `"-Wl,-rpath,\$$ORIGIN/../../lib"` should be `"-Wl,-rpath,\$$ORIGIN/../../lib/glfw"`. and make sure your module structure is /build/Release/engine.node – bmacnaughton Dec 03 '19 at 12:31
  • Still the same error, and `engine.node` was in that folder but it's failing at build time now so it's not there. – chrispytoes Dec 04 '19 at 00:10
  • sorry it didn't fix it. but if it's failing at build time then *what* is not there? – bmacnaughton Dec 05 '19 at 04:24
0

I managed to get it working with this binding.gyp file:

{
  "targets": [
    {
      "target_name": "engine",
      "sources": [
        "addon/addon.cc"
      ],
      "libraries": [
        "legacy_stdio_definitions.lib",
        "msvcrt.lib",
        "msvcmrt.lib",
        "<(module_root_dir)/addon/lib/glfw/opengl32.lib",
        "<(module_root_dir)/addon/lib/glfw/glfw3.lib"
        ],
      "include_dirs": [
        "addon/lib",
        '<!@(node -p "require(\'node-addon-api\').include")',
      ],
      'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
    }
  ]
}
chrispytoes
  • 1,714
  • 1
  • 20
  • 53
0

Just in case someone else has the same issue and ends up here. The libraries that are required by the addon needs to be within reach on runtime, even if the linker managed to find it.

For example if this is on Windows, and you linked with foo.lib during your build/link, during runtime, foo.dll should be either in the same folder (for me it worked in the same folder as .node) or in a folder in the path. Otherwise it wont be loaded and this error will be thrown. Very unexplanatory error in my opinion.

Also, keeping the libraries in the same folder as the .node helps with segregating the different arch builds & dependancies (x86, x64 etc).