Skip to content

Commit f87ee23

Browse files
sxaStewart Addison
authored andcommitted
build: configure --shared
Add configure flag for building a shared library that can be embedded in other applications (like Electron). Add flags --without-bundled-v8 and --without-v8-platform to control V8 dependencies used. PR-URL: nodejs#6994 Ref: nodejs#9385 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reference: nodejs#7487
1 parent a42a89f commit f87ee23

8 files changed

Lines changed: 181 additions & 28 deletions

File tree

common.gypi

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
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+
'force_dynamic_crt%': 0,
16+
'node_use_v8_platform%': 'true',
17+
'node_use_bundled_v8%': 'true',
18+
'node_module_version%': '',
19+
1420
'node_tag%': '',
1521
'uv_library%': 'static_library',
1622

@@ -291,6 +297,9 @@
291297
],
292298
'ldflags!': [ '-rdynamic' ],
293299
}],
300+
[ 'node_shared=="true"', {
301+
'cflags': [ '-fPIC' ],
302+
}]
294303
],
295304
}],
296305
['OS=="android"', {

configure

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ 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+
import getmoduleversion
30+
2731
# parse our options
2832
parser = optparse.OptionParser()
2933

@@ -385,6 +389,26 @@ parser.add_option('--enable-static',
385389
dest='enable_static',
386390
help='build as static library')
387391

392+
parser.add_option('--shared',
393+
action='store_true',
394+
dest='shared',
395+
help='compile shared library for embedding node in another project. ' +
396+
'(This mode is not officially supported for regular applications)')
397+
398+
parser.add_option('--without-v8-platform',
399+
action='store_true',
400+
dest='without_v8_platform',
401+
default=False,
402+
help='do not initialize v8 platform during node.js startup. ' +
403+
'(This mode is not officially supported for regular applications)')
404+
405+
parser.add_option('--without-bundled-v8',
406+
action='store_true',
407+
dest='without_bundled_v8',
408+
default=False,
409+
help='do not use V8 includes from the bundled deps folder. ' +
410+
'(This mode is not officially supported for regular applications)')
411+
388412
(options, args) = parser.parse_args()
389413

390414
# Expand ~ in the install prefix now, it gets written to multiple files.
@@ -774,7 +798,14 @@ def configure_node(o):
774798
if options.enable_static:
775799
o['variables']['node_target_type'] = 'static_library'
776800

777-
o['variables']['node_module_version'] = 46
801+
o['variables']['node_shared'] = b(options.shared)
802+
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
803+
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
804+
node_module_version = getmoduleversion.get_version()
805+
shlib_suffix = '%s.dylib' if sys.platform == 'darwin' else 'so.%s'
806+
shlib_suffix %= node_module_version
807+
o['variables']['node_module_version'] = int(node_module_version)
808+
o['variables']['shlib_suffix'] = shlib_suffix
778809

779810
if options.linked_module:
780811
o['variables']['library_files'] = options.linked_module
@@ -820,8 +851,7 @@ def configure_v8(o):
820851
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
821852
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
822853
o['variables']['node_enable_d8'] = b(options.enable_d8)
823-
824-
854+
o['variables']['force_dynamic_crt'] = 1 if options.shared else 0
825855
def configure_openssl(o):
826856
o['variables']['node_use_openssl'] = b(not options.without_ssl)
827857
o['variables']['node_shared_openssl'] = b(options.shared_openssl)

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+
'force_dynamic_crt%': 0,
12+
'node_module_version%': 'true',
813
'node_has_winsdk%': 'false',
914
'node_shared_zlib%': 'false',
1015
'node_shared_http_parser%': 'false',
@@ -93,6 +98,13 @@
9398
'deps/v8/tools/SourceMap.js',
9499
'deps/v8/tools/tickprocessor-driver.js',
95100
],
101+
'conditions': [
102+
[ 'node_shared=="true"', {
103+
'node_target_type%': 'shared_library',
104+
}, {
105+
'node_target_type%': 'executable',
106+
}],
107+
],
96108
},
97109

