diff options
author | William Marlow <william.marlow@ibm.com> | 2022-02-04 13:12:57 +0300 |
---|---|---|
committer | RafaelGSS <rafael.nunu@hotmail.com> | 2022-05-10 15:13:19 +0300 |
commit | 0eb32ed976296b5082c7c5e1e13f32e91cb23400 (patch) | |
tree | 90d2389881106e04696c40dce513feab6b7b15b3 /node.gyp | |
parent | 840e61e745e37448c9b23a0d44892b0bc50e1f24 (diff) |
build: fix various shared library build issues
Node.js unofficially supports a shared library variant where the
main node executable is a thin wrapper around node.dll/libnode.so.
The key benefit of this is to support embedding Node.js in other
applications.
Since Node.js 12 there have been a number of issues preventing the
shared library build from working correctly, primarily on Windows:
* A number of functions used executables such as `mksnapshot` are
not exported from `libnode.dll` using a `NODE_EXTERN` attribute
* A dependency on the `Winmm` system library is missing
* Incorrect defines on executable targets leads to `node.exe`
claiming to export a number of functions that are actually in
`libnode.dll`
* Because `node.exe` attempts to export symbols, `node.lib` gets
generated causing native extensions to try to link against
`node.exe` not `libnode.dll`.
* Similarly, because `node.dll` was renamed to `libnode.dll`,
native extensions don't know to look for `libnode.lib` rather
than `node.lib`.
* On macOS an RPATH is added to find `libnode.dylib` relative to
`node` in the same folder. This works fine from the
`out/Release` folder but not from an installed prefix, where
`node` will be in `bin/` and `libnode.dylib` will be in `lib/`.
* Similarly on Linux, no RPATH is added so LD_LIBRARY_PATH needs
setting correctly for `bin/node` to find `lib/libnode.so`.
For the `libnode.lib` vs `node.lib` issue there are two possible
options:
1. Ensure `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.
2. After building `libnode.dll`, dump the exports using `dumpbin`,
and process this to generate a `node.def` file to be linked into
`node.exe` with the `/DEF:node.def` flag. The export entries
in `node.def` will all read
```
my_symbol=libnode.my_symbol
```
so that `node.exe` will redirect all exported symbols back to
`libnode.dll`. This has the benefit that addons compiled with
stock Node.js will load correctly into `node.exe` from a shared
library build, but means that every embedding executable also
needs to perform this same trick.
I went with the first option as it is the cleaner of the two
solutions in my opinion. Projects wishing to generate a shared
library variant of Node.js can now, for example,
```
.\vcbuild dll package vs
```
to generate a full node installation including `libnode.dll`,
`Release\node.lib`, and all the necessary headers. Native addons
can then be built against the shared library build easily by
specifying the correct `nodedir` option.
For example
```
>npx node-gyp configure --nodedir
C:\Users\User\node\Release\node-v18.0.0-win-x64
...
>npx node-gyp build
...
>dumpbin /dependents build\Release\binding.node
Microsoft (R) COFF/PE Dumper Version 14.29.30136.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file build\Release\binding.node
File Type: DLL
Image has the following dependencies:
KERNEL32.dll
libnode.dll
VCRUNTIME140.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
...
```
PR-URL: https://github.com/nodejs/node/pull/41850
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Diffstat (limited to 'node.gyp')
-rw-r--r-- | node.gyp | 55 |
1 files changed, 54 insertions, 1 deletions
@@ -196,6 +196,16 @@ 'dependencies': [ 'node_aix_shared' ], }, { 'dependencies': [ '<(node_lib_target_name)' ], + 'conditions': [ + ['OS=="win" and node_shared=="true"', { + 'dependencies': ['generate_node_def'], + 'msvs_settings': { + 'VCLinkerTool': { + 'ModuleDefinitionFile': '<(PRODUCT_DIR)/<(node_core_target_name).def', + }, + }, + }], + ], }], [ 'node_intermediate_lib_type=="static_library" and node_shared=="false"', { 'xcode_settings': { @@ -235,8 +245,15 @@ }], [ 'node_shared=="true"', { 'xcode_settings': { - 'OTHER_LDFLAGS': [ '-Wl,-rpath,@loader_path', ], + 'OTHER_LDFLAGS': [ '-Wl,-rpath,@loader_path', '-Wl,-rpath,@loader_path/../lib'], }, + 'conditions': [ + ['OS=="linux"', { + 'ldflags': [ + '-Wl,-rpath,\\$$ORIGIN/../lib' + ], + }], + ], }], [ 'enable_lto=="true"', { 'xcode_settings': { @@ -749,6 +766,7 @@ 'libraries': [ 'Dbghelp', 'Psapi', + 'Winmm', 'Ws2_32', ], }], @@ -1502,5 +1520,40 @@ }, ] }], # end aix section + ['OS=="win" and node_shared=="true"', { + 'targets': [ + { + 'target_name': 'gen_node_def', + 'type': 'executable', + 'sources': [ + 'tools/gen_node_def.cc' + ], + }, + { + 'target_name': 'generate_node_def', + 'dependencies': [ + 'gen_node_def', + '<(node_lib_target_name)', + ], + 'type': 'none', + 'actions': [ + { + 'action_name': 'generate_node_def_action', + 'inputs': [ + '<(PRODUCT_DIR)/<(node_lib_target_name).dll' + ], + 'outputs': [ + '<(PRODUCT_DIR)/<(node_core_target_name).def', + ], + 'action': [ + '<(PRODUCT_DIR)/gen_node_def.exe', + '<@(_inputs)', + '<@(_outputs)', + ], + }, + ], + }, + ], + }], # end win section ], # end conditions block } |