diff --git a/configure b/configure
index d622a6f0625a18..5695c6b45a9a7b 100755
--- a/configure
+++ b/configure
@@ -409,6 +409,11 @@ parser.add_option('--enable-static',
dest='enable_static',
help='build as static library')
+parser.add_option('--no-target-type',
+ action='store_true',
+ dest='no_target_type',
+ help='do not compile and link node core')
+
parser.add_option('--no-browser-globals',
action='store_true',
dest='no_browser_globals',
@@ -741,6 +746,9 @@ def configure_node(o):
o['variables']['node_core_target_name'] = 'node_base'
o['variables']['node_target_type'] = 'static_library'
+ if options.no_target_type:
+ o['variables']['node_target_type'] = 'none'
+
if target_arch in ('x86', 'x64', 'ia32', 'x32'):
o['variables']['node_enable_v8_vtunejit'] = b(options.enable_vtune_profiling)
elif options.enable_vtune_profiling:
diff --git a/deps/platform_tools/README.md b/deps/platform_tools/README.md
new file mode 100644
index 00000000000000..b9bfd4ac89fe9e
--- /dev/null
+++ b/deps/platform_tools/README.md
@@ -0,0 +1,184 @@
+# platform-tools
+
+A toolchain to build and compile native dependencies with and for Node.
+
+[](https://travis-ci.org/eljefedelrodeodeljefe/platform-tools) [](https://ci.appveyor.com/project/eljefederodeodeljefe/platform-tools) [](https://gitter.im/eljefedelrodeodeljefe/platform-tools?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[](https://nodei.co/npm/platform-tools/)
+
+## TL;DR
+
+> Compile C/C++ and native node addons with Node.js. Under the hood this is shelling
+out to `gcc`, `clang` and `cl.exe` in a similar way `make` does. To mitigate `gyp` and
+`autotools` dependencies node users (eventually) could use this.
+
+Assume a file `exit_with_1.c`
+
+```c
+int main(int argc, char const* argv[]) {
+ return 1;
+}
+```
+
+The below would be an example of emulating with Node.js
+
+```console
+gcc -c exit_with_1
+gcc -o exit_with_1.o
+./exit_with_1
+```
+
+```js
+const platform_tools = require('platform-tools')
+const spawn = require('child_process').spawn
+
+let out = 'exit_with_1'
+// first compile without linking
+platform_tools.compile('exit_with_1.c', {output: `${out}.o`}, () => {
+ // then link the object file (here an easy case)
+ platform_tools.link(`${out}.o`, {output: out}, () => {
+ // now execute the compiled binary and expect the C-program to end
+ // with code 1
+ const cp = spawn(out, [], {shell: true});
+ cp.on('close', (code) => {
+ assert(code === 1), 'Compiled binary exit_with_1 must exit with code 1')
+ })
+ })
+})
+```
+
+## Implementation Status
+| Method | implemented |
+| --- | --- |
+| .compile(source [,options, cb]) | **yes** |
+| .compileAddon(source [,options, cb]) | **yes** |
+| .link(object [,options, cb]) | **yes** |
+| .config(library [,options, cb]) | **yes** |
+
+
+
+### Overview
+
+(TBD)
+
+Also this makes it easier for libarary authors and users, since compilation
+output will either be stored into a user specified location or by default into
+the current working directories `build/` directory (precisely
+``` `${process.cwd()}/build` ```)
+
+### Technical Overview
+
+**Rquirements:**
+* Node 4.5.0+
+* the default compiler for your system
+
+## Windows Users
+
+> Mote: since this repo wants to purposely increase Windows native addon usabilty
+please share if you have a hard time. However ue to the Microsoft inherent SDK
+and compiler strategy we need to assume prerequisites of you.
+
+* Windows SDK 10 standalone should be installed and in your %ProgramFiles(x86)%
+* Visual Studio 2015 should be installed and in your %ProgramFiles(x86)%
+
+**For background:** To accomplish unix-like command-line behavior, e.g.
+`gcc source_file.c -o source.exe && ./source.exe` we need to assume the location
+of the most basic C/C++ headers in various locations on your Windows installation.
+The `cl.exe` binary does not assume any search paths on it's own, if it is not
+run through Visual Studio. Although that being quite a quirk for embedders and
+library authors, Windows compiler support is as good as Unix'.
+
+## Platform
+
+This module is currently tested on:
+
+| Platform | 0.10 | 0.12 | 4.0 | 5.0 | 6.0 |
+| --- | --- | --- | --- | ---| ---|---|
+| Mac OS X | - | - | **yes** | **yes**| **yes** |
+| BSDs| - | - | **yes** | **yes**| **yes** |
+| Linux | - | - | **yes** | **yes** | **yes** |
+| Windows | - | - | **yes** | **yes** | **yes** |
+
+## Roadmap
+
+* have more complex C/C++ files compile and link fully
+* ~~make native addons build~~
+* make node build
+* make v8 build
+* override values that the lib takes as assumption
+* gyp-file integration (chop-off comments and trailing commas -> then done?)
+* more sophisticated Windows search path fallbacks for not optimal installatons
+
+
+## API
+
+
+## PlatformTools
+**Kind**: global class
+
+* [PlatformTools](#PlatformTools)
+ * [.compile(source, cb)](#PlatformTools+compile) ⇒ Callback
+ * [.link(object, options, cb)](#PlatformTools+link) ⇒ Callback
+ * [.config(lib, cb)](#PlatformTools+config) ⇒ Callback
+ * [.compileAddon(addonSrcFile, options, cb)](#PlatformTools+compileAddon) ⇒ Callback
+
+
+
+### platformTools.compile(source, cb) ⇒ Callback
+Compiles a given source code file or array of files to the platforms object
+code.
+
+**Kind**: instance method of [PlatformTools](#PlatformTools)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| source | String
| Array.<String>
| Path to source |
+| cb | function
| Optional callback for completion |
+
+
+
+### platformTools.link(object, options, cb) ⇒ Callback
+Links mutiple objects and libraries to a binary.
+
+**Kind**: instance method of [PlatformTools](#PlatformTools)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| object | String
| Array.<String>
| Path for name of object code file |
+| options | Object
| Options object |
+| cb | function
| Optional callback |
+
+
+
+### platformTools.config(lib, cb) ⇒ Callback
+Returns the necessary libraries to link against, similarly to pkg-config(1).
+
+**Kind**: instance method of [PlatformTools](#PlatformTools)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| lib | String
| Library to search dependencies against |
+| cb | function
| Optional Callback upon completion |
+
+
+
+### platformTools.compileAddon(addonSrcFile, options, cb) ⇒ Callback
+This method compiles node native addons end-to-end. Motivation behind this
+high level approach is past struggles with this technique, and especially
+different behaviors across platforms. Eventually this method should take
+care of all of the above. If the user has special cases, it is still
+possible to pass instructions via the options object and (item for roadmap)
+override certain common variables forcefully.
+
+**Kind**: instance method of [PlatformTools](#PlatformTools)
+**Returns**: Callback
- returns optional callback
+
+| Param | Type | Description |
+| --- | --- | --- |
+| addonSrcFile | String
| Path to source file |
+| options | Object
| Options object |
+| cb | function
| |
+
+## License
+
+MIT
diff --git a/deps/platform_tools/index.js b/deps/platform_tools/index.js
new file mode 100644
index 00000000000000..f7d4d30d95b28f
--- /dev/null
+++ b/deps/platform_tools/index.js
@@ -0,0 +1,2 @@
+'use strict'
+module.exports = require('./lib/platform_tools')
diff --git a/deps/platform_tools/lib/compilers.js b/deps/platform_tools/lib/compilers.js
new file mode 100644
index 00000000000000..d482a894e76888
--- /dev/null
+++ b/deps/platform_tools/lib/compilers.js
@@ -0,0 +1,77 @@
+'use strict'
+/*
+ this allows platform dependent mapping of flags that relies on the result
+ of process.platform and process.arch
+
+ logic is:
+ platform > compiler | linker | others > key of content
+ */
+module.exports = {
+ darwin: {
+ compiler: {
+ arch: (platform) => {
+ return {
+ arm: ['-arch', 'arm'], //TODO: this is likely not valid; doc is missing on AAPL gcc
+ ia32: ['-arch', 'i386'],
+ x64: ['-arch', 'x86_64']
+ }[platform]
+ }
+ },
+ linker: {
+ arch: (platform) => {
+ return {
+ arm: ['-arch', 'arm'], //TODO: this is likely not valid; doc is missing on AAPL gcc
+ ia32: ['-arch', 'i386'],
+ x64: ['-arch', 'x86_64']
+ }[platform]
+ }
+ },
+ osx_min_version: (version) => {
+ return [`-mmacosx-version-min=${version}`]
+ }
+ },
+ freebsd: {
+ compiler: {
+
+ },
+ linker: {
+
+ }
+ },
+ linux: {
+ compiler: {
+ arch: (platform) => {
+ return {
+ arm: ['-marm'], // REVIEW
+ ia32: ['-m32'],
+ x64: ['-m64']
+ }[platform]
+ }
+ },
+ linker: {
+ arch: (platform) => {
+ return {
+ arm: ['-marm'], // REVIEW
+ ia32: ['-m32'],
+ x64: ['-m64']
+ }[platform]
+ }
+ }
+ },
+ sunos: {
+ compiler: {
+
+ },
+ linker: {
+
+ }
+ },
+ win32: {
+ compiler: {
+
+ },
+ linker: {
+
+ }
+ }
+}
diff --git a/deps/platform_tools/lib/flags.js b/deps/platform_tools/lib/flags.js
new file mode 100644
index 00000000000000..5dc62b1af483f7
--- /dev/null
+++ b/deps/platform_tools/lib/flags.js
@@ -0,0 +1,173 @@
+'use strict';
+let linkerArch = ''
+switch (process.arch) {
+ case 'x64': linkerArch = 'X64'; break;
+ case 'ia32': linkerArch = 'X84'; break;
+ case 'arm': linkerArch = 'ARM'; break;
+}
+
+exports.linux = {
+
+}
+
+exports.darwin = {
+
+}
+
+exports.windows = {
+ vsStdIncludePaths: [
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\10\\Include\\10.0.10240.0\\ucrt`, //REVIEW
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0V140`,
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\bin\\x86`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\bin\\x64`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\bin\\arm`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\lib\\arm`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\lib\\winv6.3\\um\\x86`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\lib\\winv6.3\\um\\x64`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\lib\\winv6.3\\um\\arm`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\um`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\shared`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\winrt`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\atlmfc\\include`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\include`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\bin`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\lib`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\lib\\amd64`,
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0\V140`,
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\um`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\shared`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\winrt`
+ ],
+ vsStdLibPaths: [
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\bin\\x86`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 11.0\\VC\\bin`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\10\\Lib\\10.0.10240.0\\ucrt\\x64`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\lib\\amd64`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x64`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\10\\Include\\10.0.10240.0\\ucr`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\atlmfc\\include`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\include`,
+ `${process.env['ProgramFiles(x86)']}\\Microsoft Visual Studio 14.0\\VC\\include`,
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0V140`,
+ `${process.env['ProgramFiles(x86)']}\\MSBuild\\Microsoft.Cpp\\v4.0`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\um`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\shared`,
+ `${process.env['ProgramFiles(x86)']}\\Windows Kits\\8.1\\Include\\winrt`,
+ ]
+}
+
+exports.addon = {
+ darwin: {
+ compiler_flags: [
+ '-Os',
+ /*'-gdwarf-2' */,
+ '-mmacosx-version-min=10.7',
+ '-Wall',
+ '-Wall',
+ '-Wendif-labels',
+ '-W',
+ '-Wno-unused-parameter',
+ '-std=gnu++0x',
+ '-fno-rtti',
+ '-fno-exceptions',
+ '-fno-threadsafe-statics',
+ '-fno-strict-aliasing'
+ ],
+ linker_flags: [
+ '-bundle',
+ '-undefined',
+ 'dynamic_lookup',
+ '-Wl,-no_pie',
+ '-Wl,-search_paths_first',
+ '-mmacosx-version-min=10.7'
+ ]
+ },
+ linux: {
+ compiler_flags: [
+ '-fPIC',
+ '-pthread',
+ '-Wall',
+ '-Wextra',
+ '-Wno-unused-parameter',
+ '-m64',
+ '-O3','-ffunction-sections',
+ '-fdata-sections',
+ '-fno-omit-frame-pointer',
+ '-fno-rtti',
+ '-fno-exceptions',
+ // NOTE: -std=c++0x is for gcc earlier than 4.7. In the future this might
+ // need to be checked, since 4.7 and 4.8 are more recent ones and may
+ // be used more widely
+ '-std=c++11'
+ ],
+ linker_flags: [
+ '-shared',
+ '-pthread',
+ '-rdynamic',
+ '-m64',
+ '-Wl,--start-group',
+ /*${process.cwd()}/build/${options.output}.o`,*/
+ '-Wl,--end-group'
+ ]
+ },
+ windows: {
+ compiler_flags: [
+ '/W3',
+ '/WX-',
+ '/Ox',
+ '/Ob2',
+ '/Oi',
+ '/Ot',
+ '/Oy',
+ '/GL',
+ '/D', 'WIN32',
+ '/D', '_CRT_SECURE_NO_DEPRECATE',
+ '/D', '_CRT_NONSTDC_NO_DEPRECATE',
+ '/D', '_HAS_EXCEPTIONS=0',
+ '/D', 'BUILDING_V8_SHARED=1',
+ '/D', 'BUILDING_UV_SHARED=1',
+ '/D', 'BUILDING_NODE_EXTENSION',
+ '/D', '_WINDLL',
+ '/GF',
+ '/Gm-',
+ '/MT',
+ '/GS',
+ '/Gy',
+ '/fp:precise',
+ '/Zc:wchar_t',
+ '/Zc:forScope',
+ '/Zc:inline',
+ '/GR-',
+ '/Gd',
+ '/TP',
+ '/wd4351',
+ '/wd4355',
+ '/wd4800',
+ '/wd4251',
+ '/errorReport:queue',
+ '/MP'
+ ],
+ linker_flags: [
+ '/ERRORREPORT:QUEUE',
+ '/INCREMENTAL:NO',
+ 'kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib ', 'comdlg32.lib',
+ 'advapi32.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'odbc32.lib',
+ `${process.cwd()}\\build\\deps\\${process.versions.node}\\node.lib`,
+ // '/MANIFEST',
+ // `/MANIFESTUAC:"level='asInvoker' uiAccess='false'"`,
+ // '/manifest:embed',
+ '/MAP', '/MAPINFO:EXPORTS',
+ '/OPT:REF',
+ '/OPT:ICF',
+ '/LTCG',
+ '/TLBID:1',
+ '/DYNAMICBASE',
+ '/NXCOMPAT',
+ `/MACHINE:${linkerArch}`,
+ '/ignore:4199',
+ '/DLL'
+ ]
+ }
+}
diff --git a/deps/platform_tools/lib/node_platform.js b/deps/platform_tools/lib/node_platform.js
new file mode 100644
index 00000000000000..9dab6a9321e407
--- /dev/null
+++ b/deps/platform_tools/lib/node_platform.js
@@ -0,0 +1,109 @@
+'use strict';
+const http = require('https');
+const fs = require('fs');
+const path = require('path');
+const zlib = require('zlib');
+// TODO: get rid of dependency
+const tar = require('./tar');
+
+const buildDirs = [
+ `${process.cwd()}/build`,
+ `${process.cwd()}/build/deps`,
+ `${process.cwd()}/build/deps/${process.versions.node}`,
+ `${process.cwd()}/build/Release`,
+]
+
+const r = process.release
+const urls = [ {name: 'headers', url: r.headersUrl} ]
+// only present on win32
+if (process.platform === 'win32') urls.push( {name: 'node.lib', url: r.libUrl} )
+
+
+class Addon {
+ constructor() {
+ this.buildDirs = buildDirs
+ this.urls = urls
+ this.downloadCount = this.urls.length
+ }
+
+ _setupBuildDir(cb) {
+ this.buildDirs.forEach((dir) => {
+ try {
+ fs.mkdirSync(dir)
+ } catch (e) {
+ // ignore all errors
+ }
+ })
+ process.nextTick(() => { return cb(null) })
+ }
+
+ _download(url, output, cb) {
+ let self = this
+
+ const options = {
+ 'method': 'GET',
+ 'hostname': 'nodejs.org',
+ 'path': url,
+ 'headers': {}
+ };
+ const req = http.request(options, function (res) {
+ if (path.parse(url).ext === '.gz') {
+ res
+ .pipe(zlib.createUnzip())
+ .pipe(tar.extract(output, {strip: 1}))
+ .on('finish', () => {
+ // check output
+ fs.readdir(output, (err, files) => {
+ if (err || files.length <= 0) {
+ process.nextTick(() => {
+ return cb(err ? err : new Error('no files')) })
+ }
+ self.downloadCount--
+
+ if (self.downloadCount <= 0)
+ process.nextTick(() => { return cb(null) })
+ });
+ })
+
+ res.on('error', (err) => { return process.nextTick(() => { cb(err) }) });
+ } else {
+ res.pipe(fs.createWriteStream(output)).on('finish', () =>{
+ self.downloadCount--
+ if (self.downloadCount <= 0) {
+ process.nextTick(() => { return cb(null) })
+ }
+ })
+ }
+
+ })
+ req.end()
+ }
+
+
+ getDeps(cb) {
+ let count = this.urls.length
+
+ this._setupBuildDir((err) => {
+ if (err) return cb(err)
+ // first check whether download is necessary
+ fs.readdir(`${process.cwd()}/build/deps/${process.versions.node}/headers/include/node`, (err, files) => {
+ // Ignore the error case here, since we'll then override.
+ // If the header dir has at least one file we assume it has them all
+ if (files && files.length > 1)
+ return process.nextTick(() => { cb(null) })
+
+ this.urls.forEach((el) => {
+ --count
+ this._download(el.url, `${process.cwd()}/build/deps/${process.versions.node}/${el.name}`, (err) => {
+ if (err) return cb(err)
+ // invoke callback only when all deps have been downloaded or err'd
+ if (count <= 0)
+ return process.nextTick(() => { return cb(null) })
+ })
+ })
+ })
+ })
+ }
+}
+
+module.exports = new Addon()
diff --git a/deps/platform_tools/lib/pkg_config.js b/deps/platform_tools/lib/pkg_config.js
new file mode 100644
index 00000000000000..1dc8ee30aede3e
--- /dev/null
+++ b/deps/platform_tools/lib/pkg_config.js
@@ -0,0 +1,177 @@
+'use strict';
+const path = require('path')
+const fs = require('fs')
+const readline = require('readline')
+const debuglog = require('util').debuglog('platform_tools')
+
+const pkgConfigSearchPaths = [
+ '/usr/lib/pkgconfig',
+ '/usr/share/pkgconfig',
+ '/usr/local/lib/pkgconfig',
+ '/usr/local/share/pkgconfig'
+]
+
+exports.pkgConfigSearchPaths = pkgConfigSearchPaths
+
+function parsePcLine(line) {
+ // brute force REVIEW
+ // Rationale:
+ // * match line if it has ': ' or '=' delimiter via split
+ // * both cases get first result as key for the result
+ // * Libs, Cflags, Requires (all colon-case) are special cases, since they
+ // will have multiple values that are space delimited
+ // * those will be split up into an array and checked against, if the array
+ // has empty elements and hence those exluded if so
+ //
+ const hasColon = line.split(': ')
+ const hasEqual= line.split('=')
+
+ let key
+ let values
+ if (hasColon.length > 1) {
+ key = hasColon[0]
+ values = hasColon[1]
+ } else if (hasEqual.length > 1) {
+ key = hasEqual[0]
+ values = hasEqual[1]
+ }
+
+ if (key === 'Libs' || key === 'Cflags' || key === 'Requires') {
+ values = values.split(' ')
+ values = values.filter((val) => {
+ if (!(val === '')) return val
+ })
+ }
+
+ return {
+ key: key,
+ values: values
+ }
+}
+
+function resolveVariables(result) {
+ // brute force REVIEW
+ // Rationale:
+ // * check if current result is in array or string format
+ // * for both take the (element-level) string and check if it has
+ // a variable include (checks only for one REVIEW)
+ // * string replace include with the information as key of the result object,
+ // which assumes that the object has a declartion of that variable already
+ // * not recursive
+ //
+ const re = /(\$\{([^)]+)\})/ // matches ${} brackets and its inside
+ for (var key in result) {
+ if (typeof result[key] === 'string') {
+ let m
+ if ((m = re.exec(result[key])) !== null) {
+ if (m.index === re.lastIndex)
+ re.lastIndex++
+ if (m[0])
+ result[key] = result[key].replace(m[0], result[m[2]])
+ }
+ } else if (result[key] && result[key].constructor === Array) {
+ let res = []
+ result[key].forEach((el) => {
+ let m
+ // just regular regex stuff here, REVIEW: verbose
+ if ((m = re.exec(el)) !== null) {
+ if (m.index === re.lastIndex)
+ re.lastIndex++
+ if (m[0])
+ res.push(el.replace(m[0], result[m[2]])) // insert value with key
+ else
+ res.push(el) // fall through if regex actually hasn't matched a string
+ } else {
+ res.push(el) // fall through if regex does not variable include
+ }
+ })
+ result[key] = res
+ }
+ }
+ return result
+}
+
+// internal doc taken from man plg-config:
+//
+// The pkg-config program is used to retrieve information about installed
+// libraries in the system. It is typically used to compile and link against
+// one or more libraries. Here is a typical usage scenario in a Makefile:
+//
+// program: program.c
+// cc program.c $(pkg-config --cflags --libs gnomeui)
+//
+// pkg-config retrieves information about packages from special metadata files.
+// These files are named after the package, and has a .pc extension. On most
+// systems, pkg-config looks in /usr/lib/pkgconfig, /usr/share/pkgconfig,
+// /usr/local/lib/pkgconfig and /usr/local/share/pkgconfig for these files. It
+// will additionally look in the colon-separated (on Windows, semicolon-sepa-
+// rated) list of directories specified by the PKG_CONFIG_PATH environment
+// variable.
+//
+// The package name specified on the pkg-config command line is defined to be
+// the name of the metadata file, minus the .pc extension. If a library can
+// install multiple versions simultaneously, it must give each version its own
+// name (for example, GTK 1.2 might have the package name "gtk+" while GTK 2.0
+// has "gtk+-2.0").
+//
+// In addition to specifying a package name on the command line, the full path
+// to a given .pc file may be given instead. This allows a user to directly
+// query a particular .pc file.
+//
+exports.config = (lib, cb) => {
+ const parseTargets = []
+ // template for pkg-config-like output
+ let result = {
+ prefix: null,
+ exec_prefix: null,
+ libdir: null,
+ includedir: null,
+ name: null,
+ description: null,
+ version: null,
+ requires: null, // array
+ libs: null, // array
+ cflags: null // array
+ }
+
+ let searchPaths = pkgConfigSearchPaths
+ // if user specifies a path, include into the search paths
+ // will be git first in case it is a file. If not, falls back to defaults
+ if (lib.indexOf(path.sep) >= 0) {
+ const file = path.parse(lib)
+ if (file.ext !== '.pc')
+ return process.nextTick(() => { cb(new InputError('File must have .pc extension.'))})
+ searchPaths.unshift(file.dir)
+ lib = file.name
+ }
+
+ searchPaths.forEach((pathToLib) => {
+ let target = `${pathToLib}${path.sep}${lib}.pc`
+ let res
+ try {
+ res = fs.statSync(target)
+ } catch(e) {
+ // ignore ENOENTs; check will be done below
+ }
+ if (res && res.isFile()) parseTargets.push(target)
+ })
+ // bail when no .pc file was found REVIEW
+ if (parseTargets.length === 0)
+ return process.nextTick(() => { cb(null, null) })
+
+ if (parseTargets.length > 1)
+ debuglog('Found more than one .pc file. Only using first one found')
+
+ const runner = readline.createInterface({ input: fs.createReadStream(parseTargets[0]) })
+ runner.on('line', (line) => {
+ const res = parsePcLine(line)
+ if (res && res.key) {
+ result[res.key.toLowerCase()] = res.values
+ }
+ })
+ runner.on('error', (err) => { return process.nextTick(() => { cb(err) }) })
+ runner.on('close', () => {
+ result = resolveVariables(result)
+ return process.nextTick(() => { cb(null, result) })
+ })
+}
diff --git a/deps/platform_tools/lib/platform_tools.js b/deps/platform_tools/lib/platform_tools.js
new file mode 100644
index 00000000000000..1bbc631e8413f1
--- /dev/null
+++ b/deps/platform_tools/lib/platform_tools.js
@@ -0,0 +1,425 @@
+'use strict'
+const spawn = require('child_process').spawn
+const EventEmitter = require('events')
+const path = require('path')
+const fs = require('fs')
+const debuglog = require('util').debuglog('platform_tools')
+
+const addon = require('./node_platform')
+const compilerUtil = require('./compilers')
+const pkgConfig = require('./pkg_config')
+const pkgConfigSearchPaths = pkgConfig.pkgConfigSearchPaths
+const flags = require('./flags')
+
+const DEBUG = process.env.NODE_DEBUG === 'platform_tools' ? true : false
+
+// default, can be extended only in the class
+const compilers = {
+ win32: '"%programfiles(x86)%\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\cl.exe"',
+ freeBSD: 'clang',
+ darwin: 'clang',
+ linux: 'gcc',
+ sunos: 'gcc' // REVIEW
+}
+
+function shouldBeSyncAPI(a, b) {
+ if (a && b) return b
+ if (!a && !b) return true
+ if (!b && (a !== null && typeof a === 'object')) return true
+ if (!b && typeof a === 'function') return a
+}
+
+/**
+ * @class
+ */
+class PlatformTools extends EventEmitter {
+ constructor(options) {
+ super()
+ this.options = Object.assign({}, options)
+
+ this.pkgConfigSearchPaths = pkgConfigSearchPaths
+ this.cc = compilers[process.platform]
+ // branch for g++ on linux
+ if (process.platform === 'linux') this.cxx = 'g++'
+ else if (process.platform === 'darwin' || process.platform === 'freeBSD')
+ this.cxx = 'clang++'
+ else this.cxx = compilers[process.platform]
+ // defaul to cc but keep reference here, for passing state, say, to .link
+ this.compiler = this.cc
+
+ this.options.silent = this.options.silent || false
+ // utilities for .compileAdddon()
+ this.downloading = false // lock for compileAddon
+ this.deferedAddonCompilationCBs = []
+ }
+
+ /**
+ * Compiles a given source code file or array of files to the platforms object
+ * code.
+ * @param {String|String[]} source Path to source
+ * @param {Function} cb Optional callback for completion
+ * @return {Callback}
+ */
+ compile(sources, opts, cb) {
+ const options = Object.assign({}, opts)
+ const sync = shouldBeSyncAPI(options, cb)
+
+ if (typeof sources === 'string' || sources instanceof String) {
+ return this._compile(sources, opts, cb)
+
+ } else if (Array.isArray(sources) && sources.length > 0) {
+ let opts = options
+ let count = sources.length
+ const files = []
+ opts.output = undefined
+
+ sources.forEach((source) => {
+ this._compile(source, opts, (err, file) => {
+ --count
+ if (err) return process.nextTick(() => { cb(err) })
+ files.push(file)
+
+ if (count === 0)
+ process.nextTick(() => { return cb(null, files) })
+ })
+ })
+
+ } else {
+ const err = new Error('First argument must be a string or array of strings\
+ \r to source files.')
+ if (sync) throw err
+ else return cb(err)
+ }
+ }
+
+ _compile(source, opts, cb) {
+ // forward declarations and input handling
+ const silent = this.options.silent
+ const options = Object.assign({}, opts)
+
+ const sync = shouldBeSyncAPI(options, cb)
+ if (sync !== true) cb = sync
+
+ if (!source)
+ throw new Error('Function expects a source file as first argument')
+
+ // parsing inputs
+ const ext = path.extname(source)
+ if (!(ext === '.c' || ext === '.cc' || ext === '.cpp'))
+ throw new Error('Source file must have .c, .cc or .cpp extension')
+
+ // sets compiler to cxx for subsequent calls to .link and others
+ if (ext === '.cc' || ext === '.cpp') this.compiler = this.cxx
+
+ const args = []
+ if (process.platform === 'win32') args.push('/nologo')
+ // -D / /D flags
+ if (opts.defines) {
+ const isNode4 = process.versions.node[0] <= 4 // v4 quirk: doesn't properply escape ''-DFLAG_IS_SET''
+ options.defines.forEach((define) => {
+ if (process.platform === 'win32')
+ args.push(`${isNode4 ? '' : '\''}/D${define}${isNode4 ? '' : '\''}`)
+ else
+ args.push(`${isNode4 ? '' : '\''}-D${define}${isNode4 ? '' : '\''}`)
+ })
+ }
+ // add seach paths for the compiler
+ if (opts.include_headers) {
+ options.include_headers.forEach((el) => {
+ if (process.platform === 'win32')
+ args.push(`/I"${el}"`)
+ else
+ args.push(`-I${el}`)
+ })
+ }
+ // windows quirk: VS hides away standard include paths. For that reason we
+ // need to push those manually
+ if (process.platform === 'win32')
+ flags.windows.vsStdIncludePaths.forEach((el) => { args.push(`/I"${el}"`) })
+
+ // adds unrestricted compiler flags, such as optimizations
+ if (opts.compiler_flags) {
+ options.compiler_flags.forEach((el) => {
+ if (process.platform === 'win32')
+ args.push(el) // not implemented
+ else
+ args.push(`${el}`)
+ })
+ }
+
+ args.push(process.platform === 'win32' ? '/c' : '-c') // compile, only
+ // specify minimal output, REVIEW: refactor verbosity
+ let filename = ''
+ if (options.output)
+ filename = options.output
+ else
+ filename = `${process.cwd()}/build/${path.parse(source).name}`
+
+ if (opts.output) {
+ if (process.platform === 'win32') {
+ args.push(`/Fo${filename}`)
+ } else {
+ args.push('-o')
+ args.push(`${filename}`)
+ }
+ } else {
+ if (process.platform === 'win32') {
+ args.push(`/Fo${filename}.o`)
+ } else {
+ args.push('-o')
+ args.push(`${filename}.o`)
+ }
+ }
+ // necessary input file
+ args.push(source)
+
+ debuglog(this.compiler, args)
+ // actual entry point
+ const runner = spawn(this.compiler, args, {shell: true});
+ runner.stderr.on('data', (data) => {
+ process.stdout.write(data)
+ });
+ runner.on('error', (err) => { return cb(err) })
+ runner.on('exit', (code) => {
+ if (code != 0) {
+ return cb(new Error('compiler suffered errors'))
+ }
+ // REVIEW: normalizing extension seems to be hack from APi inconsistency
+ // between .compileAddon's and .compile's options
+ const ext = path.parse(filename).ext === '.o' ? '' : '.o'
+ return process.nextTick(() => { cb(null, `${filename}${ext}`) })
+ });
+ }
+
+ /**
+ * Links mutiple objects and libraries to a binary.
+ * @param {String|String[]} object Path for name of object code file
+ * @param {Object} options Options object
+ * @param {Function} cb Optional callback
+ * @return {Callback}
+ */
+ link(objectFiles, opts, cb) {
+ // unlike _compile there will be no API handling here for now.
+ // The array as input case is handled in _link itself due to how the
+ // compilers take inputs
+ this._link(objectFiles, opts, cb)
+ }
+
+ _link(objectFiles, opts, cb) {
+ const silent = this.options.silent
+ const options = Object.assign({}, opts)
+
+ const sync = shouldBeSyncAPI(options, cb)
+ if (sync !== true) cb = sync
+
+ const args = []
+
+ let filename = ''
+ // necessary object file(s)
+ // NOTE: this branches for the array or single string case for the linker.
+ // The former will emulate `gcc file_1.o file_2.o -o somenewname`
+ if (typeof objectFiles === 'string' || objectFiles instanceof String) {
+ args.push(objectFiles)
+ // specify minimal output
+ filename = `${process.cwd()}/build/${path.parse(objectFiles).name}`
+ } else if (Array.isArray(objectFiles) && objectFiles.length > 0) {
+ objectFiles.forEach((objectFile) => { args.push(objectFile) })
+ // NOTE: there is no fallback for when options.output is not defined.
+ // This would need to be handled here
+ filename = `${options.output}`
+ }
+ // on win32 everything herafter is a linker flag
+ if (process.platform === 'win32')
+ args.push('/link')
+ // library lookup paths from options object
+ if (options && options.include_libraries) {
+ options.include_libraries.forEach((el) => {
+ if (process.platform === 'win32')
+ args.push("/LIBPATH:" + '\"' + el + '\"')
+ else
+ args.push(`-L${el}`)
+ })
+ }
+ // additional linker flags from options object
+ if (options && options.linker_flags) {
+ options.linker_flags.forEach((el) => {
+ if (process.platform === 'win32')
+ args.push(el)
+ else
+ args.push(`${el}`)
+ })
+ }
+
+ if (process.platform === 'win32')
+ flags.windows.vsStdLibPaths.forEach((el) => { args.push("/LIBPATH:" + '\"' + el + '\"') })
+ // output name. NOTE: on windows the output is a linker flag and needs to
+ // succeed it. The other platforms do not have a dedicated linker flag,
+ // though in their cases one could use the `ld` binary. Here we are just
+ // aware of the fact and let the compiler binary figure that out
+ if (options && options.output) {
+ if (process.platform === 'win32') {
+ args.push(`/OUT:${filename}${opts.isWinAddon ? '.node' : '.exe'}`)
+ } else {
+ args.push('-o')
+ args.push(`${options.output}`)
+ }
+ } else {
+ if (process.platform === 'win32') {
+ args.push(`/OUT:${filename}${opts.isWinAddon ? '.node' : '.exe'}`)
+ } else {
+ args.push('-o')
+ args.push(`${filename}`)
+ }
+ }
+ // some situations demand flags at the end position, i.e. gcc for .a libraries
+ if (options && options.tail_flags) {
+ options.tail_flags.forEach((el) => {
+ if (process.platform === 'win32')
+ args.push(el)
+ else
+ args.push(`${el}`)
+ })
+ }
+ //
+ let cwd = undefined
+ if (opts.isWinAddon) cwd = `${process.cwd()}/build/`
+
+ debuglog(this.compiler, args)
+ // actual entry point: shelling out to the compiler
+ const runner = spawn(this.compiler, args, {shell: true, cwd: cwd});
+ runner.stdout.on('data', (data) => {
+ if (!silent)
+ process.stdout.write(data)
+ });
+ runner.on('error', (err) => { return cb(err) })
+ runner.on('exit', (code) => {
+ if (code != 0) {
+ return process.nextTick(() => { cb(new Error('linker suffered errors')) })
+ }
+ return process.nextTick(() => { cb(null, filename) })
+ });
+ }
+
+ /**
+ * Returns the necessary libraries to link against, similarly to pkg-config(1).
+ * @param {String} lib Library to search dependencies against
+ * @param {Function} cb Optional Callback upon completion
+ * @return {Callback}
+ */
+ config(lib, cb) {
+ return pkgConfig.config(lib, cb)
+ }
+ /**
+ * This method compiles node native addons end-to-end. Motivation behind this
+ * high level approach is past struggles with this technique, and especially
+ * different behaviors across platforms. Eventually this method should take
+ * care of all of the above. If the user has special cases, it is still
+ * possible to pass instructions via the options object and (item for roadmap)
+ * override certain common variables forcefully.
+ *
+ * @param {String} addonSrcFile Path to source file
+ * @param {Object} options Options object
+ * @param {Function} cb
+ * @return {Callback} returns optional callback
+ */
+ compileAddon(addonSrcFile, options, cb) {
+ // checks for existing deps.
+ fs.readdir(`${process.cwd()}/build/deps/${process.versions.node}/headers/include/node`, (err, files) => {
+ if (!this.downloading && (err || files.length <= 0)) {
+ this.downloading = true // lock here, for the multi addon per project case
+
+ return addon.getDeps((err) => {
+ this.downloading = false
+ if (err) return cb(err)
+ // execute all deferred functions
+ if (this.deferedAddonCompilationCBs.length > 0)
+ this.deferedAddonCompilationCBs.forEach((exe) => { exe() })
+ // proceeed normally
+ this._compileAddon(addonSrcFile, options, (err) => {
+ process.nextTick(() => {
+ if (err)
+ return cb(err)
+ return cb(null)
+ })
+ })
+ })
+ }
+ // compile when header files are already present
+ // NOTE: this function should only be called when headers are present. If
+ // we arrive here we are pushing it to a class variable and let .getDeps()
+ // callback execute those functions.
+ // The conequence of not doing this are real flaky race conditions.
+ const exe = () => {
+ this._compileAddon(addonSrcFile, options, (err) => {
+ process.nextTick(() => {
+ if (err)
+ return cb(err)
+ return cb(null)
+ })
+ })
+ }
+ // determine state of the module and decide to defer execution
+ if (this.downloading)
+ this.deferedAddonCompilationCBs.push(exe)
+ else
+ exe()
+ });
+ }
+
+ _compileAddon(addonSrcFile, options, cb) {
+ let opt = {
+ output: `${process.cwd()}/build/${options.output}.o`,
+ include_headers: [
+ `${process.cwd()}/build/deps/${process.versions.node}/headers/include/node`,
+ `${process.cwd()}/node_modules/nan`
+ ],
+ compiler_flags: []
+ }
+ // the following bumps flags and deps on a per platform basis. No magic.
+ if (process.platform === 'darwin') {
+ opt.compiler_flags = flags.addon.darwin.compiler_flags
+ } else if (process.platform === 'linux') {
+ opt.compiler_flags = flags.addon.linux.compiler_flags
+ opt.compiler_flags.push(`-Wl,-soname=${options.output}.node`)
+ } else if (process.platform === 'win32') {
+ opt.compiler_flags = flags.addon.windows.compiler_flags
+ }
+
+ this.compile(addonSrcFile, opt, (err, files) => {
+ if (err) return cb(err.toString())
+ // then link the object file (here an easy case)
+ let opt = {
+ output: `${process.cwd()}/build/${options.output}.node`,
+ include_libraries: [
+ `${process.cwd()}/build/Release`
+ ],
+ linker_flags: []
+ }
+
+ if (process.platform === 'darwin') {
+ opt.linker_flags = flags.addon.darwin.linker_flags
+ } else if (process.platform === 'linux') {
+ opt.linker_flags = flags.addon.linux.linker_flags
+ // REVIEW: the above won't compile. Have considered trailing
+ // flag mechanism, but works without. Review this asap
+ } else if (process.platform === 'win32') {
+ opt.linker_flags = flags.addon.windows.linker_flags
+ }
+
+ // NOTE: quirk b/c unix executables don't have ending, win have, exlude
+ // it manually when building addons
+ if (process.platform === 'win32') opt.isWinAddon = true
+
+ this.link(files, opt, (err) => {
+ if (err) return cb(err)
+
+ process.nextTick(() => { return cb(null) })
+ })
+ })
+ }
+}
+
+
+module.exports = new PlatformTools()
+module.exports.PlatformTools = PlatformTools
+module.exports.compilerUtil = compilerUtil
diff --git a/deps/platform_tools/lib/tar/index.js b/deps/platform_tools/lib/tar/index.js
new file mode 100644
index 00000000000000..016372d994edea
--- /dev/null
+++ b/deps/platform_tools/lib/tar/index.js
@@ -0,0 +1,205 @@
+/*
+ widely based on and copied from:
+ * https://github.com/mafintosh/tar-stream
+ * https://github.com/mafintosh/tar-fs
+ * https://github.com/rvagg/bl
+ * https://github.com/mafintosh/end-of-stream
+ * https://github.com/mafintosh/pump
+ * https://github.com/substack/node-mkdirp
+ */
+var tar = require('./tar-stream')
+var pump = require('./pump')
+var fs = require('fs')
+var path = require('path')
+var os = require('os')
+
+var win32 = os.platform() === 'win32'
+
+var noop = function () {}
+
+var echo = function (name) {
+ return name
+}
+
+var normalize = !win32 ? echo : function (name) {
+ return name.replace(/\\/g, '/').replace(/:/g, '_')
+}
+
+
+var strip = function (map, level) {
+ return function (header) {
+ header.name = header.name.split('/').slice(level).join('/')
+ if (header.linkname) header.linkname = header.linkname.split('/').slice(level).join('/')
+ return map(header)
+ }
+}
+
+var head = function (list) {
+ return list.length ? list[list.length - 1] : null
+}
+
+var processGetuid = function () {
+ return process.getuid ? process.getuid() : -1
+}
+
+var processUmask = function () {
+ return process.umask ? process.umask() : 0
+}
+
+exports.extract = function (cwd, opts) {
+ if (!cwd) cwd = '.'
+ if (!opts) opts = {}
+
+ var xfs = opts.fs || fs
+ var ignore = opts.ignore || opts.filter || noop
+ var map = opts.map || noop
+ var mapStream = opts.mapStream || echo
+ var own = opts.chown !== false && !win32 && processGetuid() === 0
+ var extract = opts.extract || tar.extract()
+ var stack = []
+ var now = new Date()
+ var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
+ var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
+ var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
+ var strict = opts.strict !== false
+
+ if (opts.strip) map = strip(map, opts.strip)
+
+ if (opts.readable) {
+ dmode |= parseInt(555, 8)
+ fmode |= parseInt(444, 8)
+ }
+ if (opts.writable) {
+ dmode |= parseInt(333, 8)
+ fmode |= parseInt(222, 8)
+ }
+
+ var utimesParent = function (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
+ var top
+ while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop()
+ if (!top) return cb()
+ xfs.utimes(top[0], now, top[1], cb)
+ }
+
+ var utimes = function (name, header, cb) {
+ if (opts.utimes === false) return cb()
+
+ if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb)
+ if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link?
+
+ xfs.utimes(name, now, header.mtime, function (err) {
+ if (err) return cb(err)
+ utimesParent(name, cb)
+ })
+ }
+
+ var chperm = function (name, header, cb) {
+ var link = header.type === 'symlink'
+ var chmod = link ? xfs.lchmod : xfs.chmod
+ var chown = link ? xfs.lchown : xfs.chown
+
+ if (!chmod) return cb()
+ chmod(name, (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask, function (err) {
+ if (err) return cb(err)
+ if (!own) return cb()
+ if (!chown) return cb()
+ chown(name, header.uid, header.gid, cb)
+ })
+ }
+
+ extract.on('entry', function (header, stream, next) {
+ header = map(header) || header
+ header.name = normalize(header.name)
+ var name = path.join(cwd, path.join('/', header.name))
+
+ if (ignore(name, header)) {
+ stream.resume()
+ return next()
+ }
+
+ var stat = function (err) {
+ if (err) return next(err)
+ utimes(name, header, function (err) {
+ if (err) return next(err)
+ if (win32) return next()
+ chperm(name, header, next)
+ })
+ }
+
+ var onfile = function () {
+ var ws = xfs.createWriteStream(name)
+ var rs = mapStream(stream, header)
+
+ ws.on('error', function (err) { // always forward errors on destroy
+ rs.destroy(err)
+ })
+
+ pump(rs, ws, function (err) {
+ if (err) return next(err)
+ ws.on('close', stat)
+ })
+ }
+
+ if (header.type === 'directory') {
+ stack.push([name, header.mtime])
+ return mkdirp(name, {fs: xfs}, stat)
+ }
+
+ xfs.mkdir(path.dirname(name), function (err) {
+ if (err && err.code != 'EEXIST') return next(err)
+
+ switch (header.type) {
+ case 'file': return onfile()
+ }
+
+ if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')'))
+
+ stream.resume()
+ next()
+ })
+ })
+
+ return extract
+}
+
+var _0777 = parseInt('0777', 8);
+
+function mkdirp (p, opts, f, made) {
+ var mode = opts.mode;
+ var xfs = opts.fs || fs;
+
+ if (mode === undefined) {
+ mode = _0777 & (~process.umask());
+ }
+ if (!made) made = null;
+
+ var cb = f || function () {};
+ p = path.resolve(p);
+
+ xfs.mkdir(p, mode, function (er) {
+ if (!er) {
+ made = made || p;
+ return cb(null, made);
+ }
+ switch (er.code) {
+ case 'ENOENT':
+ mkdirp(path.dirname(p), opts, function (er, made) {
+ if (er) cb(er, made);
+ else mkdirp(p, opts, cb, made);
+ });
+ break;
+
+ // In the case of any other error, just see if there's a dir
+ // there already. If so, then hooray! If not, then something
+ // is borked.
+ default:
+ xfs.stat(p, function (er2, stat) {
+ // if the stat fails, then that's super weird.
+ // let the original error be the failure reason.
+ if (er2 || !stat.isDirectory()) cb(er, made)
+ else cb(null, made);
+ });
+ break;
+ }
+ });
+}
diff --git a/deps/platform_tools/lib/tar/pump.js b/deps/platform_tools/lib/tar/pump.js
new file mode 100644
index 00000000000000..9009b2fcecb5e6
--- /dev/null
+++ b/deps/platform_tools/lib/tar/pump.js
@@ -0,0 +1,146 @@
+var fs = require('fs') // we only need fs to get the ReadStream and WriteStream prototypes
+
+var noop = function () {}
+
+var isFn = function (fn) {
+ return typeof fn === 'function'
+}
+
+var isFS = function (stream) {
+ return (stream instanceof (fs.ReadStream || noop) || stream instanceof (fs.WriteStream || noop)) && isFn(stream.close)
+}
+
+var isRequest = function (stream) {
+ return stream.setHeader && isFn(stream.abort)
+}
+
+var destroyer = function (stream, reading, writing, callback) {
+ callback = callback
+
+ var closed = false
+ stream.on('close', function () {
+ closed = true
+ })
+
+ eos(stream, {readable: reading, writable: writing}, function (err) {
+ if (err) return callback(err)
+ closed = true
+ callback()
+ })
+
+ var destroyed = false
+ return function (err) {
+ if (closed) return
+ if (destroyed) return
+ destroyed = true
+
+ if (isFS(stream)) return stream.close() // use close for fs streams to avoid fd leaks
+ if (isRequest(stream)) return stream.abort() // request.destroy just do .end - .abort is what we want
+
+ if (isFn(stream.destroy)) return stream.destroy()
+
+ callback(err || new Error('stream was destroyed'))
+ }
+}
+
+var call = function (fn) {
+ fn()
+}
+
+var pipe = function (from, to) {
+ return from.pipe(to)
+}
+
+var pump = function () {
+ var streams = Array.prototype.slice.call(arguments)
+ var callback = isFn(streams[streams.length - 1] || noop) && streams.pop() || noop
+
+ if (Array.isArray(streams[0])) streams = streams[0]
+ if (streams.length < 2) throw new Error('pump requires two streams per minimum')
+
+ var error
+ var destroys = streams.map(function (stream, i) {
+ var reading = i < streams.length - 1
+ var writing = i > 0
+ return destroyer(stream, reading, writing, function (err) {
+ if (!error) error = err
+ if (err) destroys.forEach(call)
+ if (reading) return
+ destroys.forEach(call)
+ callback(error)
+ })
+ })
+
+ return streams.reduce(pipe)
+}
+
+var noop = function() {};
+
+var isRequest = function(stream) {
+ return stream.setHeader && typeof stream.abort === 'function';
+};
+
+var isChildProcess = function(stream) {
+ return stream.stdio && Array.isArray(stream.stdio) && stream.stdio.length === 3
+};
+
+var eos = function(stream, opts, callback) {
+ if (typeof opts === 'function') return eos(stream, null, opts);
+ if (!opts) opts = {};
+
+ callback = callback || noop
+
+ var ws = stream._writableState;
+ var rs = stream._readableState;
+ var readable = opts.readable || (opts.readable !== false && stream.readable);
+ var writable = opts.writable || (opts.writable !== false && stream.writable);
+
+ var onlegacyfinish = function() {
+ if (!stream.writable) onfinish();
+ };
+
+ var onfinish = function() {
+ writable = false;
+ if (!readable) callback();
+ };
+
+ var onend = function() {
+ readable = false;
+ if (!writable) callback();
+ };
+
+ var onexit = function(exitCode) {
+ callback(exitCode ? new Error('exited with error code: ' + exitCode) : null);
+ };
+
+ var onclose = function() {
+ if (readable && !(rs && rs.ended)) return callback(new Error('premature close'));
+ if (writable && !(ws && ws.ended)) return callback(new Error('premature close'));
+ };
+
+ var onrequest = function() {
+ stream.req.on('finish', onfinish);
+ };
+
+ if (isRequest(stream)) {
+ stream.on('complete', onfinish);
+ stream.on('abort', onclose);
+ if (stream.req) onrequest();
+ else stream.on('request', onrequest);
+ } else if (writable && !ws) { // legacy streams
+ stream.on('end', onlegacyfinish);
+ stream.on('close', onlegacyfinish);
+ }
+
+ if (isChildProcess(stream)) stream.on('exit', onexit);
+
+ stream.on('end', onend);
+ stream.on('finish', onfinish);
+ if (opts.error !== false) stream.on('error', callback);
+ stream.on('close', onclose);
+ return function() {
+
+ };
+};
+
+module.exports = pump
diff --git a/deps/platform_tools/lib/tar/tar-stream.js b/deps/platform_tools/lib/tar/tar-stream.js
new file mode 100644
index 00000000000000..63b7e837fb8a8d
--- /dev/null
+++ b/deps/platform_tools/lib/tar/tar-stream.js
@@ -0,0 +1,504 @@
+var util = require('util')
+var bl = BufferList
+
+var Writable = require('stream').Writable
+var PassThrough = require('stream').PassThrough
+
+var noop = function () {}
+
+var overflow = function (size) {
+ size &= 511
+ return size && 512 - size
+}
+
+var emptyStream = function (self, offset) {
+ var s = new Source(self, offset)
+ s.end()
+ return s
+}
+
+var mixinPax = function (header, pax) {
+ if (pax.path) header.name = pax.path
+ if (pax.linkpath) header.linkname = pax.linkpath
+ header.pax = pax
+ return header
+}
+
+var Source = function (self, offset) {
+ this._parent = self
+ this.offset = offset
+ PassThrough.call(this)
+}
+
+util.inherits(Source, PassThrough)
+
+Source.prototype.destroy = function (err) {
+ this._parent.destroy(err)
+}
+
+var Extract = function (opts) {
+ if (!(this instanceof Extract)) return new Extract(opts)
+ Writable.call(this, opts)
+
+ this._offset = 0
+ this._buffer = bl()
+ this._missing = 0
+ this._onparse = noop
+ this._header = null
+ this._stream = null
+ this._overflow = null
+ this._cb = null
+ this._locked = false
+ this._destroyed = false
+ this._pax = null
+ this._paxGlobal = null
+ this._gnuLongPath = null
+ this._gnuLongLinkPath = null
+
+ var self = this
+ var b = self._buffer
+
+ var oncontinue = function () {
+ self._continue()
+ }
+
+ var onunlock = function (err) {
+ self._locked = false
+ if (err) return self.destroy(err)
+ if (!self._stream) oncontinue()
+ }
+
+ var onstreamend = function () {
+ self._stream = null
+ var drain = overflow(self._header.size)
+ if (drain) self._parse(drain, ondrain)
+ else self._parse(512, onheader)
+ if (!self._locked) oncontinue()
+ }
+
+ var ondrain = function () {
+ self._buffer.consume(overflow(self._header.size))
+ self._parse(512, onheader)
+ oncontinue()
+ }
+
+ var onpaxglobalheader = function () {
+ var size = self._header.size
+ self._paxGlobal = headers.decodePax(b.slice(0, size))
+ b.consume(size)
+ onstreamend()
+ }
+
+ var onpaxheader = function () {
+ var size = self._header.size
+ self._pax = headers.decodePax(b.slice(0, size))
+ if (self._paxGlobal) self._pax = Object.assign(self._paxGlobal, self._pax)
+ b.consume(size)
+ onstreamend()
+ }
+
+ var ongnulongpath = function () {
+ var size = self._header.size
+ this._gnuLongPath = headers.decodeLongPath(b.slice(0, size))
+ b.consume(size)
+ onstreamend()
+ }
+
+ var ongnulonglinkpath = function () {
+ var size = self._header.size
+ this._gnuLongLinkPath = headers.decodeLongPath(b.slice(0, size))
+ b.consume(size)
+ onstreamend()
+ }
+
+ var onheader = function () {
+ var offset = self._offset
+ var header
+ try {
+ header = self._header = headers.decode(b.slice(0, 512))
+ } catch (err) {
+ self.emit('error', err)
+ }
+ b.consume(512)
+
+ if (!header) {
+ self._parse(512, onheader)
+ oncontinue()
+ return
+ }
+ if (header.type === 'gnu-long-path') {
+ self._parse(header.size, ongnulongpath)
+ oncontinue()
+ return
+ }
+ if (header.type === 'gnu-long-link-path') {
+ self._parse(header.size, ongnulonglinkpath)
+ oncontinue()
+ return
+ }
+ if (header.type === 'pax-global-header') {
+ self._parse(header.size, onpaxglobalheader)
+ oncontinue()
+ return
+ }
+ if (header.type === 'pax-header') {
+ self._parse(header.size, onpaxheader)
+ oncontinue()
+ return
+ }
+
+ if (self._gnuLongPath) {
+ header.name = self._gnuLongPath
+ self._gnuLongPath = null
+ }
+
+ if (self._gnuLongLinkPath) {
+ header.linkname = self._gnuLongLinkPath
+ self._gnuLongLinkPath = null
+ }
+
+ if (self._pax) {
+ self._header = header = mixinPax(header, self._pax)
+ self._pax = null
+ }
+
+ self._locked = true
+
+ if (!header.size) {
+ self._parse(512, onheader)
+ self.emit('entry', header, emptyStream(self, offset), onunlock)
+ return
+ }
+
+ self._stream = new Source(self, offset)
+
+ self.emit('entry', header, self._stream, onunlock)
+ self._parse(header.size, onstreamend)
+ oncontinue()
+ }
+
+ this._parse(512, onheader)
+}
+
+util.inherits(Extract, Writable)
+
+Extract.prototype.destroy = function (err) {
+ if (this._destroyed) return
+ this._destroyed = true
+
+ if (err) this.emit('error', err)
+ this.emit('close')
+ if (this._stream) this._stream.emit('close')
+}
+
+Extract.prototype._parse = function (size, onparse) {
+ if (this._destroyed) return
+ this._offset += size
+ this._missing = size
+ this._onparse = onparse
+}
+
+Extract.prototype._continue = function () {
+ if (this._destroyed) return
+ var cb = this._cb
+ this._cb = noop
+ if (this._overflow) this._write(this._overflow, undefined, cb)
+ else cb()
+}
+
+Extract.prototype._write = function (data, enc, cb) {
+ if (this._destroyed) return
+
+ var s = this._stream
+ var b = this._buffer
+ var missing = this._missing
+
+ // we do not reach end-of-chunk now. just forward it
+
+ if (data.length < missing) {
+ this._missing -= data.length
+ this._overflow = null
+ if (s) return s.write(data, cb)
+ b.append(data)
+ return cb()
+ }
+
+ // end-of-chunk. the parser should call cb.
+
+ this._cb = cb
+ this._missing = 0
+
+ var overflow = null
+ if (data.length > missing) {
+ overflow = data.slice(missing)
+ data = data.slice(0, missing)
+ }
+
+ if (s) s.end(data)
+ else b.append(data)
+
+ this._overflow = overflow
+ this._onparse()
+}
+
+var DuplexStream = require('stream').Duplex
+ , util = require('util')
+
+
+function BufferList (callback) {
+ if (!(this instanceof BufferList))
+ return new BufferList(callback)
+
+ this._bufs = []
+ this.length = 0
+
+ DuplexStream.call(this)
+}
+util.inherits(BufferList, DuplexStream)
+
+
+BufferList.prototype._offset = function _offset (offset) {
+ var tot = 0, i = 0, _t
+ for (; i < this._bufs.length; i++) {
+ _t = tot + this._bufs[i].length
+ if (offset < _t)
+ return [ i, offset - tot ]
+ tot = _t
+ }
+}
+
+
+BufferList.prototype.append = function append (buf) {
+ var i = 0
+ , newBuf
+
+ if (buf != null) {
+ // coerce number arguments to strings, since Buffer(number) does
+ // uninitialized memory allocation
+ if (typeof buf == 'number')
+ buf = buf.toString()
+
+ newBuf = Buffer.isBuffer(buf) ? buf : new Buffer(buf)
+ this._bufs.push(newBuf)
+ this.length += newBuf.length
+ }
+
+ return this
+}
+
+
+BufferList.prototype.slice = function slice (start, end) {
+ return this.copy(null, 0, start, end)
+}
+
+
+BufferList.prototype.copy = function copy (dst, dstStart, srcStart, srcEnd) {
+ if (typeof srcStart != 'number' || srcStart < 0)
+ srcStart = 0
+ if (typeof srcEnd != 'number' || srcEnd > this.length)
+ srcEnd = this.length
+ if (srcStart >= this.length)
+ return dst || new Buffer(0)
+ if (srcEnd <= 0)
+ return dst || new Buffer(0)
+
+ var copy = !!dst
+ , off = this._offset(srcStart)
+ , len = srcEnd - srcStart
+ , bytes = len
+ , bufoff = (copy && dstStart) || 0
+ , start = off[1]
+ , l
+ , i
+
+ // copy/slice everything
+ if (srcStart === 0 && srcEnd == this.length) {
+ if (!copy) // slice, just return a full concat
+ return Buffer.concat(this._bufs)
+
+ // copy, need to copy individual buffers
+ for (i = 0; i < this._bufs.length; i++) {
+ this._bufs[i].copy(dst, bufoff)
+ bufoff += this._bufs[i].length
+ }
+
+ return dst
+ }
+
+ // easy, cheap case where it's a subset of one of the buffers
+ if (bytes <= this._bufs[off[0]].length - start) {
+ return copy
+ ? this._bufs[off[0]].copy(dst, dstStart, start, start + bytes)
+ : this._bufs[off[0]].slice(start, start + bytes)
+ }
+
+ if (!copy) // a slice, we need something to copy in to
+ dst = new Buffer(len)
+
+ for (i = off[0]; i < this._bufs.length; i++) {
+ l = this._bufs[i].length - start
+
+ if (bytes > l) {
+ this._bufs[i].copy(dst, bufoff, start)
+ } else {
+ this._bufs[i].copy(dst, bufoff, start, start + bytes)
+ break
+ }
+
+ bufoff += l
+ bytes -= l
+
+ if (start)
+ start = 0
+ }
+
+ return dst
+}
+
+BufferList.prototype.consume = function consume (bytes) {
+ while (this._bufs.length) {
+ if (bytes >= this._bufs[0].length) {
+ bytes -= this._bufs[0].length
+ this.length -= this._bufs[0].length
+ this._bufs.shift()
+ } else {
+ this._bufs[0] = this._bufs[0].slice(bytes)
+ this.length -= bytes
+ break
+ }
+ }
+ return this
+}
+
+
+var ZEROS = '0000000000000000000'
+var SEVENS = '7777777777777777777'
+var ZERO_OFFSET = '0'.charCodeAt(0)
+var USTAR = 'ustar\x0000'
+var MASK = parseInt('7777', 8)
+
+var clamp = function (index, len, defaultValue) {
+ if (typeof index !== 'number') return defaultValue
+ index = ~~index // Coerce to integer.
+ if (index >= len) return len
+ if (index >= 0) return index
+ index += len
+ if (index >= 0) return index
+ return 0
+}
+
+var toType = function (flag) {
+ switch (flag) {
+ case 0:
+ return 'file'
+ case 1:
+ return 'link'
+ case 2:
+ return 'symlink'
+ case 3:
+ return 'character-device'
+ case 4:
+ return 'block-device'
+ case 5:
+ return 'directory'
+ case 6:
+ return 'fifo'
+ case 7:
+ return 'contiguous-file'
+ case 72:
+ return 'pax-header'
+ case 55:
+ return 'pax-global-header'
+ case 27:
+ return 'gnu-long-link-path'
+ case 28:
+ case 30:
+ return 'gnu-long-path'
+ }
+
+ return null
+}
+
+
+var indexOf = function (block, num, offset, end) {
+ for (; offset < end; offset++) {
+ if (block[offset] === num) return offset
+ }
+ return end
+}
+
+var cksum = function (block) {
+ var sum = 8 * 32
+ for (var i = 0; i < 148; i++) sum += block[i]
+ for (var j = 156; j < 512; j++) sum += block[j]
+ return sum
+}
+
+
+var decodeOct = function (val, offset) {
+ // If prefixed with 0x80 then parse as a base-256 integer
+ if (val[offset] & 0x80) {
+ return parse256(val.slice(offset, offset + 8))
+ } else {
+ // Older versions of tar can prefix with spaces
+ while (offset < val.length && val[offset] === 32) offset++
+ var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)
+ while (offset < end && val[offset] === 0) offset++
+ if (end === offset) return 0
+ return parseInt(val.slice(offset, end).toString(), 8)
+ }
+}
+
+var decodeStr = function (val, offset, length) {
+ return val.slice(offset, indexOf(val, 0, offset, offset + length)).toString()
+}
+
+const headers = {}
+
+headers.decode = function (buf) {
+ var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET
+
+ var name = decodeStr(buf, 0, 100)
+ var mode = decodeOct(buf, 100)
+ var uid = decodeOct(buf, 108)
+ var gid = decodeOct(buf, 116)
+ var size = decodeOct(buf, 124)
+ var mtime = decodeOct(buf, 136)
+ var type = toType(typeflag)
+ var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100)
+ var uname = decodeStr(buf, 265, 32)
+ var gname = decodeStr(buf, 297, 32)
+ var devmajor = decodeOct(buf, 329)
+ var devminor = decodeOct(buf, 337)
+
+ if (buf[345]) name = decodeStr(buf, 345, 155) + '/' + name
+
+ // to support old tar versions that use trailing / to indicate dirs
+ if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5
+
+ var c = cksum(buf)
+
+ // checksum is still initial value if header was null.
+ if (c === 8 * 32) return null
+
+ // valid checksum
+ if (c !== decodeOct(buf, 148)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?')
+
+ return {
+ name: name,
+ mode: mode,
+ uid: uid,
+ gid: gid,
+ size: size,
+ mtime: new Date(1000 * mtime),
+ type: type,
+ linkname: linkname,
+ uname: uname,
+ gname: gname,
+ devmajor: devmajor,
+ devminor: devminor
+ }
+}
+
+
+module.exports.extract = Extract
diff --git a/deps/platform_tools/package.json b/deps/platform_tools/package.json
new file mode 100644
index 00000000000000..08aebe03ac4175
--- /dev/null
+++ b/deps/platform_tools/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "platform-tools",
+ "version": "0.3.3",
+ "description": "A toolchain to build and compile native dependencies with and for Node.",
+ "main": "index.js",
+ "scripts": {
+ "test": "node test/test-runner.js",
+ "doc": "jsdoc2md lib/platform_tools.js > doc/API.md && node -e \"const fs = require('fs');fs.writeFile('README.md', fs.readFileSync('doc/README.md'));['doc/README.md', 'doc/API.md', 'doc/LICENSE.md'].forEach(function(el){fs.appendFileSync('README.md',fs.readFileSync(el))})\"",
+ "smoke-deps": "git clone -b feature/platform-tools --depth=1 https://github.com/eljefedelrodeodeljefe/node test/fixtures/sources/smoke/node",
+ "smoke-node": "cd test/fixtures/sources/smoke/node && ./configure --no-target-type && make -j8 > pt_debug_log.txt && cd ../../../../../ && node test/smoke/node.js",
+ "smoke": "npm run smoke-deps && npm run smoke-node"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/eljefedelrodeodeljefe/platform-tools.git"
+ },
+ "keywords": [
+ "compiler",
+ "toolchain",
+ "linker",
+ "c",
+ "c++",
+ "cpp",
+ "native",
+ "addons"
+ ],
+ "author": "Robert Jefe Lindstaedt ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/eljefedelrodeodeljefe/platform-tools/issues"
+ },
+ "homepage": "https://github.com/eljefedelrodeodeljefe/platform-tools#readme",
+ "devDependencies": {
+ "jsdoc-to-markdown": "^1.3.6",
+ "nan": "^2.3.5",
+ "tape": "^4.6.0"
+ },
+ "dependencies": {}
+}
diff --git a/lib/internal/module.js b/lib/internal/module.js
index a12af12f3e3d7e..3934fb0570c35d 100644
--- a/lib/internal/module.js
+++ b/lib/internal/module.js
@@ -54,7 +54,7 @@ function stripBOM(content) {
exports.builtinLibs = ['assert', 'buffer', 'child_process', 'cluster',
'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net',
'os', 'path', 'punycode', 'querystring', 'readline', 'repl', 'stream',
- 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib'];
+ 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib', 'platform_tools'];
function addBuiltinLibsToObject(object) {
// Make built-in modules available directly (loaded lazily).
diff --git a/lib/platform_tools.js b/lib/platform_tools.js
new file mode 100644
index 00000000000000..7197f532e056db
--- /dev/null
+++ b/lib/platform_tools.js
@@ -0,0 +1,2 @@
+'use strict';
+module.exports = require('../deps/platform_tools');
diff --git a/node.gyp b/node.gyp
index c3f591351d52ce..90a00f8d952e58 100644
--- a/node.gyp
+++ b/node.gyp
@@ -47,6 +47,7 @@
'lib/path.js',
'lib/process.js',
'lib/punycode.js',
+ 'lib/platform_tools.js',
'lib/querystring.js',
'lib/readline.js',
'lib/repl.js',
diff --git a/vcbuild.bat b/vcbuild.bat
index ee5b4c8a17df08..5b98181633f610 100644
--- a/vcbuild.bat
+++ b/vcbuild.bat
@@ -20,6 +20,7 @@ set noprojgen=
set nobuild=
set nosign=
set nosnapshot=
+set notargettype=
set test_args=
set package=
set msi=
@@ -55,6 +56,7 @@ if /i "%1"=="nosign" set nosign=1&goto arg-ok
if /i "%1"=="nosnapshot" set nosnapshot=1&goto arg-ok
if /i "%1"=="noetw" set noetw=1&goto arg-ok
if /i "%1"=="noperfctr" set noperfctr=1&goto arg-ok
+if /i "%1"=="notargettype" set notargettype=1&goto arg-ok
if /i "%1"=="licensertf" set licensertf=1&goto arg-ok
if /i "%1"=="test" set test_args=%test_args% addons doctool known_issues message parallel sequential -J&set jslint=1&set build_addons=1&goto arg-ok
if /i "%1"=="test-ci" set test_args=%test_args% %test_ci_args% -p tap --logfile test.tap addons doctool known_issues message sequential parallel&set build_addons=1&goto arg-ok