diff --git a/common.gypi b/common.gypi index 258cd1603e..f26b66e648 100644 --- a/common.gypi +++ b/common.gypi @@ -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', @@ -291,6 +297,9 @@ ], 'ldflags!': [ '-rdynamic' ], }], + [ 'node_shared=="true"', { + 'cflags': [ '-fPIC' ], + }] ], }], ['OS=="android"', { diff --git a/configure b/configure index 27ab9a54a9..2b9df01a24 100755 --- a/configure +++ b/configure @@ -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() @@ -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. @@ -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 @@ -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) diff --git a/node.gyp b/node.gyp index caddcfac02..7f2afb5f25 100644 --- a/node.gyp +++ b/node.gyp @@ -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', @@ -101,6 +106,11 @@ }, { 'use_openssl_def': 0, }], + [ 'node_shared=="true"', { + 'node_target_type%': 'shared_library', + }, { + 'node_target_type%': 'executable', + }], ], }, @@ -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' ], }], @@ -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/' @@ -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' ] @@ -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', diff --git a/src/node.cc b/src/node.cc index 155d1cdcd2..085c3d6a07 100644 --- a/src/node.cc +++ b/src/node.cc @@ -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" @@ -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); @@ -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 @@ -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; @@ -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; diff --git a/src/node.h b/src/node.h index f70b5f8e78..4d3293eab6 100644 --- a/src/node.h +++ b/src/node.h @@ -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) \ diff --git a/tools/getnodeversion.py b/tools/getnodeversion.py index 766e4f60dc..f2032cccef 100644 --- a/tools/getnodeversion.py +++ b/tools/getnodeversion.py @@ -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() diff --git a/tools/install.py b/tools/install.py index b1997d4852..64441bacd1 100755 --- a/tools/install.py +++ b/tools/install.py @@ -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')