Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: add maintaining info for shared library option #42517

Closed
wants to merge 26 commits into from
Closed
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
04fc7e6
doc: add maintaining info for shared libary option
mhdawson Mar 29, 2022
d868979
fix typo
mhdawson Mar 29, 2022
31a712d
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
00f1f2b
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
e3d1085
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
e066018
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
2dea68b
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
b81291c
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
8f5935e
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
a5b3e46
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
c721355
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
b3c5a0a
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 30, 2022
4ce8d4a
squash: address comments
mhdawson Mar 30, 2022
6b136cd
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Mar 31, 2022
487a5c2
squash: address comments
mhdawson Mar 31, 2022
3f0212b
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Apr 7, 2022
5ca69c2
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Apr 7, 2022
1646f22
squash: address comments
mhdawson Apr 7, 2022
2136f11
squash: satisfy the linter
mhdawson Apr 7, 2022
b165ebd
Update doc/contributing/maintaining-shared-library-support.md
mhdawson Apr 21, 2022
86b1571
squash: address comments
mhdawson Apr 21, 2022
1912c7c
squash: address comments
mhdawson Apr 21, 2022
fa78950
Update doc/contributing/maintaining-shared-library-support.md
mhdawson May 10, 2022
7703b6e
squash: update to reflect current approach
mhdawson May 10, 2022
0a42b27
squash: address linter issues
mhdawson May 10, 2022
a89bafa
squash: stand on head to make linter happy
mhdawson May 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions doc/contributing/maintaining-shared-library-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# 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`.
mhdawson marked this conversation as resolved.
Show resolved Hide resolved
mhdawson marked this conversation as resolved.
Show resolved Hide resolved

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.exe wrapper, 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is only true on Linux and macOS where we can embed a relative RPATH into the executable. AIX doesn't have this luxury so currently it hard codes an absolute path to libnode.a into the executable.

On Windows libnode.dll and node.exe sit in the same directory as this is the expected location for DLLs. See this MSDN article if you want to know more about the DLL search order on Windows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lux01 updated, can you tell me what the hardcoded path for AIX is so that I can add it?


## Exports

On windows, functions that may be linked from native
addons or additional Node.js executables need to have
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 will cause the build to fail.
mhdawson marked this conversation as resolved.
Show resolved Hide resolved

## Native addons

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

The current node executable wrapper addresses this by
ensuring that node.lib from node.exe does not get generated
and instead copy libnode.lib to node.lib. This means addons
compiled when referencing the correct node.lib file will correctly
depend on libnode.dll. The down side is that native addons compiled
with stock Node.js will still try to resolve symbols against
node.exe rather than libnode.dll. This would be a problem for
package that use node-addon-api pre-compiled binaries with the
goal of them working across different Node.js versions and
types (standard versus shared library). At this point the
main purpose for the node executable wrapper is for testing
so this is not considered a major issue.
mhdawson marked this conversation as resolved.
Show resolved Hide resolved

For applications that use the shared library and also
want to support pre-compiled addons it should be possible
to use an approach as follows on windows (and something similar
on other platforms):

* the exports from libnode using dumpbin
* process the dumpbin output to generate a node.def file to be linked
into node.exe with the /DEF:node.def flag.
The export entries in node.def would all read my\_symbol=libnode.my\_symbol
so that node.exe will redirect all exported symbols back to libnode.dll.

However, this has not been validated/tested. It would be
a good contribution for somebody to extend the node executable
wrapper to do this.

## 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/)
* <https://ci.nodejs.org/view/All/job/node-test-commit-osx-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.