Skip to main content

Maintaining shared library support

Node.js unofficially supports a build option where Node.js is built as a shared library. The shared library is called libnode with additional postfixes as appropriate for the platform (for example libnode.dll on windows). The shared library provides a way to embed Node.js into other applications and to have multiple applications use a single copy of Node.js instead of having to bundle in the full Node.js footprint into each application. For workloads that require multiple Node.js instances this can result in a significant footprint savings.

This document provides an outline of the approach and things to look out for when maintaining the shared library support.

Currently, shared library support has only been tested on:

  • Linux
  • macOS
  • Windows
  • AIX

Building with shared library option

On non-Windows platforms, Node.js is built with the shared library option by adding --shared to the configure step. On Windows platforms Node.js is built with the shared library option by adding dll to the vcbuild command line.

Once built there are two key components:

  • executable - node
  • library - libnode

The node executable is a thin wrapper around libnode which is generated so that we can run the standard Node.js test suite against the shared library.

The executable and library will have extensions as appropriate for the platform on which they are built. For example, node.exe on windows and node on other platforms for the executable.

libnode may have additional naming components, as an example in a build on macOS libnode.105.dylib. For non-windows platforms the additional naming components include the NODE_MODULE_VERSION and the appropriate postfix used for shared libraries on the platform.

In cases where an application links against the shared library it is up to the application developer to add options so that the shared library can be found by the application or to set the LIBPATH (AIX), LD_LIBRARY_PATH (Linux/Unix), etc. so that it is found at runtime.

For the node wrapper, on linux and macOS it is built so that it can find the shared library in one of the following:

  • the same directory as the node executable
  • ../lib with the expectation that the executable is installed in a bin directory at the same level as a lib directory in which the shared library is installed. This is where the default package that is build with the shared library option will place the executable and library.

For the node wrapper on windows it is built expecting that both the executable and shared library will be in the same directory as it common practice on that platform.

For the node wrapper on AIX, it is built with the path to the shared library hardcoded as that is the only option.

Exports

On windows, functions that may be linked from native addons or additional Node.js executables need to have NODE_EXTERN_PRIVATE or NODE_EXTERN otherwise they will not be exported by the shared library. In the case of functions used by additional Node.js executables (ex: mksnapshot) a missing NODE_EXTERN or NODE_EXTERN_PRIVATE will cause the build to fail. NODE_EXTERN_PRIVATE should be used in these cases unless the intent is to add the function to the public embedder API.

Native addons

For regular Node.js builds, running native addons relies on symbols exported by the node executable. As a result any pre-built binaries expect symbols to be exported from the executable instead of the shared library itself.

The node executable and shared library are built and linked so that the required symbols are exported from the node executable. This requires some extra work on some platforms and the process to build the node executable is a good example of how this can be achieved. Applications that use the shared library and want to support native addons should employ a similar technique.

Testing

There is currently no testing in the regular CI run for PRs. There are some CI jobs that can be used to test the shared library support and some are run as part of daily testing. These include:

TODO: add a Job for windows

For code that modifies/affects shared library support these CI jobs should run and it should be validated that there are no regressions in the test suite.