Cannot link nodeJS native C++ addon to OpenSSL statically bound with node (0.10.18) when building with node-gyp

StackOverflow https://stackoverflow.com/questions/18908619

Question

I have read this: https://github.com/TooTallNate/node-gyp/wiki/Linking-to-OpenSSL, but for some reason it does not work for me. I am getting "undefined symbol: SHA1" when trying to require the addon from node. Here's my code (src/sha_export.cc):

#include <node.h>
#include <node_buffer.h>
#include <v8.h>

#include <openssl/sha.h>

using namespace v8;

Handle<Value> Sha1(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  unsigned char*msg = (unsigned char*) node::Buffer::Data(args[0]->ToObject());
  size_t msglen = node::Buffer::Length(args[0]->ToObject());
  unsigned char dgst[20];

  SHA1(msg, msglen, dgst);

  return scope.Close(node::Buffer::New((const char*)dgst, 20)->handle_);
}

void init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("sha1"),
    FunctionTemplate::New(Sha1)->GetFunction());
}

NODE_MODULE(token, init)

and here's the binding.gyp:

{
  'targets': [
    {
       "target_name": "token"
     , "sources": [ "src/sha_export.cc" ]
     ,'conditions': [
        ['node_shared_openssl=="false"', {
          # so when "node_shared_openssl" is "false", then OpenSSL has been
          # bundled into the node executable. So we need to include the same
          # header files that were used when building node.
          'include_dirs': [
            '<(node_root_dir)/deps/openssl/openssl/include'
          ],
          "conditions" : [
            ["target_arch=='ia32'", {
              "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
            }],
            ["target_arch=='x64'", {
              "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
            }],
            ["target_arch=='arm'", {
              "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
            }]
          ]
        }]
      ]
    }
  ]
}

I checked that I have node_shared_openssl set to false in config.gypi, and even put an #error in sha.h in /deps/openssl to make sure it is included. However, I'm still getting "undefined symbol: SHA1" when requiring the addon, obviously meaning that linking to the bundled OpenSSL didn't work. If I add

     , 'link_settings': {
          'libraries': [
              '-lcrypto'
          ]
      }

after sources, everything works, but then ldd token.node shows libcrypto.so.1.0.0 => /lib/i386-linux-gnu/libcrypto.so.1.0.0 (0xb7525000) which means that I am linking to the shared dynamic OpenSSL instead now. So my question is: is it at all possible to link to the OpenSSL statically bundled with node? What am I doing wrong then?

Thank you very much!

PS Just in case it's important: the OS is Ubuntu 12.04 LTS

Was it helpful?

Solution

Well, answering my own question... Got some help from Ben Noordhuison on node.js IRC. Thanks a lot Ben!

Apparently, there is a limited number of OpenSSL routines exposed by the node executable, basically, only the ones node uses itself, and in my case that did not include the higher level SHA1 function, but it does include the lower level ones: SHA1_Init, SHA1_Update, and SHA1_Final. Changed my code to look like

SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, msg, msglen);
SHA1_Final(dgst, &ctx);

instead of just SHA1(msg, msglen, dgst); and it works fine without external dependencies.

According to Ben, there could also be some issues with linking to static OpenSSL on Windows: cannot comment on this, using Linux only.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top