diff --git a/doc/contributing/maintaining-shared-library-support.md b/doc/contributing/maintaining-shared-library-support.md new file mode 100644 index 00000000000000..45d0bc279673f0 --- /dev/null +++ b/doc/contributing/maintaining-shared-library-support.md @@ -0,0 +1,117 @@ +# 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 platoforms, Node.js is built with the shared library +option by adding `--shared` to the configure step. On Windows +platofrms 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: + +* [node-test-commit-linux-as-shared-lib](https://ci.nodejs.org/view/Node.js%20Daily/job/node-test-commit-linux-as-shared-lib/) +* +* [node-test-commit-aix-shared-lib](https://ci.nodejs.org/view/Node.js%20Daily/job/node-test-commit-aix-shared-lib/) + +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.