Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWilliam Marlow <william.marlow@ibm.com>2022-02-04 13:12:57 +0300
committerRafaelGSS <rafael.nunu@hotmail.com>2022-05-10 15:13:19 +0300
commit0eb32ed976296b5082c7c5e1e13f32e91cb23400 (patch)
tree90d2389881106e04696c40dce513feab6b7b15b3 /src
parent840e61e745e37448c9b23a0d44892b0bc50e1f24 (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 'src')
-rw-r--r--src/debug_utils.h6
-rw-r--r--src/env.h2
-rw-r--r--src/node.h10
-rw-r--r--src/node_internals.h15
-rw-r--r--src/node_native_module.h2
-rw-r--r--src/node_options.h2
-rw-r--r--src/node_snapshot_builder.h2
-rw-r--r--src/util.h6
8 files changed, 29 insertions, 16 deletions
diff --git a/src/debug_utils.h b/src/debug_utils.h
index 377493359e9..bd1fa5207f9 100644
--- a/src/debug_utils.h
+++ b/src/debug_utils.h
@@ -35,7 +35,7 @@ template <typename... Args>
inline std::string SPrintF(const char* format, Args&&... args);
template <typename... Args>
inline void FPrintF(FILE* file, const char* format, Args&&... args);
-void FWrite(FILE* file, const std::string& str);
+void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str);
// Listing the AsyncWrap provider types first enables us to cast directly
// from a provider type to a debug category.
@@ -57,7 +57,7 @@ enum class DebugCategory {
CATEGORY_COUNT
};
-class EnabledDebugList {
+class NODE_EXTERN_PRIVATE EnabledDebugList {
public:
bool enabled(DebugCategory category) const {
DCHECK_GE(static_cast<int>(category), 0);
@@ -168,7 +168,7 @@ void CheckedUvLoopClose(uv_loop_t* loop);
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream);
namespace per_process {
-extern EnabledDebugList enabled_debug_list;
+extern NODE_EXTERN_PRIVATE EnabledDebugList enabled_debug_list;
template <typename... Args>
inline void FORCE_INLINE Debug(DebugCategory cat,
diff --git a/src/env.h b/src/env.h
index 7e35833e45b..475ca4d8b7c 100644
--- a/src/env.h
+++ b/src/env.h
@@ -558,7 +558,7 @@ class Environment;
struct AllocatedBuffer;
typedef size_t SnapshotIndex;
-class IsolateData : public MemoryRetainer {
+class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
public:
IsolateData(v8::Isolate* isolate,
uv_loop_t* event_loop,
diff --git a/src/node.h b/src/node.h
index dec8dd6805f..e866fcd9369 100644
--- a/src/node.h
+++ b/src/node.h
@@ -32,6 +32,16 @@
# define NODE_EXTERN __attribute__((visibility("default")))
#endif
+// Declarations annotated with NODE_EXTERN_PRIVATE do not form part of
+// the public API. They are implementation details that can and will
+// change between releases, even in semver patch releases. Do not use
+// any such symbol in external code.
+#ifdef NODE_SHARED_MODE
+#define NODE_EXTERN_PRIVATE NODE_EXTERN
+#else
+#define NODE_EXTERN_PRIVATE
+#endif
+
#ifdef BUILDING_NODE_EXTENSION
# undef BUILDING_V8_SHARED
# undef BUILDING_UV_SHARED
diff --git a/src/node_internals.h b/src/node_internals.h
index bf760f4d995..c56fccb9845 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -320,13 +320,14 @@ enum InitializationSettingsFlags : uint64_t {
};
// TODO(codebytere): eventually document and expose to embedders.
-InitializationResult InitializeOncePerProcess(int argc, char** argv);
-InitializationResult InitializeOncePerProcess(
- int argc,
- char** argv,
- InitializationSettingsFlags flags,
- ProcessFlags::Flags process_flags = ProcessFlags::kNoFlags);
-void TearDownOncePerProcess();
+InitializationResult NODE_EXTERN_PRIVATE InitializeOncePerProcess(int argc,
+ char** argv);
+InitializationResult NODE_EXTERN_PRIVATE InitializeOncePerProcess(
+ int argc,
+ char** argv,
+ InitializationSettingsFlags flags,
+ ProcessFlags::Flags process_flags = ProcessFlags::kNoFlags);
+void NODE_EXTERN_PRIVATE TearDownOncePerProcess();
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s);
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);
void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params);
diff --git a/src/node_native_module.h b/src/node_native_module.h
index 3be3f2364dd..7acd154d419 100644
--- a/src/node_native_module.h
+++ b/src/node_native_module.h
@@ -29,7 +29,7 @@ using NativeModuleCacheMap =
// This class should not depend on any Environment, or depend on access to
// the its own singleton - that should be encapsulated in NativeModuleEnv
// instead.
-class NativeModuleLoader {
+class NODE_EXTERN_PRIVATE NativeModuleLoader {
public:
NativeModuleLoader(const NativeModuleLoader&) = delete;
NativeModuleLoader& operator=(const NativeModuleLoader&) = delete;
diff --git a/src/node_options.h b/src/node_options.h
index a3937900b41..8e9a044520e 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -491,7 +491,7 @@ void Parse(
namespace per_process {
extern Mutex cli_options_mutex;
-extern std::shared_ptr<PerProcessOptions> cli_options;
+extern NODE_EXTERN_PRIVATE std::shared_ptr<PerProcessOptions> cli_options;
} // namespace per_process
diff --git a/src/node_snapshot_builder.h b/src/node_snapshot_builder.h
index 61450a51dfa..2714293fbc9 100644
--- a/src/node_snapshot_builder.h
+++ b/src/node_snapshot_builder.h
@@ -13,7 +13,7 @@ namespace node {
class ExternalReferenceRegistry;
struct SnapshotData;
-class SnapshotBuilder {
+class NODE_EXTERN_PRIVATE SnapshotBuilder {
public:
static std::string Generate(const std::vector<std::string> args,
const std::vector<std::string> exec_args);
diff --git a/src/util.h b/src/util.h
index 8c21c53a134..14c8758c849 100644
--- a/src/util.h
+++ b/src/util.h
@@ -26,6 +26,8 @@
#include "v8.h"
+#include "node.h"
+
#include <climits>
#include <cstddef>
#include <cstdio>
@@ -110,8 +112,8 @@ struct AssertionInfo {
const char* message;
const char* function;
};
-[[noreturn]] void Assert(const AssertionInfo& info);
-[[noreturn]] void Abort();
+[[noreturn]] void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info);
+[[noreturn]] void NODE_EXTERN_PRIVATE Abort();
void DumpBacktrace(FILE* fp);
// Windows 8+ does not like abort() in Release mode