Skip to content

Commit

Permalink
build: configure --shared
Browse files Browse the repository at this point in the history
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: #6994
Ref: #7487
Ref: #9385
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
  • Loading branch information
sxa authored and Myles Borins committed Nov 18, 2016
1 parent bb2fdf5 commit f21c2b9
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 28 deletions.
9 changes: 9 additions & 0 deletions common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
'python%': 'python',

'node_shared%': 'false',
'force_dynamic_crt%': 0,
'node_use_v8_platform%': 'true',
'node_use_bundled_v8%': 'true',
'node_module_version%': '',

'node_tag%': '',
'uv_library%': 'static_library',

Expand Down Expand Up @@ -291,6 +297,9 @@
],
'ldflags!': [ '-rdynamic' ],
}],
[ 'node_shared=="true"', {
'cflags': [ '-fPIC' ],
}]
],
}],
['OS=="android"', {
Expand Down
35 changes: 32 additions & 3 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ from gyp.common import GetFlavor
sys.path.insert(0, os.path.join(root_dir, 'tools', 'configure.d'))
import nodedownload

# imports in tools/
sys.path.insert(0, os.path.join(root_dir, 'tools'))

# parse our options
parser = optparse.OptionParser()

Expand Down Expand Up @@ -385,6 +388,26 @@ parser.add_option('--enable-static',
dest='enable_static',
help='build as static library')

parser.add_option('--shared',
action='store_true',
dest='shared',
help='compile shared library for embedding node in another project. ' +
'(This mode is not officially supported for regular applications)')

parser.add_option('--without-v8-platform',
action='store_true',
dest='without_v8_platform',
default=False,
help='do not initialize v8 platform during node.js startup. ' +
'(This mode is not officially supported for regular applications)')

parser.add_option('--without-bundled-v8',
action='store_true',
dest='without_bundled_v8',
default=False,
help='do not use V8 includes from the bundled deps folder. ' +
'(This mode is not officially supported for regular applications)')

(options, args) = parser.parse_args()

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

o['variables']['node_module_version'] = 46
o['variables']['node_shared'] = b(options.shared)
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
node_module_version = getmoduleversion.get_version()
shlib_suffix = '%s.dylib' if sys.platform == 'darwin' else 'so.%s'
shlib_suffix %= node_module_version
o['variables']['node_module_version'] = int(node_module_version)
o['variables']['shlib_suffix'] = shlib_suffix

if options.linked_module:
o['variables']['library_files'] = options.linked_module
Expand Down Expand Up @@ -820,8 +850,7 @@ def configure_v8(o):
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
o['variables']['node_enable_d8'] = b(options.enable_d8)


o['variables']['force_dynamic_crt'] = 1 if options.shared else 0
def configure_openssl(o):
o['variables']['node_use_openssl'] = b(not options.without_ssl)
o['variables']['node_shared_openssl'] = b(options.shared_openssl)
Expand Down
56 changes: 48 additions & 8 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
'node_use_lttng%': 'false',
'node_use_etw%': 'false',
'node_use_perfctr%': 'false',
'node_use_v8_platform%': 'true',
'node_use_bundled_v8%': 'true',
'node_shared%': 'false',
'force_dynamic_crt%': 0,
'node_module_version%': 'true',
'node_has_winsdk%': 'false',
'node_shared_zlib%': 'false',
'node_shared_http_parser%': 'false',
Expand Down Expand Up @@ -101,6 +106,11 @@
}, {
'use_openssl_def': 0,
}],
[ 'node_shared=="true"', {
'node_target_type%': 'shared_library',
}, {
'node_target_type%': 'executable',
}],
],
},

Expand Down Expand Up @@ -220,6 +230,42 @@


