Skip to content

Commit 4bb43f7

Browse files
sxasxa555
authored and
sxa555
committed
build: Add support for buliding Node as a shared library
1 parent f43f965 commit 4bb43f7

File tree

7 files changed

+155
-25
lines changed

7 files changed

+155
-25
lines changed

common.gypi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
1212
'python%': 'python',
1313

14+
'node_shared%': 'false',
15+
'node_use_v8_platform%': 'true',
16+
'node_use_bundled_v8%': 'true',
17+
'node_module_version%': '',
18+
1419
'node_tag%': '',
1520
'uv_library%': 'static_library',
1621

@@ -290,6 +295,9 @@
290295
],
291296
'ldflags!': [ '-rdynamic' ],
292297
}],
298+
[ 'node_shared=="true"', {
299+
'cflags': [ '-fPIC' ],
300+
}]
293301
],
294302
}],
295303
[ 'OS=="android"', {

configure

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ from gyp.common import GetFlavor
2424
sys.path.insert(0, os.path.join(root_dir, 'tools', 'configure.d'))
2525
import nodedownload
2626

27+
# imports in tools/
28+
sys.path.insert(0, os.path.join(root_dir, 'tools'))
29+
2730
# parse our options
2831
parser = optparse.OptionParser()
2932

@@ -375,6 +378,31 @@ parser.add_option('--enable-static',
375378
dest='enable_static',
376379
help='build as static library')
377380

381+
parser.add_option('--static-libstdc++',
382+
action='store_true',
383+
dest='use_static_libstdcpp',
384+
help='statically link to libstdc++ library instead of dynamically linking')
385+
386+
parser.add_option('--shared',
387+
action='store_true',
388+
dest='shared',
389+
help='compile shared library for embedding node in another project. ' +
390+
'(This mode is not officially supported for regular applications)')
391+
392+
parser.add_option('--without-v8-platform',
393+
action='store_true',
394+
dest='without_v8_platform',
395+
default=False,
396+
help='do not initialize v8 platform during node.js startup. ' +
397+
'(This mode is not officially supported for regular applications)')
398+
399+
parser.add_option('--without-bundled-v8',
400+
action='store_true',
401+
dest='without_bundled_v8',
402+
default=False,
403+
help='do not use V8 includes from the bundled deps folder. ' +
404+
'(This mode is not officially supported for regular applications)')
405+
378406
(options, args) = parser.parse_args()
379407

380408
# Expand ~ in the install prefix now, it gets written to multiple files.
@@ -764,6 +792,10 @@ def configure_node(o):
764792
if options.enable_static:
765793
o['variables']['node_target_type'] = 'static_library'
766794

795+
o['variables']['node_shared'] = b(options.shared)
796+
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
797+
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
798+
767799
if options.linked_module:
768800
o['variables']['library_files'] = options.linked_module
769801

node.gyp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
'node_use_lttng%': 'false',
66
'node_use_etw%': 'false',
77
'node_use_perfctr%': 'false',
8+
'node_use_v8_platform%': 'true',
9+
'node_use_bundled_v8%': 'true',
10+
'node_shared%': 'false',
11+
'node_module_version%': 'true',
12+
'node_use_static_libstdcpp%': 'false',
813
'node_has_winsdk%': 'false',
914
'node_shared_zlib%': 'false',
1015
'node_shared_http_parser%': 'false',
@@ -92,6 +97,13 @@
9297
'deps/v8/tools/SourceMap.js',
9398
'deps/v8/tools/tickprocessor-driver.js',
9499
],
100+
'conditions': [
101+
[ 'node_shared=="true"', {
102+
'node_target_type%': 'shared_library',
103+
}, {
104+
'node_target_type%': 'executable',
105+
}],
106+
],
95107
},
96108

