I am trying to link a static library using node-gyp
in order to use it as a native node
addon. However, when I run node-gyp rebuild
I get the following linking error:
error LNK2001: unresolved external symbol "double __cdecl mylibengine::criticalZvalue(double)" (?criticalZvalue@mylibengine@@YANN@Z)
Which is immediately followed by:
C:\Users\Mihai\Desktop\msp-addon\build\Release\mylib-addon.node : fatal error LNK1120: 1 unresolved externals [C:\Users\Mihai\Desktop\mylib-addon\build\mylib-addon.vcxproj
The binding.gyp
looks like:
{
'targets': [{
'target_name': 'mylib-addon',
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
'include_dirs': [
'<!@(node -p \"require(\'node-addon-api\').include\")',
'<(module_root_dir)/dependencies/mylib/include/'
],
'sources': [
'src/MyLibNode.cpp'
],
'dependencies': [
'<!(node -p \"require(\'node-addon-api\').gyp\")'
],
'libraries': [
'<(module_root_dir)/dependencies/mylib/lib/x64/libmylib.a'
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
}]
}
The MyLibNode.cpp
looks like this:
#include <napi.h>
#include "engine.h"
Napi::Object InitAll(Napi::Env env, Napi::Object exports)
{
// Temporary check to make sure `libmylib.a` works.
mylibengine::criticalZvalue(.3);
return exports;
}
NODE_API_MODULE(mspaddon, InitAll)
I am sure that the linker can find libmylib.a
, because when I change the name of the library (e.g., to disabled.a
) I get a different error saying that the input file cannot be opened. However, it is unable to resolve the external symbol.
I found a similar, unanswered, question here. Answers to other questions indicate adding the full library path to libraries
, but I don't think that's the problem for my scenario.
Why can't node-gyp
resolve the external symbol?
Additional information:
g++
, as described belowI have the following project structure:
├───build
└───dependencies
└───mylib
├───include
└───lib
└───x64
dependencies/mylib/include
I have a header file called engine.h
which contains:#pragma once
namespace mylibengine
{
double criticalZvalue(double quantile);
}
dependencies/mylib/lib/x64
I have a static library named libmylib.a
main.cpp
which contains:#include <iostream>
#include <engine.h>
int main()
{
std::cout << "Main working." << "\n";
std::cout << mylibengine::criticalZvalue(.3) << "\n";
}
I can link the library in the executable as:
g++ -obuild/main main.cpp -Idependencies/mylib/include/ -Ldependencies/mylib/lib/x64/ -lmylib
At this point, running main.exe
will output just fine:
Main working.
-0.524002
In the question above, the static library libmylib.a
is compiled using the g++
from a mingw64
installation. However, node-gyp
uses the Microsoft C and C++ (MSVC) runtime libraries.
It seems (i.e., see this issue on GitHub) that node-gyp
does not support mingw64
. In the issue linked, someone indicates
mingw uses its own name mangling scheme that makes interoperability impossible.
which is also the issue encountered in this question (i.e., error LNK2001: unresolved external symbol
). The solution is to create the static library using the Microsoft toolchain and then the symbols will be correctly resolved by the linker.