'conditions': [
[ 'node_shared=="false"', {
'msvs_settings': {
'VCManifestTool': {
'EmbedManifest': 'true',
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
}
},
}, {
'defines': [
'NODE_SHARED_MODE',
],
'conditions': [
[ 'node_module_version!=""', {
'product_extension': 'so.<(node_module_version)',
}]
],
}],
[ 'node_use_bundled_v8=="true"', {
'include_dirs': [
'deps/v8' # include/v8_platform.h
],

'dependencies': [
'deps/v8/tools/gyp/v8.gyp:v8',
'deps/v8/tools/gyp/v8.gyp:v8_libplatform'
],
}],
[ 'node_use_v8_platform=="true"', {
'defines': [
'NODE_USE_V8_PLATFORM=1',
],
}, {
'defines': [
'NODE_USE_V8_PLATFORM=0',
],
}],
[ 'node_enable_d8=="true"', {
'dependencies': [ 'deps/v8/src/d8.gyp:d8' ],
}],
Expand Down Expand Up @@ -292,7 +338,7 @@
],
},
'conditions': [
['OS in "linux freebsd"', {
['OS in "linux freebsd" and node_shared=="false"', {
'ldflags': [
'-Wl,--whole-archive,'
'<(PRODUCT_DIR)/obj.target/deps/openssl/'
Expand Down Expand Up @@ -460,7 +506,7 @@
'NODE_PLATFORM="sunos"',
],
}],
[ 'OS=="freebsd" or OS=="linux"', {
[ '(OS=="freebsd" or OS=="linux") and node_shared=="false"', {
'ldflags': [ '-Wl,-z,noexecstack',
'-Wl,--whole-archive <(V8_BASE)',
'-Wl,--no-whole-archive' ]
Expand All @@ -469,12 +515,6 @@
'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ],
}],
],
'msvs_settings': {
'VCManifestTool': {
'EmbedManifest': 'true',
'AdditionalManifestFiles': 'src/res/node.exe.extra.manifest'
}
},
},
{
'target_name': 'mkssldef',
Expand Down
37 changes: 31 additions & 6 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
#include "string_bytes.h"
#include "util.h"
#include "uv.h"
#if NODE_USE_V8_PLATFORM
#include "libplatform/libplatform.h"
#endif // NODE_USE_V8_PLATFORM
#include "v8-debug.h"
#include "v8-profiler.h"
#include "zlib.h"
Expand Down Expand Up @@ -167,6 +169,30 @@ static v8::Platform* default_platform;
static uv_sem_t debug_semaphore;
#endif

static struct {
#if NODE_USE_V8_PLATFORM
void Initialize(int thread_pool_size) {
platform_ = v8::platform::CreateDefaultPlatform(thread_pool_size);
V8::InitializePlatform(platform_);
}

void PumpMessageLoop(Isolate* isolate) {
v8::platform::PumpMessageLoop(platform_, isolate);
}

void Dispose() {
delete platform_;
platform_ = nullptr;
}

v8::Platform* platform_;
#else // !NODE_USE_V8_PLATFORM
void Initialize(int thread_pool_size) {}
void PumpMessageLoop(Isolate* isolate) {}
void Dispose() {}
#endif // !NODE_USE_V8_PLATFORM
} v8_platform;

static void PrintErrorString(const char* format, ...) {
va_list ap;
va_start(ap, format);
Expand Down Expand Up @@ -4226,11 +4252,11 @@ static void StartNodeInstance(void* arg) {
SealHandleScope seal(isolate);
bool more;
do {
v8::platform::PumpMessageLoop(default_platform, isolate);
v8_platform.PumpMessageLoop(isolate);
more = uv_run(env->event_loop(), UV_RUN_ONCE);

if (more == false) {
v8::platform::PumpMessageLoop(default_platform, isolate);
v8_platform.PumpMessageLoop(isolate);
EmitBeforeExit(env);

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

const int thread_pool_size = 4;
default_platform = v8::platform::CreateDefaultPlatform(thread_pool_size);
V8::InitializePlatform(default_platform);

v8_platform.Initialize(thread_pool_size);
V8::Initialize();

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

delete default_platform;
default_platform = nullptr;
v8_platform.Dispose();

delete[] exec_argv;
exec_argv = nullptr;
Expand Down
14 changes: 10 additions & 4 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,23 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
# define NODE_MODULE_EXPORT __attribute__((visibility("default")))
#endif

#ifdef NODE_SHARED_MODE
# define NODE_CTOR_PREFIX
#else
# define NODE_CTOR_PREFIX static
#endif

#if defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
#define NODE_C_CTOR(fn) \
static void __cdecl fn(void); \
NODE_CTOR_PREFIX void __cdecl fn(void); \
__declspec(dllexport, allocate(".CRT$XCU")) \
void (__cdecl*fn ## _)(void) = fn; \
static void __cdecl fn(void)
NODE_CTOR_PREFIX void __cdecl fn(void)
#else
#define NODE_C_CTOR(fn) \
static void fn(void) __attribute__((constructor)); \
static void fn(void)
NODE_CTOR_PREFIX void fn(void) __attribute__((constructor)); \
NODE_CTOR_PREFIX void fn(void)
#endif

#define NODE_MODULE_X(modname, regfunc, priv, flags) \
Expand Down
14 changes: 9 additions & 5 deletions tools/getnodeversion.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import os,re
import os
import re

node_version_h = os.path.join(os.path.dirname(__file__), '..', 'src',
node_version_h = os.path.join(
os.path.dirname(__file__),
'..',
'src',
'node_version.h')

f = open(node_version_h)

for line in f:
if re.match('#define NODE_MAJOR_VERSION', line):
if re.match('^#define NODE_MAJOR_VERSION', line):
major = line.split()[2]
if re.match('#define NODE_MINOR_VERSION', line):
if re.match('^#define NODE_MINOR_VERSION', line):
minor = line.split()[2]
if re.match('#define NODE_PATCH_VERSION', line):
if re.match('^#define NODE_PATCH_VERSION', line):
patch = line.split()[2]

print '%(major)s.%(minor)s.%(patch)s'% locals()
17 changes: 15 additions & 2 deletions tools/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,22 @@ def subdir_files(path, dest, action):

def files(action):
is_windows = sys.platform == 'win32'
output_file = 'node'
output_prefix = 'out/Release/'

exeext = '.exe' if is_windows else ''
action(['out/Release/node' + exeext], 'bin/node' + exeext)
if 'false' == variables.get('node_shared'):
if is_windows:
output_file += '.exe'
else:
if is_windows:
output_file += '.dll'
else:
# GYP will output to lib.target, this is hardcoded in its source,
# see the _InstallablaeTargetInstallPath function.
output_prefix += 'lib.target/'
output_file = 'lib' + output_file + '.so'

action([output_prefix + output_file], 'bin/' + output_file)

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

0 comments on commit f21c2b9

Please sign in to comment.