97109
'targets': [
@@ -209,6 +221,42 @@
209221

210222

211223
'conditions': [
224+
[ 'node_shared=="false"', {
225+
'msvs_settings': {
226+
'VCManifestTool': {
227+
'EmbedManifest': 'true',
228+
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
229+
}
230+
},
231+
}, {
232+
'defines': [
233+
'NODE_SHARED_MODE',
234+
],
235+
'conditions': [
236+
[ 'node_module_version!=""', {
237+
'product_extension': 'so.<(node_module_version)',
238+
}]
239+
],
240+
}],
241+
[ 'node_use_bundled_v8=="true"', {
242+
'include_dirs': [
243+
'deps/v8' # include/v8_platform.h
244+
],
245+
246+
'dependencies': [
247+
'deps/v8/tools/gyp/v8.gyp:v8',
248+
'deps/v8/tools/gyp/v8.gyp:v8_libplatform'
249+
],
250+
}],
251+
[ 'node_use_v8_platform=="true"', {
252+
'defines': [
253+
'NODE_USE_V8_PLATFORM=1',
254+
],
255+
}, {
256+
'defines': [
257+
'NODE_USE_V8_PLATFORM=0',
258+
],
259+
}],
212260
[ 'node_tag!=""', {
213261
'defines': [ 'NODE_TAG="<(node_tag)"' ],
214262
}],
@@ -278,7 +326,7 @@
278326
],
279327
},
280328
'conditions': [
281-
['OS in "linux freebsd"', {
329+
['OS in "linux freebsd" and node_shared=="false"', {
282330
'ldflags': [
283331
'-Wl,--whole-archive <(PRODUCT_DIR)/<(OPENSSL_PRODUCT)',
284332
'-Wl,--no-whole-archive',
@@ -441,7 +489,7 @@
441489
'NODE_PLATFORM="sunos"',
442490
],
443491
}],
444-
[ 'OS=="freebsd" or OS=="linux"', {
492+
[ '(OS=="freebsd" or OS=="linux") and node_shared=="false"', {
445493
'ldflags': [ '-Wl,-z,noexecstack',
446494
'-Wl,--whole-archive <(V8_BASE)',
447495
'-Wl,--no-whole-archive' ]
@@ -450,12 +498,6 @@
450498
'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ],
451499
}],
452500
],
453-
'msvs_settings': {
454-
'VCManifestTool': {
455-
'EmbedManifest': 'true',
456-
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
457-
}
458-
},
459501
},
460502
# generate ETW header and resource files
461503
{

src/node.cc

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
#include "string_bytes.h"
4040
#include "util.h"
4141
#include "uv.h"
42+
#if NODE_USE_V8_PLATFORM
4243
#include "libplatform/libplatform.h"
44+
#endif // NODE_USE_V8_PLATFORM
4345
#include "v8-debug.h"
4446
#include "v8-profiler.h"
4547
#include "zlib.h"
@@ -167,6 +169,30 @@ static v8::Platform* default_platform;
167169
static uv_sem_t debug_semaphore;
168170
#endif
169171

172+
static struct {
173+
#if NODE_USE_V8_PLATFORM
174+
void Initialize(int thread_pool_size) {
175+
platform_ = v8::platform::CreateDefaultPlatform(thread_pool_size);
176+
V8::InitializePlatform(platform_);
177+
}
178+
179+
void PumpMessageLoop(Isolate* isolate) {
180+
v8::platform::PumpMessageLoop(platform_, isolate);
181+
}
182+
183+
void Dispose() {
184+
delete platform_;
185+
platform_ = nullptr;
186+
}
187+
188+
v8::Platform* platform_;
189+
#else // !NODE_USE_V8_PLATFORM
190+
void Initialize(int thread_pool_size) {}
191+
void PumpMessageLoop(Isolate* isolate) {}
192+
void Dispose() {}
193+
#endif // !NODE_USE_V8_PLATFORM
194+
} v8_platform;
195+
170196
static void PrintErrorString(const char* format, ...) {
171197
va_list ap;
172198
va_start(ap, format);
@@ -4219,11 +4245,11 @@ static void StartNodeInstance(void* arg) {
42194245
SealHandleScope seal(isolate);
42204246
bool more;
42214247
do {
4222-
v8::platform::PumpMessageLoop(default_platform, isolate);
4248+
v8_platform.PumpMessageLoop(isolate);
42234249
more = uv_run(env->event_loop(), UV_RUN_ONCE);
42244250

42254251
if (more == false) {
4226-
v8::platform::PumpMessageLoop(default_platform, isolate);
4252+
v8_platform.PumpMessageLoop(isolate);
42274253
EmitBeforeExit(env);
42284254

42294255
// Emit `beforeExit` if the loop became alive either after emitting
@@ -4283,8 +4309,8 @@ int Start(int argc, char** argv) {
42834309
#endif
42844310

42854311
const int thread_pool_size = 4;
4286-
default_platform = v8::platform::CreateDefaultPlatform(thread_pool_size);
4287-
V8::InitializePlatform(default_platform);
4312+
4313+
v8_platform.Initialize(thread_pool_size);
42884314
V8::Initialize();
42894315

42904316
int exit_code = 1;
@@ -4301,8 +4327,7 @@ int Start(int argc, char** argv) {
43014327
}
43024328
V8::Dispose();
43034329

4304-
delete default_platform;
4305-
default_platform = nullptr;
4330+
v8_platform.Dispose();
43064331

43074332
delete[] exec_argv;
43084333
exec_argv = nullptr;

src/node.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,17 +396,23 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
396396
# define NODE_MODULE_EXPORT __attribute__((visibility("default")))
397397
#endif
398398

399+
#ifdef NODE_SHARED_MODE
400+
# define NODE_CTOR_PREFIX
401+
#else
402+
# define NODE_CTOR_PREFIX static
403+
#endif
404+
399405
#if defined(_MSC_VER)
400406
#pragma section(".CRT$XCU", read)
401407
#define NODE_C_CTOR(fn) \
402-
static void __cdecl fn(void); \
408+
NODE_CTOR_PREFIX void __cdecl fn(void); \
403409
__declspec(dllexport, allocate(".CRT$XCU")) \
404410
void (__cdecl*fn ## _)(void) = fn; \
405-
static void __cdecl fn(void)
411+
NODE_CTOR_PREFIX void __cdecl fn(void)
406412
#else
407413
#define NODE_C_CTOR(fn) \
408-
static void fn(void) __attribute__((constructor)); \
409-
static void fn(void)
414+
NODE_CTOR_PREFIX void fn(void) __attribute__((constructor)); \
415+
NODE_CTOR_PREFIX void fn(void)
410416
#endif
411417

412418
#define NODE_MODULE_X(modname, regfunc, priv, flags) \

tools/getnodeversion.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
import os,re
1+
import os
2+
import re
23

3-
node_version_h = os.path.join(os.path.dirname(__file__), '..', 'src',
4+
node_version_h = os.path.join(
5+
os.path.dirname(__file__),
6+
'..',
7+
'src',
48
'node_version.h')
59

610
f = open(node_version_h)
711

812
for line in f:
9-
if re.match('#define NODE_MAJOR_VERSION', line):
13+
if re.match('^#define NODE_MAJOR_VERSION', line):
1014
major = line.split()[2]
11-
if re.match('#define NODE_MINOR_VERSION', line):
15+
if re.match('^#define NODE_MINOR_VERSION', line):
1216
minor = line.split()[2]
13-
if re.match('#define NODE_PATCH_VERSION', line):
17+
if re.match('^#define NODE_PATCH_VERSION', line):
1418
patch = line.split()[2]
1519

1620
print '%(major)s.%(minor)s.%(patch)s'% locals()

tools/install.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,22 @@ def subdir_files(path, dest, action):
123123

124124
def files(action):
125125
is_windows = sys.platform == 'win32'
126+
output_file = 'node'
127+
output_prefix = 'out/Release/'
126128

127-
exeext = '.exe' if is_windows else ''
128-
action(['out/Release/node' + exeext], 'bin/node' + exeext)
129+
if 'false' == variables.get('node_shared'):
130+
if is_windows:
131+
output_file += '.exe'
132+
else:
133+
if is_windows:
134+
output_file += '.dll'
135+
else:
136+
# GYP will output to lib.target, this is hardcoded in its source,
137+
# see the _InstallablaeTargetInstallPath function.
138+
output_prefix += 'lib.target/'
139+
output_file = 'lib' + output_file + '.so'
140+
141+
action([output_prefix + output_file], 'bin/' + output_file)
129142

130143
if 'true' == variables.get('node_use_dtrace'):
131144
action(['out/Release/node.d'], 'lib/dtrace/node.d')

0 commit comments

Comments
 (0)