98110
'targets': [
@@ -211,6 +223,42 @@
211223

212224

213225
'conditions': [
226+
[ 'node_shared=="false"', {
227+
'msvs_settings': {
228+
'VCManifestTool': {
229+
'EmbedManifest': 'true',
230+
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
231+
}
232+
},
233+
}, {
234+
'defines': [
235+
'NODE_SHARED_MODE',
236+
],
237+
'conditions': [
238+
[ 'node_module_version!=""', {
239+
'product_extension': 'so.<(node_module_version)',
240+
}]
241+
],
242+
}],
243+
[ 'node_use_bundled_v8=="true"', {
244+
'include_dirs': [
245+
'deps/v8' # include/v8_platform.h
246+
],
247+
248+
'dependencies': [
249+
'deps/v8/tools/gyp/v8.gyp:v8',
250+
'deps/v8/tools/gyp/v8.gyp:v8_libplatform'
251+
],
252+
}],
253+
[ 'node_use_v8_platform=="true"', {
254+
'defines': [
255+
'NODE_USE_V8_PLATFORM=1',
256+
],
257+
}, {
258+
'defines': [
259+
'NODE_USE_V8_PLATFORM=0',
260+
],
261+
}],
214262
[ 'node_enable_d8=="true"', {
215263
'dependencies': [ 'deps/v8/src/d8.gyp:d8' ],
216264
}],
@@ -283,7 +331,7 @@
283331
],
284332
},
285333
'conditions': [
286-
['OS in "linux freebsd"', {
334+
['OS in "linux freebsd" and node_shared=="false"', {
287335
'ldflags': [
288336
'-Wl,--whole-archive,'
289337
'<(PRODUCT_DIR)/obj.target/deps/openssl/'
@@ -448,7 +496,7 @@
448496
'NODE_PLATFORM="sunos"',
449497
],
450498
}],
451-
[ 'OS=="freebsd" or OS=="linux"', {
499+
[ '(OS=="freebsd" or OS=="linux") and node_shared=="false"', {
452500
'ldflags': [ '-Wl,-z,noexecstack',
453501
'-Wl,--whole-archive <(V8_BASE)',
454502
'-Wl,--no-whole-archive' ]
@@ -457,12 +505,6 @@
457505
'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ],
458506
}],
459507
],
460-
'msvs_settings': {
461-
'VCManifestTool': {
462-
'EmbedManifest': 'true',
463-
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
464-
}
465-
},
466508
},
467509
# generate ETW header and resource files
468510
{

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);
@@ -4226,11 +4252,11 @@ static void StartNodeInstance(void* arg) {
42264252
SealHandleScope seal(isolate);
42274253
bool more;
42284254
do {
4229-
v8::platform::PumpMessageLoop(default_platform, isolate);
4255+
v8_platform.PumpMessageLoop(isolate);
42304256
more = uv_run(env->event_loop(), UV_RUN_ONCE);
42314257

42324258
if (more == false) {
4233-
v8::platform::PumpMessageLoop(default_platform, isolate);
4259+
v8_platform.PumpMessageLoop(isolate);
42344260
EmitBeforeExit(env);
42354261

42364262
// Emit `beforeExit` if the loop became alive either after emitting
@@ -4291,8 +4317,8 @@ int Start(int argc, char** argv) {
42914317
#endif
42924318

42934319
const int thread_pool_size = 4;
4294-
default_platform = v8::platform::CreateDefaultPlatform(thread_pool_size);
4295-
V8::InitializePlatform(default_platform);
4320+
4321+
v8_platform.Initialize(thread_pool_size);
42964322
V8::Initialize();
42974323

42984324
int exit_code = 1;
@@ -4309,8 +4335,7 @@ int Start(int argc, char** argv) {
43094335
}
43104336
V8::Dispose();
43114337

4312-
delete default_platform;
4313-
default_platform = nullptr;
4338+
v8_platform.Dispose();
43144339

43154340
delete[] exec_argv;
43164341
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/getmoduleversion.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from __future__ import print_function
2+
import os
3+
import re
4+
5+
def get_version():
6+
node_version_h = os.path.join(
7+
os.path.dirname(__file__),
8+
'..',
9+
'src',
10+
'node_version.h')
11+
12+
f = open(node_version_h)
13+
14+
regex = '^#define NODE_MODULE_VERSION [0-9]+'
15+
16+
for line in f:
17+
if re.match(regex, line):
18+
major = line.split()[2]
19+
return major
20+
21+
raise Exception('Could not find pattern matching %s' % regex)
22+
23+
if __name__ == '__main__':
24+
print(get_version())

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)