diff --git a/.eslintrc.yaml b/.eslintrc.yaml
new file mode 100644
index 0000000000..f808ce2d9a
--- /dev/null
+++ b/.eslintrc.yaml
@@ -0,0 +1,6 @@
+---
+  env:
+    node: true
+    es6: true
+  rules:
+    no-unused-vars: error
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..dbd053a90b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,26 @@
+<!--
+Thank you for reporting an issue. The more information you can give us, the
+better the chance we can fix your problem.
+
+This issue tracker is for issues with node-gyp,
+if you have an issue installing a specific module, please file an issue on
+that module's issue tracker (`npm issues modulename`).
+-->
+
+* **Node Version**: <!-- `node -v` and `npm -v` -->
+* **Platform**: <!-- `uname -a` (UNIX), or `systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type"` (Windows) -->
+* **Compiler**: <!-- `cc -v` (UNIX) or `msbuild /version & cl` (Windows) -->
+* **Module**: <!-- what you tried to build/install -->
+
+<details><summary>Verbose output (from npm or node-gyp):</summary>
+
+<!-- Paste your log between the backticks. Contents of npm-debug.log or verbose build output -->
+
+```
+
+```
+
+</details>
+
+<!-- Any further details -->
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000000..10156d89af
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,17 @@
+<!--
+Thank you for your pull request. Please review the below requirements.
+
+Contributor guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md
+-->
+
+##### Checklist
+<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
+
+- [ ] `npm install && npm test` passes
+- [ ] tests are included <!-- Bug fixes and new features should include tests -->
+- [ ] documentation is changed or added
+- [ ] commit message follows [commit guidelines](https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#commit-message-guidelines)
+
+##### Description of change
+<!-- Provide a description of the change -->
+
diff --git a/.jshintrc b/.jshintrc
index 52475ba2e6..4b8521dac0 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,7 +1,7 @@
 {
   "asi": true,
   "laxcomma": true,
-  "es5": true,
+  "esversion": 6,
   "node": true,
   "strict": false
 }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f7e66f8d0..33bbfad5de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,54 @@
+v3.8.0 2018-08-09
+=================
+
+* [[`c5929cb4fe`](https://github.com/nodejs/node-gyp/commit/c5929cb4fe)] - **doc**: update Xcode preferences tab name. (Ivan Daniluk) [#1330](https://github.com/nodejs/node-gyp/pull/1330)
+* [[`8b488da8b9`](https://github.com/nodejs/node-gyp/commit/8b488da8b9)] - **doc**: update link to commit guidelines (Jonas Hermsmeier) [#1456](https://github.com/nodejs/node-gyp/pull/1456)
+* [[`b4fe8c16f9`](https://github.com/nodejs/node-gyp/commit/b4fe8c16f9)] - **doc**: fix visual studio links (Bartosz Sosnowski) [#1490](https://github.com/nodejs/node-gyp/pull/1490)
+* [[`536759c7e9`](https://github.com/nodejs/node-gyp/commit/536759c7e9)] - **configure**: use sys.version\_info to get python version (Yang Guo) [#1504](https://github.com/nodejs/node-gyp/pull/1504)
+* [[`94c39c604e`](https://github.com/nodejs/node-gyp/commit/94c39c604e)] - **gyp**: fix ninja build failure (GYP patch) (Daniel Bevenius) [nodejs/node#12484](https://github.com/nodejs/node/pull/12484)
+* [[`e8ea74e0fa`](https://github.com/nodejs/node-gyp/commit/e8ea74e0fa)] - **tools**: patch gyp to avoid xcrun errors (Ujjwal Sharma) [nodejs/node#21520](https://github.com/nodejs/node/pull/21520)
+* [[`ea9aff44f2`](https://github.com/nodejs/node-gyp/commit/ea9aff44f2)] - **tools**: fix "the the" typos in comments (Masashi Hirano) [nodejs/node#20716](https://github.com/nodejs/node/pull/20716)
+* [[`207e5aa4fd`](https://github.com/nodejs/node-gyp/commit/207e5aa4fd)] - **gyp**: implement LD/LDXX for ninja and FIPS (Sam Roberts) 
+* [[`b416c5f4b7`](https://github.com/nodejs/node-gyp/commit/b416c5f4b7)] - **gyp**: enable cctest to use objects (gyp part) (Daniel Bevenius) [nodejs/node#12450](https://github.com/nodejs/node/pull/12450)
+* [[`40692d016b`](https://github.com/nodejs/node-gyp/commit/40692d016b)] - **gyp**: add compile\_commands.json gyp generator (Ben Noordhuis) [nodejs/node#12450](https://github.com/nodejs/node/pull/12450)
+* [[`fc3c4e2b10`](https://github.com/nodejs/node-gyp/commit/fc3c4e2b10)] - **gyp**: float gyp patch for long filenames (Anna Henningsen) [nodejs/node#7963](https://github.com/nodejs/node/pull/7963)
+* [[`8aedbfdef6`](https://github.com/nodejs/node-gyp/commit/8aedbfdef6)] - **gyp**: backport GYP fix to fix AIX shared suffix (Stewart Addison) 
+* [[`6cd84b84fc`](https://github.com/nodejs/node-gyp/commit/6cd84b84fc)] - **test**: formatting and minor fixes for execFileSync replacement (Rod Vagg) [#1521](https://github.com/nodejs/node-gyp/pull/1521)
+* [[`60e421363f`](https://github.com/nodejs/node-gyp/commit/60e421363f)] - **test**: added test/processExecSync.js for when execFileSync is not available. (Rohit Hazra) [#1492](https://github.com/nodejs/node-gyp/pull/1492)
+* [[`969447c5bd`](https://github.com/nodejs/node-gyp/commit/969447c5bd)] - **deps**: bump request to 2.8.7, fixes heok/hawk issues (Rohit Hazra) [#1492](https://github.com/nodejs/node-gyp/pull/1492)
+* [[`340403ccfe`](https://github.com/nodejs/node-gyp/commit/340403ccfe)] - **win**: improve parsing of SDK version (Alessandro Vergani) [#1516](https://github.com/nodejs/node-gyp/pull/1516)
+
+v3.7.0 2018-06-08
+=================
+
+* [[`84cea7b30d`](https://github.com/nodejs/node-gyp/commit/84cea7b30d)] - Remove unused gyp test scripts. (Ben Noordhuis) [#1458](https://github.com/nodejs/node-gyp/pull/1458)
+* [[`0540e4ec63`](https://github.com/nodejs/node-gyp/commit/0540e4ec63)] - **gyp**: escape spaces in filenames in make generator (Jeff Senn) [#1436](https://github.com/nodejs/node-gyp/pull/1436)
+* [[`88fc6fa0ec`](https://github.com/nodejs/node-gyp/commit/88fc6fa0ec)] - Drop dependency on minimatch. (Brian Woodward) [#1158](https://github.com/nodejs/node-gyp/pull/1158)
+* [[`1e203c5148`](https://github.com/nodejs/node-gyp/commit/1e203c5148)] - Fix include path when pointing to Node.js source (Richard Lau) [#1055](https://github.com/nodejs/node-gyp/pull/1055)
+* [[`53d8cb967c`](https://github.com/nodejs/node-gyp/commit/53d8cb967c)] - Prefix build targets with /t: on Windows (Natalie Wolfe) [#1164](https://github.com/nodejs/node-gyp/pull/1164)
+* [[`53a5f8ff38`](https://github.com/nodejs/node-gyp/commit/53a5f8ff38)] - **gyp**: add support for .mm files to msvs generator (Julien Racle) [#1167](https://github.com/nodejs/node-gyp/pull/1167)
+* [[`dd8561e528`](https://github.com/nodejs/node-gyp/commit/dd8561e528)] - **zos**: don't use universal-new-lines mode (John Barboza) [#1451](https://github.com/nodejs/node-gyp/pull/1451)
+* [[`e5a69010ed`](https://github.com/nodejs/node-gyp/commit/e5a69010ed)] - **zos**: add search locations for libnode.x (John Barboza) [#1451](https://github.com/nodejs/node-gyp/pull/1451)
+* [[`79febace53`](https://github.com/nodejs/node-gyp/commit/79febace53)] - **doc**: update macOS information in README (Josh Parnham) [#1323](https://github.com/nodejs/node-gyp/pull/1323)
+* [[`9425448945`](https://github.com/nodejs/node-gyp/commit/9425448945)] - **gyp**: don't print xcodebuild not found errors (Gibson Fahnestock) [#1370](https://github.com/nodejs/node-gyp/pull/1370)
+* [[`6f1286f5b2`](https://github.com/nodejs/node-gyp/commit/6f1286f5b2)] - Fix infinite install loop. (Ben Noordhuis) [#1384](https://github.com/nodejs/node-gyp/pull/1384)
+* [[`2580b9139e`](https://github.com/nodejs/node-gyp/commit/2580b9139e)] - Update `--nodedir` description in README. (Ben Noordhuis) [#1372](https://github.com/nodejs/node-gyp/pull/1372)
+* [[`a61360391a`](https://github.com/nodejs/node-gyp/commit/a61360391a)] - Update README with another way to install on windows (JeffAtDeere) [#1352](https://github.com/nodejs/node-gyp/pull/1352)
+* [[`47496bf6dc`](https://github.com/nodejs/node-gyp/commit/47496bf6dc)] - Fix IndexError when parsing GYP files. (Ben Noordhuis) [#1267](https://github.com/nodejs/node-gyp/pull/1267)
+* [[`b2024dee7b`](https://github.com/nodejs/node-gyp/commit/b2024dee7b)] - **zos**: support platform (John Barboza) [#1276](https://github.com/nodejs/node-gyp/pull/1276)
+* [[`90d86512f4`](https://github.com/nodejs/node-gyp/commit/90d86512f4)] - **win**: run PS with `-NoProfile` (Refael Ackermann) [#1292](https://github.com/nodejs/node-gyp/pull/1292)
+* [[`2da5f86ef7`](https://github.com/nodejs/node-gyp/commit/2da5f86ef7)] - **doc**: add github PR and Issue templates (Gibson Fahnestock) [#1228](https://github.com/nodejs/node-gyp/pull/1228)
+* [[`a46a770d68`](https://github.com/nodejs/node-gyp/commit/a46a770d68)] - **doc**: update proposed DCO and CoC (Mikeal Rogers) [#1229](https://github.com/nodejs/node-gyp/pull/1229)
+* [[`7e803d58e0`](https://github.com/nodejs/node-gyp/commit/7e803d58e0)] - **doc**: headerify the Install instructions (Nick Schonning) [#1225](https://github.com/nodejs/node-gyp/pull/1225)
+* [[`f27599193a`](https://github.com/nodejs/node-gyp/commit/f27599193a)] - **gyp**: update xml string encoding conversion (Liu Chao) [#1203](https://github.com/nodejs/node-gyp/pull/1203)
+* [[`0a07e481f7`](https://github.com/nodejs/node-gyp/commit/0a07e481f7)] - **configure**: don't set ensure if tarball is set (Gibson Fahnestock) [#1220](https://github.com/nodejs/node-gyp/pull/1220)
+
+v3.6.3 2018-06-08
+=================
+
+* [[`90cd2e8da9`](https://github.com/nodejs/node-gyp/commit/90cd2e8da9)] - **gyp**: fix regex to match multi-digit versions (Jonas Hermsmeier) [#1455](https://github.com/nodejs/node-gyp/pull/1455)
+* [[`7900122337`](https://github.com/nodejs/node-gyp/commit/7900122337)] - deps: pin `request` version range (Refael Ackerman) [#1300](https://github.com/nodejs/node-gyp/pull/1300)
+
 v3.6.2 2017-06-01
 =================
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..f48786bd84
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# Contributing to node-gyp
+
+## Code of Conduct
+
+Please read the
+[Code of Conduct](https://github.com/nodejs/TSC/blob/master/CODE_OF_CONDUCT.md)
+which explains the minimum behavior expectations for node-gyp contributors.
+
+<a id="developers-certificate-of-origin"></a>
+## Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+* (a) The contribution was created in whole or in part by me and I
+  have the right to submit it under the open source license
+  indicated in the file; or
+
+* (b) The contribution is based upon previous work that, to the best
+  of my knowledge, is covered under an appropriate open source
+  license and I have the right under that license to submit that
+  work with modifications, whether created in whole or in part
+  by me, under the same open source license (unless I am
+  permitted to submit under a different license), as indicated
+  in the file; or
+
+* (c) The contribution was provided directly to me by some other
+  person who certified (a), (b) or (c) and I have not modified
+  it.
+
+* (d) I understand and agree that this project and the contribution
+  are public and that a record of the contribution (including all
+  personal information I submit with it, including my sign-off) is
+  maintained indefinitely and may be redistributed consistent with
+  this project or the open source license(s) involved.
diff --git a/README.md b/README.md
index 03db320900..f378616964 100644
--- a/README.md
+++ b/README.md
@@ -1,28 +1,21 @@
-node-gyp
-=========
-### Node.js native addon build tool
+# `node-gyp` - Node.js native addon build tool
 
 `node-gyp` is a cross-platform command-line tool written in Node.js for compiling
-native addon modules for Node.js.  It bundles the [gyp](https://gyp.gsrc.io)
+native addon modules for Node.js. It bundles the [gyp](https://gyp.gsrc.io)
 project used by the Chromium team and takes away the pain of dealing with the
-various differences in build platforms. It is the replacement to the `node-waf`
-program which is removed for node `v0.8`. If you have a native addon for node that
-still has a `wscript` file, then you should definitely add a `binding.gyp` file
-to support the latest versions of node.
+various differences in build platforms.
 
-Multiple target versions of node are supported (i.e. `0.8`, ..., `4`, `5`, `6`,
-etc.), regardless of what version of node is actually installed on your system
+Multiple target versions of Node.js are supported (i.e. `0.8`, ..., `4`, `5`, `6`,
+etc.), regardless of what version of Node.js is actually installed on your system
 (`node-gyp` downloads the necessary development files or headers for the target version).
 
-#### Features:
+## Features
 
  * Easy to use, consistent interface
  * Same commands to build your module on every platform
- * Supports multiple target versions of Node
+ * Supports multiple target versions of Node.js
 
-
-Installation
-------------
+## Installation
 
 You can install with `npm`:
 
@@ -32,29 +25,35 @@ $ npm install -g node-gyp
 
 You will also need to install:
 
-  * On Unix:
-    * `python` (`v2.7` recommended, `v3.x.x` is __*not*__ supported)
-    * `make`
-    * A proper C/C++ compiler toolchain, like [GCC](https://gcc.gnu.org)
-  * On Mac OS X:
-    * `python` (`v2.7` recommended, `v3.x.x` is __*not*__ supported) (already installed on Mac OS X)
-    * [Xcode](https://developer.apple.com/xcode/download/)
-      * You also need to install the `Command Line Tools` via Xcode. You can find this under the menu `Xcode -> Preferences -> Downloads`
-      * This step will install `gcc` and the related toolchain containing `make`
-  * On Windows:
-    * Option 1: Install all the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) using `npm install --global --production windows-build-tools` from an elevated PowerShell or CMD.exe (run as Administrator).
-    * Option 2: Install tools and configuration manually:
-      * Visual C++ Build Environment:
-        * Option 1: Install [Visual C++ Build Tools](http://landinghub.visualstudio.com/visual-cpp-build-tools) using the **Default Install** option.
+### On Unix
+
+   * `python` (`v2.7` recommended, `v3.x.x` is __*not*__ supported)
+   * `make`
+   * A proper C/C++ compiler toolchain, like [GCC](https://gcc.gnu.org)
+
+### On macOS
+
+   * `python` (`v2.7` recommended, `v3.x.x` is __*not*__ supported) (already installed on macOS)
+   * [Xcode](https://developer.apple.com/xcode/download/)
+     * You also need to install the `Command Line Tools` via Xcode. You can find this under the menu `Xcode -> Preferences -> Locations` (or by running `xcode-select --install` in your Terminal)
+       * This step will install `gcc` and the related toolchain containing `make`
 
-        * Option 2: Install [Visual Studio 2015](https://www.visualstudio.com/products/visual-studio-community-vs) (or modify an existing installation) and select *Common Tools for Visual C++* during setup. This also works with the free Community and Express for Desktop editions.
+### On Windows
 
-        > :bulb: [Windows Vista / 7 only] requires [.NET Framework 4.5.1](http://www.microsoft.com/en-us/download/details.aspx?id=40773)
+#### Option 1
 
-      * Install [Python 2.7](https://www.python.org/downloads/) (`v3.x.x` is not supported), and run `npm config set python python2.7` (or see below for further instructions on specifying the proper Python version and path.)
-      * Launch cmd, `npm config set msvs_version 2015`
+Install all the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) using `npm install --global --production windows-build-tools` from an elevated PowerShell or CMD.exe (run as Administrator).
 
-    If the above steps didn't work for you, please visit [Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules) for additional tips.
+#### Option 2
+
+Install tools and configuration manually:
+   * Install Visual C++ Build Environment: [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools)
+   (using "Visual C++ build tools" workload) or [Visual Studio 2017 Community](https://visualstudio.microsoft.com/pl/thank-you-downloading-visual-studio/?sku=Community)
+   (using the "Desktop development with C++" workload)
+   * Install [Python 2.7](https://www.python.org/downloads/) (`v3.x.x` is not supported), and run `npm config set python python2.7` (or see below for further instructions on specifying the proper Python version and path.)
+   * Launch cmd, `npm config set msvs_version 2017`
+
+   If the above steps didn't work for you, please visit [Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules) for additional tips.
 
 If you have multiple Python versions installed, you can identify which Python
 version `node-gyp` uses by setting the '--python' variable:
@@ -63,7 +62,7 @@ version `node-gyp` uses by setting the '--python' variable:
 $ node-gyp --python /path/to/python2.7
 ```
 
-If `node-gyp` is called by way of `npm` *and* you have multiple versions of
+If `node-gyp` is called by way of `npm`, *and* you have multiple versions of
 Python installed, then you can set `npm`'s 'python' config key to the appropriate
 value:
 
@@ -71,12 +70,7 @@ value:
 $ npm config set python /path/to/executable/python2.7
 ```
 
-Note that OS X is just a flavour of Unix and so needs `python`, `make`, and C/C++.
-An easy way to obtain these is to install XCode from Apple,
-and then use it to install the command line tools (under Preferences -> Downloads).
-
-How to Use
-----------
+## How to Use
 
 To compile your native addon, first go to its root directory:
 
@@ -97,33 +91,30 @@ needs to be added (not needed when run by npm as configured above):
 $ node-gyp configure --msvs_version=2015
 ```
 
-__Note__: The `configure` step looks for the `binding.gyp` file in the current
-directory to process. See below for instructions on creating the `binding.gyp` file.
+__Note__: The `configure` step looks for a `binding.gyp` file in the current
+directory to process. See below for instructions on creating a `binding.gyp` file.
 
 Now you will have either a `Makefile` (on Unix platforms) or a `vcxproj` file
-(on Windows) in the `build/` directory. Next invoke the `build` command:
+(on Windows) in the `build/` directory. Next, invoke the `build` command:
 
 ``` bash
 $ node-gyp build
 ```
 
 Now you have your compiled `.node` bindings file! The compiled bindings end up
-in `build/Debug/` or `build/Release/`, depending on the build mode. At this point
-you can require the `.node` file with Node and run your tests!
+in `build/Debug/` or `build/Release/`, depending on the build mode. At this point,
+you can require the `.node` file with Node.js and run your tests!
 
 __Note:__ To create a _Debug_ build of the bindings file, pass the `--debug` (or
-`-d`) switch when running either the `configure`, `build` or `rebuild` command.
+`-d`) switch when running either the `configure`, `build` or `rebuild` commands.
 
+## The `binding.gyp` file
 
-The "binding.gyp" file
-----------------------
+A `binding.gyp` file describes the configuration to build your module, in a
+JSON-like format. This file gets placed in the root of your package, alongside
+`package.json`.
 
-Previously when node had `node-waf` you had to write a `wscript` file. The
-replacement for that is the `binding.gyp` file, which describes the configuration
-to build your module in a JSON-like format. This file gets placed in the root of
-your package, alongside the `package.json` file.
-
-A barebones `gyp` file appropriate for building a node addon looks like:
+A barebones `gyp` file appropriate for building a Node.js addon could look like:
 
 ``` python
 {
@@ -145,8 +136,7 @@ Some additional resources for addons and writing `gyp` files:
  * [*"binding.gyp" files out in the wild* wiki page](https://github.com/nodejs/node-gyp/wiki/%22binding.gyp%22-files-out-in-the-wild)
 
 
-Commands
---------
+## Commands
 
 `node-gyp` responds to the following commands:
 
@@ -157,86 +147,74 @@ Commands
 | `clean`       | Removes the `build` directory if it exists
 | `configure`   | Generates project build files for the current platform
 | `rebuild`     | Runs `clean`, `configure` and `build` all in a row
-| `install`     | Installs node header files for the given version
-| `list`        | Lists the currently installed node header versions
-| `remove`      | Removes the node header files for the given version
+| `install`     | Installs Node.js header files for the given version
+| `list`        | Lists the currently installed Node.js header versions
+| `remove`      | Removes the Node.js header files for the given version
 
 
-Command Options
---------
+## Command Options
 
 `node-gyp` accepts the following command options:
 
 | **Command**                       | **Description**
 |:----------------------------------|:------------------------------------------
-| `-j n`, `--jobs n`                | Run make in parallel
-| `--target=v6.2.1`                 | Node version to build for (default=process.version)
+| `-j n`, `--jobs n`                | Run `make` in parallel
+| `--target=v6.2.1`                 | Node.js version to build for (default is `process.version`)
 | `--silly`, `--loglevel=silly`     | Log all progress to console
 | `--verbose`, `--loglevel=verbose` | Log most progress to console
 | `--silent`, `--loglevel=silent`   | Don't log anything to console
-| `debug`, `--debug`                | Make Debug build (default=Release)
+| `debug`, `--debug`                | Make Debug build (default is `Release`)
 | `--release`, `--no-debug`         | Make Release build
 | `-C $dir`, `--directory=$dir`     | Run command in different directory
-| `--make=$make`                    | Override make command (e.g. gmake)
+| `--make=$make`                    | Override `make` command (e.g. `gmake`)
 | `--thin=yes`                      | Enable thin static libraries
 | `--arch=$arch`                    | Set target architecture (e.g. ia32)
 | `--tarball=$path`                 | Get headers from a local tarball
-| `--devdir=$path`                  | SDK download directory (default=~/.node-gyp)
+| `--devdir=$path`                  | SDK download directory (default is OS cache directory)
 | `--ensure`                        | Don't reinstall headers if already present
 | `--dist-url=$url`                 | Download header tarball from custom URL
 | `--proxy=$url`                    | Set HTTP proxy for downloading header tarball
 | `--cafile=$cafile`                | Override default CA chain (to download tarball)
-| `--nodedir=$path`                 | Set the path to the node binary
-| `--python=$path`                  | Set path to the python (2) binary
-| `--msvs_version=$version`         | Set Visual Studio version (win)
-| `--solution=$solution`            | Set Visual Studio Solution version (win)
-
-
-Configuration
---------
-
-__`node-gyp` responds to environment variables or `npm` configuration__
-1. Environment variables take the form `npm_config_OPTION_NAME` for any of the 
- options listed above (dashes in option names should be replaced by underscores).
- These work also when `node-gyp` is invoked directly:  
- `$ export npm_config_devdir=/tmp/.gyp`  
- or on Windows  
- `> set npm_config_devdir=c:\temp\.gyp`  
-2. As `npm` configuration, variables take the form `OPTION_NAME`.
- This way only works when `node-gyp` is executed by `npm`:  
- `$ npm config set [--global] devdir /tmp/.gyp`  
- `$ npm i buffertools`
- 
-
-
-License
--------
-
-(The MIT License)
-
-Copyright (c) 2012 Nathan Rajlich &lt;nathan@tootallnate.net&gt;
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-'Software'), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-[python-v2.7.10]: https://www.python.org/downloads/release/python-2710/
-[msvc2013]: https://www.microsoft.com/en-gb/download/details.aspx?id=44914
-[win7sdk]: https://www.microsoft.com/en-us/download/details.aspx?id=8279
-[compiler update for the Windows SDK 7.1]: https://www.microsoft.com/en-us/download/details.aspx?id=4422
+| `--nodedir=$path`                 | Set the path to the node source code
+| `--python=$path`                  | Set path to the Python 2 binary
+| `--msvs_version=$version`         | Set Visual Studio version (Windows only)
+| `--solution=$solution`            | Set Visual Studio Solution version (Windows only)
+
+## Configuration
+
+### Environment variables
+
+Use the form `npm_config_OPTION_NAME` for any of the command options listed
+above (dashes in option names should be replaced by underscores).
+
+For example, to set `devdir` equal to `/tmp/.gyp`, you would:
+
+Run this on Unix:
+
+```bash
+$ export npm_config_devdir=/tmp/.gyp
+```
+
+Or this on Windows:
+
+```console
+> set npm_config_devdir=c:\temp\.gyp
+```
+
+### `npm` configuration
+
+Use the form `OPTION_NAME` for any of the command options listed above.
+
+For example, to set `devdir` equal to `/tmp/.gyp`, you would run:
+
+```bash
+$ npm config set [--global] devdir /tmp/.gyp
+```
+
+**Note:** Configuration set via `npm` will only be used when `node-gyp`
+is run via `npm`, not when `node-gyp` is run directly.
+
+## License
+
+`node-gyp` is available under the MIT license. See the [LICENSE
+file](LICENSE) for details.
diff --git a/addon.gypi b/addon.gypi
index f2f6a7925e..e8b95c5501 100644
--- a/addon.gypi
+++ b/addon.gypi
@@ -1,6 +1,7 @@
 {
   'variables' : {
     'node_engine_include_dir%': 'deps/v8/include',
+    'node_host_binary%': 'node'
   },
   'target_defaults': {
     'type': 'loadable_module',
@@ -18,7 +19,10 @@
     'include_dirs': [
       '<(node_root_dir)/include/node',
       '<(node_root_dir)/src',
+      '<(node_root_dir)/deps/openssl/config',
+      '<(node_root_dir)/deps/openssl/openssl/include',
       '<(node_root_dir)/deps/uv/include',
+      '<(node_root_dir)/deps/zlib',
       '<(node_root_dir)/<(node_engine_include_dir)'
     ],
     'defines!': [
@@ -52,6 +56,14 @@
         'standalone_static_library': '<(standalone_static_library)'
       }],
 
+      ['_type!="executable"', {
+        'conditions': [
+          [ 'OS=="android"', {
+            'cflags!': [ '-fPIE' ],
+          }]
+        ]
+      }],
+
       ['_win_delay_load_hook=="true"', {
         # If the addon specifies `'win_delay_load_hook': 'true'` in its
         # binding.gyp, link a delay-load hook into the DLL. This hook ensures
@@ -59,12 +71,13 @@
         # is named node.exe, iojs.exe, or something else.
         'conditions': [
           [ 'OS=="win"', {
+            'defines': [ 'HOST_BINARY=\"<(node_host_binary)<(EXECUTABLE_SUFFIX)\"', ],
             'sources': [
               '<(node_gyp_dir)/src/win_delay_load_hook.cc',
             ],
             'msvs_settings': {
               'VCLinkerTool': {
-                'DelayLoadDLLs': [ 'iojs.exe', 'node.exe' ],
+                'DelayLoadDLLs': [ '<(node_host_binary)<(EXECUTABLE_SUFFIX)' ],
                 # Don't print a linker warning when no imports from either .exe
                 # are used.
                 'AdditionalOptions': [ '/ignore:4199' ],
@@ -89,6 +102,17 @@
           '-Wl,-bimport:<(node_exp_file)'
         ],
       }],
+      [ 'OS=="zos"', {
+        'cflags': [
+          '-q64',
+          '-Wc,DLL',
+          '-qlonglong'
+        ],
+        'ldflags': [
+          '-q64',
+          '<(node_exp_file)'
+        ],
+      }],
       [ 'OS=="win"', {
         'conditions': [
           ['node_engine=="chakracore"', {
@@ -124,10 +148,10 @@
           '_FILE_OFFSET_BITS=64'
         ],
       }],
-      [ 'OS in "freebsd openbsd netbsd solaris" or \
+      [ 'OS in "freebsd openbsd netbsd solaris android" or \
          (OS=="linux" and target_arch!="ia32")', {
         'cflags': [ '-fPIC' ],
-      }]
+      }],
     ]
   }
 }
diff --git a/bin/node-gyp.js b/bin/node-gyp.js
index 70d7d50262..8c9b6169bb 100755
--- a/bin/node-gyp.js
+++ b/bin/node-gyp.js
@@ -1,19 +1,11 @@
 #!/usr/bin/env node
 
-/**
- * Set the title.
- */
-
 process.title = 'node-gyp'
 
-/**
- * Module dependencies.
- */
-
+var envPaths = require('env-paths')
 var gyp = require('../')
 var log = require('npmlog')
-var osenv = require('osenv')
-var path = require('path')
+var os = require('os')
 
 /**
  * Process and execute the selected commands.
@@ -24,11 +16,11 @@ var completed = false
 prog.parseArgv(process.argv)
 prog.devDir = prog.opts.devdir
 
-var homeDir = osenv.home()
+var homeDir = os.homedir()
 if (prog.devDir) {
   prog.devDir = prog.devDir.replace(/^~/, homeDir)
 } else if (homeDir) {
-  prog.devDir = path.resolve(homeDir, '.node-gyp')
+  prog.devDir = envPaths('node-gyp', { suffix: '' }).cache
 } else {
   throw new Error(
     "node-gyp requires that the user's home directory is specified " +
@@ -42,7 +34,7 @@ if (prog.todo.length === 0) {
   } else {
     console.log('%s', prog.usage())
   }
-  return process.exit(0)
+  process.exit(0)
 }
 
 log.info('it worked if it ends with', 'ok')
@@ -126,7 +118,7 @@ process.on('uncaughtException', function (err) {
 })
 
 function errorMessage () {
-  // copied from npm's lib/util/error-handler.js
+  // copied from npm's lib/utils/error-handler.js
   var os = require('os')
   log.error('System', os.type() + ' ' + os.release())
   log.error('command', process.argv
diff --git a/gyp/AUTHORS b/gyp/AUTHORS
index fecf84a1c4..d76d8cd768 100644
--- a/gyp/AUTHORS
+++ b/gyp/AUTHORS
@@ -1,9 +1,10 @@
 # Names should be added to this file like so:
 # Name or Organization <email address>
 
-Google Inc.
-Bloomberg Finance L.P.
-Yandex LLC
+Google Inc. <*@google.com>
+Bloomberg Finance L.P. <*@bloomberg.net>
+IBM Inc. <*@*.ibm.com>
+Yandex LLC <*@yandex-team.ru>
 
 Steven Knight <knight@baldmt.com>
 Ryan Norton <rnorton10@gmail.com>
diff --git a/gyp/PRESUBMIT.py b/gyp/PRESUBMIT.py
index dde025383c..e52f9d2d22 100644
--- a/gyp/PRESUBMIT.py
+++ b/gyp/PRESUBMIT.py
@@ -73,23 +73,14 @@
 ]
 
 
-def CheckChangeOnUpload(input_api, output_api):
-  report = []
-  report.extend(input_api.canned_checks.PanProjectChecks(
-      input_api, output_api))
-  return report
-
-
-def CheckChangeOnCommit(input_api, output_api):
-  report = []
-
+def _LicenseHeader(input_api):
   # Accept any year number from 2009 to the current year.
   current_year = int(input_api.time.strftime('%Y'))
-  allowed_years = (str(s) for s in reversed(xrange(2009, current_year + 1)))
+  allowed_years = (str(s) for s in reversed(range(2009, current_year + 1)))
   years_re = '(' + '|'.join(allowed_years) + ')'
 
   # The (c) is deprecated, but tolerate it until it's removed from all files.
-  license = (
+  return (
       r'.*? Copyright (\(c\) )?%(year)s Google Inc\. All rights reserved\.\n'
       r'.*? Use of this source code is governed by a BSD-style license that '
         r'can be\n'
@@ -98,8 +89,18 @@ def CheckChangeOnCommit(input_api, output_api):
       'year': years_re,
   }
 
+def CheckChangeOnUpload(input_api, output_api):
+  report = []
+  report.extend(input_api.canned_checks.PanProjectChecks(
+      input_api, output_api, license_header=_LicenseHeader(input_api)))
+  return report
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  report = []
+
   report.extend(input_api.canned_checks.PanProjectChecks(
-      input_api, output_api, license_header=license))
+      input_api, output_api, license_header=_LicenseHeader(input_api)))
   report.extend(input_api.canned_checks.CheckTreeIsOpen(
       input_api, output_api,
       'http://gyp-status.appspot.com/status',
diff --git a/gyp/buildbot/aosp_manifest.xml b/gyp/buildbot/aosp_manifest.xml
deleted file mode 100644
index bd73b303c6..0000000000
--- a/gyp/buildbot/aosp_manifest.xml
+++ /dev/null
@@ -1,466 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<manifest>
-  <remote  name="aosp"
-           fetch=".."
-           review="https://android-review.googlesource.com/" />
-  <default revision="master"
-           remote="aosp"
-           sync-j="4" />
-
-  <project groups="device,flo" name="device/asus/deb" revision="0ce3a783d549d023ddc553a04fed717ffb2ff533" />
-  <project groups="device,flo" name="device/asus/flo" revision="55ea79b11f9f82b2aa03f44a3429112fc5c06d07" />
-  <project groups="device,flo" name="device/asus/flo-kernel" revision="6d74123947016999ae62d9c3067ae97782fdba21" />
-  <project groups="device,grouper" name="device/asus/grouper" revision="78fe48f44e90ef3a7eceab5465dbad63cd16ce88" />
-  <project groups="device,grouper" name="device/asus/tilapia" revision="e5033bc80764067cbb1c9dc3970f0718e35ae8c7" />
-  <project name="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30" />
-  <project groups="pdk" name="device/generic/armv7-a-neon" revision="8bcf4b7a6380b26c2b42dae00dd8443de2a8e12c" />
-  <project groups="pdk" name="device/generic/common" revision="11c092a6cbfcf6207f07a9a8e3398e747e7f5461" />
-  <project groups="pdk" name="device/generic/goldfish" revision="638ee524f83053613c47ddea22c4bf98a0175c2f" />
-  <project groups="pdk" name="device/generic/mini-emulator-armv7-a-neon" revision="2a7ade61377b7906187ab46b5859c896baa0ab0e" />
-  <project groups="pdk" name="device/generic/mini-emulator-mips" revision="2ff06dda649ba43507a911057f7854a3373ef7d6" />
-  <project groups="pdk" name="device/generic/mini-emulator-x86" revision="a2f05b8c5259c232be5b029b2d5e721ba3f70917" />
-  <project groups="pdk" name="device/generic/mips" revision="dd06e7883227cc68bb1206584c8e3a768e49d02d" />
-  <project name="device/generic/qemu" revision="bd2543e810f3fa56e9dcfe301b893832534c85db" />
-  <project groups="pdk" name="device/generic/x86" revision="f111878fb41e2bdf4eb092d1edf0eb53cc5d0153" />
-  <project groups="device" name="device/google/accessory/arduino" revision="abc5159a3ca9dbb5c7e364a1eab99901a4440ac5" />
-  <project groups="device" name="device/google/accessory/demokit" revision="7dfe7f89a3b174709c773fe319531006e46440d9" />
-  <project groups="device,hammerhead" name="device/lge/hammerhead" revision="ec229bf178b891cc18552833f2de743acf390a7c" />
-  <project groups="device,hammerhead" name="device/lge/hammerhead-kernel" revision="a1dc58be96e7a71496e3e89079ac704930f982f2" />
-  <project groups="device,mako" name="device/lge/mako" revision="7e5f0f313819ffa3b45cd4208ab552f446c33936" />
-  <project groups="device,mako" name="device/lge/mako-kernel" revision="b7de901b8cb86036e9b92b3b6f188b45a524b125" />
-  <project groups="pdk" name="device/sample" revision="096f9eb5763fd2766fcbbe4f6b9da51c87f61797" />
-  <project groups="device,manta" name="device/samsung/manta" revision="78fe248ddb214aca2215df46be83882dc50c9283" />
-  <project groups="pdk" name="platform/abi/cpp" path="abi/cpp" revision="a0f99286d0909f7a30b0bee742bec2a0b62c4dd0" />
-  <project name="platform/art" path="art" revision="36b111c7d3d635e262114dabde4c26952c7dcbe6" />
-  <project groups="pdk" name="platform/bionic" path="bionic" revision="36bacd237de931c48714d1a8aa4aa9522283e407" />
-  <project name="platform/bootable/bootloader/legacy" path="bootable/bootloader/legacy" revision="3c491d6efb8ff2534a6934702760a6273f197918" />
-  <project name="platform/bootable/diskinstaller" path="bootable/diskinstaller" revision="ca40959a8caafa0df6a5c3d845e2afe6b252093f" />
-  <project groups="pdk" name="platform/bootable/recovery" path="bootable/recovery" revision="974fe112ae6df95ca6d49688d6e3e459d87e16de" />
-  <project groups="pdk" name="platform/build" path="build" revision="d23798bfdc9bb34909177c3c5f06f0c97cc9897e" >
-    <copyfile dest="Makefile" src="core/root.mk"/>
-  </project>
-  <project groups="cts" name="platform/cts" path="cts" revision="e15e8f846e19816e18ee3293c5b99f78463be28e" />
-  <project name="platform/dalvik" path="dalvik" revision="fb5b0d5bc46bce9c8ed6b1150498d6e145811a7d" />
-  <project name="platform/developers/build" path="developers/build" revision="75c5c41b06f045c3304b1b19d8250f04a8da8f10" />
-  <project name="platform/developers/demos" path="developers/demos" revision="64526120cd8da89bcb9a48acf95307d2c172a6e8" />
-  <project name="platform/developers/docs" path="developers/docs" revision="c0b835ddd9acc27176dc9a0f7d1aa2faf5d51806" />
-  <project name="platform/developers/samples/android" path="developers/samples/android" revision="dea82fa23f038d66bd9cfdff2afb8ef22add1c4f" />
-  <project name="platform/development" path="development" revision="0efeb2c66bff9b36feecd9315d14d2afb46e4669" />
-  <project name="platform/docs/source.android.com" path="docs/source.android.com" revision="c4795fa0df2c5fb4832ae65482944e8e5400e4f6" />
-  <project groups="pdk" name="platform/external/aac" path="external/aac" revision="35f30c5ab8089f38681d2fdd416c00aebef5a7ff" />
-  <project name="platform/external/android-clat" path="external/android-clat" revision="18921713780edb45ceef327d5fcf3387818300f3" />
-  <project name="platform/external/android-mock" path="external/android-mock" revision="4fe497660c2e939300dc5b743d662aef458b1726" />
-  <project name="platform/external/ant-glob" path="external/ant-glob" revision="0f189400fd2a36bf11bfb058e7f3917eb7ed163a" />
-  <project name="platform/external/antlr" path="external/antlr" revision="47997265eeb7d954a32ece693bbe6dab740872dd" />
-  <project name="platform/external/apache-harmony" path="external/apache-harmony" revision="6942e08fdbbd8402c9deabb0f60c8c871194b244" />
-  <project name="platform/external/apache-http" path="external/apache-http" revision="85ed0e10781c3c57343300a02556dd5131c450aa" />
-  <project name="platform/external/apache-qp" path="external/apache-qp" revision="64ea622b23e6612eb8e7dcae6bfd4314beb022a8" />
-  <project name="platform/external/apache-xml" path="external/apache-xml" revision="00ee83ff1bd827a852065986ed0da7a3ded57a55" />
-  <project name="platform/external/arduino" path="external/arduino" revision="d06daf9bbc46838400461eb8e15842974e38d82a" />
-  <project groups="pdk" name="platform/external/bison" path="external/bison" revision="c2418b886165add7f5a31fc5609f0ce2d004a90e" />
-  <project name="platform/external/blktrace" path="external/blktrace" revision="d345431f16b8f76f30a58193ff2b26d5853e1109" />
-  <project groups="pdk" name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="3b4040093ddf0e0025d0dd034aa65078bb695514" />
-  <project name="platform/external/bouncycastle" path="external/bouncycastle" revision="234720ebe66540a53cff98b2448dddbc884bd09f" />
-  <project groups="pdk" name="platform/external/bsdiff" path="external/bsdiff" revision="6f503758fad2cbcf8359e8f0af32e4d79a2a48ae" />
-  <project groups="pdk" name="platform/external/bzip2" path="external/bzip2" revision="1cb636bd8e9e5cdfd5d5b2909a122f6e80db62de" />
-  <project name="platform/external/ceres-solver" path="external/ceres-solver" revision="399f7d09e0c45af54b77b4ab9508d6f23759b927" />
-  <project groups="pdk" name="platform/external/checkpolicy" path="external/checkpolicy" revision="c66ac590eebc731f6021f267ebea208e87d8f04f" />
-  <project name="platform/external/chromium" path="external/chromium" revision="f294081d501ad98b7d7f50bc73f291063caf2c5f" />
-  <project name="platform/external/chromium-libpac" path="external/chromium-libpac" revision="09cf45bf5a650fe1abd50b9d61c2670a62f62767" />
-  <project groups="pdk" name="platform/external/chromium-trace" path="external/chromium-trace" revision="8252ae6b83ea65cf871e7981e981da07379f5a0f" />
-  <project name="platform/external/chromium_org" path="external/chromium_org" revision="43165a58c6167882aabb62f470c4e4d21f807d79" />
-  <project name="platform/external/chromium_org/sdch/open-vcdiff" path="external/chromium_org/sdch/open-vcdiff" revision="6d634da5463d9bc5fc88f86aec1d2ac4fe6f612e" />
-  <project name="platform/external/chromium_org/testing/gtest" path="external/chromium_org/testing/gtest" revision="65df883d09205766c521f2e6c126f4070a423141" />
-  <project name="platform/external/chromium_org/third_party/WebKit" path="external/chromium_org/third_party/WebKit" revision="a25b4978c2c50d573391a6d56a0e8ad35f52ffc8" />
-  <project name="platform/external/chromium_org/third_party/angle" path="external/chromium_org/third_party/angle" revision="8b77c2b2231f7d895979f6341e1ad1964a654ce4" />
-  <project name="platform/external/chromium_org/third_party/boringssl/src" path="external/chromium_org/third_party/boringssl/src" revision="85fb7432d3c851200342dd982b211f8dac860687" />
-  <project name="platform/external/chromium_org/third_party/brotli/src" path="external/chromium_org/third_party/brotli/src" revision="96f298ac43a9216b251d6c3264d8f5ada89e107f" />
-  <project name="platform/external/chromium_org/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille" path="external/chromium_org/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille" revision="bb4c72f1deb0b8b2b0468b0bf1050462ebcf6135" />
-  <project name="platform/external/chromium_org/third_party/freetype" path="external/chromium_org/third_party/freetype" revision="dc263f2ee2786739da036911ed8b29c07a639ab9" />
-  <project name="platform/external/chromium_org/third_party/icu" path="external/chromium_org/third_party/icu" revision="85e5871666cade1bb4b53f0cebfae53bc7d8d1f2" />
-  <project name="platform/external/chromium_org/third_party/leveldatabase/src" path="external/chromium_org/third_party/leveldatabase/src" revision="d4e10f2a91f5de7bd17adcdbd80c54b19ab336fe" />
-  <project name="platform/external/chromium_org/third_party/libaddressinput/src" path="external/chromium_org/third_party/libaddressinput/src" revision="7127f6844fac19d7610e34f4f7e03398fcd95531" />
-  <project name="platform/external/chromium_org/third_party/libjingle/source/talk" path="external/chromium_org/third_party/libjingle/source/talk" revision="8fd7b6a4d9e6757c5e1ff50147e6089979bf6701" />
-  <project name="platform/external/chromium_org/third_party/libphonenumber/src/phonenumbers" path="external/chromium_org/third_party/libphonenumber/src/phonenumbers" revision="de6af28b9f9f34a31ffb7772b7510fd215a0814e" />
-  <project name="platform/external/chromium_org/third_party/libphonenumber/src/resources" path="external/chromium_org/third_party/libphonenumber/src/resources" revision="8f194ead1ebd76ebb28b7e2dfc0a7baddc62bb22" />
-  <project name="platform/external/chromium_org/third_party/libsrtp" path="external/chromium_org/third_party/libsrtp" revision="5eddd5b3436aa8b2c7eb1f3c6db154281c6b91c5" />
-  <project name="platform/external/chromium_org/third_party/libvpx" path="external/chromium_org/third_party/libvpx" revision="c20d6540c47e427470c5a56b35fea3c5e9098748" />
-  <project name="platform/external/chromium_org/third_party/libyuv" path="external/chromium_org/third_party/libyuv" revision="6e77b766a9eb7889c1a10cab978705ffe03ff3e7" />
-  <project name="platform/external/chromium_org/third_party/mesa/src" path="external/chromium_org/third_party/mesa/src" revision="e70a8ff30d20e1bf6bb5c06b5cd7bd4ea9ae20e1" />
-  <project name="platform/external/chromium_org/third_party/openmax_dl" path="external/chromium_org/third_party/openmax_dl" revision="83d0254a412b93e81b06a354b90fb627408b4ec8" />
-  <project name="platform/external/chromium_org/third_party/openssl" path="external/chromium_org/third_party/openssl" revision="c2a9402712e13e15fcae2b17ec0cbecb816ef52e" />
-  <project name="platform/external/chromium_org/third_party/opus/src" path="external/chromium_org/third_party/opus/src" revision="e383b38591b010ab08ebddf1fd8d821796bd961a" />
-  <project name="platform/external/chromium_org/third_party/ots" path="external/chromium_org/third_party/ots" revision="4d6e4ddc4b0db2023b1380236c33aa04a7e9e927" />
-  <project name="platform/external/chromium_org/third_party/sfntly/cpp/src" path="external/chromium_org/third_party/sfntly/cpp/src" revision="2bac2ec7167835b214bfe42e762cd2ce6cf8cf1a" />
-  <project name="platform/external/chromium_org/third_party/skia" path="external/chromium_org/third_party/skia" revision="2d75d0865c7bac54bf5e234855609d0f628388b7" />
-  <project name="platform/external/chromium_org/third_party/smhasher/src" path="external/chromium_org/third_party/smhasher/src" revision="09e3094b8ab52bb1ad9ab8c8351d99df50327b67" />
-  <project name="platform/external/chromium_org/third_party/usrsctp/usrsctplib" path="external/chromium_org/third_party/usrsctp/usrsctplib" revision="ed9a6fb519aa7606cab965b2c4218756e849ddb6" />
-  <project name="platform/external/chromium_org/third_party/webrtc" path="external/chromium_org/third_party/webrtc" revision="8b45a80ec9c21b148a5674d3a23ca5fa70981f71" />
-  <project name="platform/external/chromium_org/third_party/yasm/source/patched-yasm" path="external/chromium_org/third_party/yasm/source/patched-yasm" revision="0f308c9bc9aa3258a0e90285b9d4e69bbb5b0a73" />
-  <project name="platform/external/chromium_org/tools/grit" path="external/chromium_org/tools/grit" revision="4ad93ed16c8ae7742fd7c34c83036b8d03c21fb9" />
-  <project name="platform/external/chromium_org/tools/gyp" path="external/chromium_org/tools/gyp" revision="9c42a79388ce87185ad04cb02047c1e56ac5e066" />
-  <project name="platform/external/chromium_org/v8" path="external/chromium_org/v8" revision="db865e6839e98cc9d07609bf81bb6610117ba6ff" />
-  <project groups="pdk" name="platform/external/clang" path="external/clang" revision="070ed154a0a8bc2c0fd4fb9b8a86a0f1218e6dfa" />
-  <project groups="pdk" name="platform/external/compiler-rt" path="external/compiler-rt" revision="c185902e393cd71823258016ead1b315ed062b24" />
-  <project name="platform/external/conscrypt" path="external/conscrypt" revision="26163c268a6d2625384b87e907afad8ef19f9a47" />
-  <project name="platform/external/dexmaker" path="external/dexmaker" revision="2b528c4b156f2de5c641875b98e59e0b09ebaccd" />
-  <project name="platform/external/dhcpcd" path="external/dhcpcd" revision="03baf5eab896198b5060d287af3fd60d360bf48f" />
-  <project groups="pdk" name="platform/external/dnsmasq" path="external/dnsmasq" revision="7674911bc9d10adf57c2c2d15d0c641b48e4afe6" />
-  <project name="platform/external/doclava" path="external/doclava" revision="b9d279d8f9c29a3044d13482846efb21f27b5df4" />
-  <project groups="pdk" name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="721f3bc56989b5f4101e646a02d598ddb4a7ff6e" />
-  <project name="platform/external/easymock" path="external/easymock" revision="c9a234086537e5fd820b110bbd99e3cdc695004c" />
-  <project name="platform/external/eclipse-basebuilder" path="external/eclipse-basebuilder" revision="6134da6347cc997e0cf2921aaadfb46f21c05d85" />
-  <project name="platform/external/eclipse-windowbuilder" path="external/eclipse-windowbuilder" revision="a5f3ee137e94737538ec3bdf9b3716765d178c17" />
-  <project name="platform/external/eigen" path="external/eigen" revision="b015e75e8c7ba1ab4ddb91e9372a57e76f3fd159" />
-  <project name="platform/external/elfutils" path="external/elfutils" revision="38ecac0276825a9463803485440646582e477e78" />
-  <project name="platform/external/embunit" path="external/embunit" revision="336b7c65098af0d1be69f2db55f4e75342d73b3f" />
-  <project name="platform/external/emma" path="external/emma" revision="daacd02a6b9f7a3e82bdf1cc5b84db85ed59edb1" />
-  <project name="platform/external/esd" path="external/esd" revision="224a67f2683a7ee997179fc5dd16115e39987b0f" />
-  <project groups="pdk" name="platform/external/expat" path="external/expat" revision="907ec055718996baf36961e7f47f8447e49b3865" />
-  <project name="platform/external/eyes-free" path="external/eyes-free" revision="16bd4c7a4d1bfe229068b637614dad7c48dd2ceb" />
-  <project name="platform/external/f2fs-tools" path="external/f2fs-tools" revision="00dc8a1c6c87acf687e64e66cfc2fd7ca28e646e" />
-  <project name="platform/external/fdlibm" path="external/fdlibm" revision="c831c726067e0d8a05362e710e2405f0eff81e07" />
-  <project name="platform/external/fio" path="external/fio" revision="6f4e805b805f1ab3025482e471147bb51efa99bd" />
-  <project groups="pdk" name="platform/external/flac" path="external/flac" revision="7f32dd57579bdff88e46e1e403154be0b99165da" />
-  <project groups="pdk" name="platform/external/freetype" path="external/freetype" revision="899c67b6cfcd2010784fbf08c5415af16c526e0c" />
-  <project name="platform/external/fsck_msdos" path="external/fsck_msdos" revision="17a1471db8c528cd9d44ec4385d2eb3614138856" />
-  <project name="platform/external/ganymed-ssh2" path="external/ganymed-ssh2" revision="d3724dabc1cfbacd105fe6c422b4dcba80e4fb2d" />
-  <project groups="pdk" name="platform/external/gcc-demangle" path="external/gcc-demangle" revision="9241386b62c353302c2f9eccda0672685b252b4d" />
-  <project name="platform/external/genext2fs" path="external/genext2fs" revision="e11a9c7fe6f1cef99aad2f25afaea37b72fe9f93" />
-  <project name="platform/external/giflib" path="external/giflib" revision="621696a283c0ce34956417f760f1005fadcd12ae" />
-  <project name="platform/external/google-diff-match-patch" path="external/google-diff-match-patch" revision="cecbe12841337860291c2d6a5728b681ec5fca2a" />
-  <project name="platform/external/google-fonts/carrois-gothic-sc" path="external/google-fonts/carrois-gothic-sc" revision="0062a10458d4c357f3082d66bcb129d11913aaae" />
-  <project name="platform/external/google-fonts/coming-soon" path="external/google-fonts/coming-soon" revision="2c5cb418c690815545bbb0316eae5fd33b9fc859" />
-  <project name="platform/external/google-fonts/dancing-script" path="external/google-fonts/dancing-script" revision="7b6623bd54cee3e48ae8a4f477f616366643cc78" />
-  <project name="platform/external/grub" path="external/grub" revision="33a4e7e4cfa81dc21d37091515891859ef3ab934" />
-  <project groups="pdk" name="platform/external/gtest" path="external/gtest" revision="fa3c26b862ca17c0d2db67606226b49d1648b4bf" />
-  <project name="platform/external/guava" path="external/guava" revision="5e6db342fc75b1945298142530f2d1d1861bce73" />
-  <project name="platform/external/hamcrest" path="external/hamcrest" revision="ba28ac1e0386f26d9a45be5ed16fc9c598b27e70" />
-  <project name="platform/external/harfbuzz" path="external/harfbuzz" revision="7a08026033b424da3b7022ebcce35f033949df8b" />
-  <project name="platform/external/harfbuzz_ng" path="external/harfbuzz_ng" revision="3e537b48a7b56c742ecf3c2ed24ff15fcb73f575" />
-  <project name="platform/external/hyphenation" path="external/hyphenation" revision="bfa84834dfeb7fe8d058c2e7e07b5981451ddf82" />
-  <project name="platform/external/icu" path="external/icu" revision="3c09e2ebbdae6000f3bd471c34d055bc1913f7e4" />
-  <project groups="pdk" name="platform/external/icu4c" path="external/icu4c" revision="e5311394ca22b280da41cd17059288dab3fb1ea6" />
-  <project groups="pdk" name="platform/external/iproute2" path="external/iproute2" revision="5d4c86892885ae1bc12e0e157b35ef44e8ba81bd" />
-  <project name="platform/external/ipsec-tools" path="external/ipsec-tools" revision="f4cb1ee4b00abbfb6f968dc25818c23b4b47e584" />
-  <project name="platform/external/iptables" path="external/iptables" revision="e3928b77f18db0fdc615693017c6c15eb71bf4e0" />
-  <project name="platform/external/iputils" path="external/iputils" revision="1c7c426ab377c3a005a36d612ebbb16de86fb7d4" />
-  <project name="platform/external/jack" path="external/jack" revision="5ceb2025ac5d25ed48183ac2d3dac4691fe761fb" />
-  <project name="platform/external/javasqlite" path="external/javasqlite" revision="b8501bdeb0b7e39a0d82f2a96ad382c05a763b22" />
-  <project name="platform/external/javassist" path="external/javassist" revision="9566207cff5871c672fac1f0d4332d93292036d7" />
-  <project name="platform/external/jdiff" path="external/jdiff" revision="e4694302d6a3786c64d954e0b3cf42786283bd3c" />
-  <project name="platform/external/jemalloc" path="external/jemalloc" revision="615fe54259e545c33275753a316c2bfd1198b4f0" />
-  <project groups="pdk" name="platform/external/jhead" path="external/jhead" revision="871af5c305ce1d3087e58fae091c60c359f5fa45" />
-  <project name="platform/external/jmdns" path="external/jmdns" revision="f4eb7466d5c09098f9dc54137ed3235e3c43fc9f" />
-  <project name="platform/external/jmonkeyengine" path="external/jmonkeyengine" revision="a6b44658eb1c55295f132a36233a11aa2bd8f9cf" />
-  <project groups="pdk" name="platform/external/jpeg" path="external/jpeg" revision="213197252c8c4825f6572c651126c22067025fe9" />
-  <project name="platform/external/jsilver" path="external/jsilver" revision="739060b01245f1dc5f1800949b3c30c291253cff" />
-  <project name="platform/external/jsr305" path="external/jsr305" revision="a82868820d6350811b9ddfde4bf8ed5016084269" />
-  <project name="platform/external/junit" path="external/junit" revision="8f312e0c3d6dff30d015d2c85fdaae0a39220fd6" />
-  <project name="platform/external/kernel-headers" path="external/kernel-headers" revision="8b663ef01dcaadfe1dec7ba826e5cd1cf0bb2c91" />
-  <project name="platform/external/libcap-ng" path="external/libcap-ng" revision="1d1011a3c5049a7f9eef99d22f3704e4367579cc" />
-  <project name="platform/external/libcxx" path="external/libcxx" revision="a9aa30b5d18422fce29a42ce1a704bc5f28febde" />
-  <project name="platform/external/libcxxabi" path="external/libcxxabi" revision="87a9be28aceed80250cd1d1a47eb8afa0ee67b51" />
-  <project name="platform/external/libcxxrt" path="external/libcxxrt" revision="d1ee2b2a4946a073596514462d7629373d22fb27" />
-  <project name="platform/external/libexif" path="external/libexif" revision="25d371312cee1452a2adcf8b7f6cad6267bda32d" />
-  <project name="platform/external/libffi" path="external/libffi" revision="385ba8b006b9995456d3c9283fd20dded90809cc" />
-  <project groups="pdk" name="platform/external/libgsm" path="external/libgsm" revision="50761abed8f4734970874165b386cfd4d9599db4" />
-  <project groups="pdk" name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb" />
-  <project name="platform/external/libmtp" path="external/libmtp" revision="7075348937f6a8c9d9211942fcb6c376f4227776" />
-  <project groups="pdk" name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="46abb3dcf960058e48d1444b6a11cc7e84912339" />
-  <project groups="pdk" name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="15d81f71a668b3092549c6b7f83694bf680d9c49" />
-  <project name="platform/external/libnl" path="external/libnl" revision="99debfa4c01b49c9b470884cc56f81fcdee0fa1f" />
-  <project groups="pdk" name="platform/external/libnl-headers" path="external/libnl-headers" revision="52c926a9de955fa2d987bf8c5d4a1304b5a2a611" />
-  <project name="platform/external/libogg" path="external/libogg" revision="ec0b24fb1468abe37be4164a6feb16568e036bde" />
-  <project name="platform/external/libpcap" path="external/libpcap" revision="9dab0cd7430a4d23e0a7752fb13b941692171c3d" />
-  <project name="platform/external/libphonenumber" path="external/libphonenumber" revision="485e6d5c6e48a1fc43cc0a090e687c723dac056c" />
-  <project groups="pdk" name="platform/external/libpng" path="external/libpng" revision="48b7ba25a15a9eae83d366c02475539725d035d0" />
-  <project name="platform/external/libppp" path="external/libppp" revision="706e567fc5ff6b79738a5f470e5aa7b2cae76459" />
-  <project name="platform/external/libseccomp-helper" path="external/libseccomp-helper" revision="e87019943a8b5a7cd0880910f671c37b240d5754" />
-  <project groups="pdk" name="platform/external/libselinux" path="external/libselinux" revision="da4208c8808e6a62fcfe848343abd3e2f3b339cc" />
-  <project groups="pdk" name="platform/external/libsepol" path="external/libsepol" revision="d26204e7d0a3be178a97d4920b82007e05a2a632" />
-  <project name="platform/external/libssh2" path="external/libssh2" revision="2bb40f2445cab3ba588efb29e1835cdba2b27248" />
-  <project name="platform/external/libunwind" path="external/libunwind" revision="b3436a3feed4dcb22dafc8f7818b742cacaddd1d" />
-  <project name="platform/external/libusb" path="external/libusb" revision="2801917fe150393d4f4a354165fe89550ae22613" />
-  <project name="platform/external/libusb-compat" path="external/libusb-compat" revision="94867ba54eb7faa8efca81cf2214d00bb9143d27" />
-  <project name="platform/external/libvorbis" path="external/libvorbis" revision="de559619fd4dd0d2d9608436696fd44bdf74eba8" />
-  <project groups="pdk" name="platform/external/libvpx" path="external/libvpx" revision="d64f247f64fbb814c9ecf06a56bcb0948bfca21f" />
-  <project name="platform/external/libxml2" path="external/libxml2" revision="399e808f940777d18efe377bd34f738dc84729e0" />
-  <project name="platform/external/libxslt" path="external/libxslt" revision="98f5140c33273d3bd67ca03566f8417406001016" />
-  <project groups="libyuv" name="platform/external/libyuv" path="external/libyuv" revision="482a582884351288fb701532359652970b1ba7c0" />
-  <project name="platform/external/linux-tools-perf" path="external/linux-tools-perf" revision="3e1937964f6c183eb6a0000e2dca27fc3a419ca2" />
-  <project name="platform/external/littlemock" path="external/littlemock" revision="328b01eada8965cd38feea884d4080c31e3763b0" />
-  <project groups="pdk" name="platform/external/llvm" path="external/llvm" revision="c4c1f81ae1b07138df50e0459631abf3082bda9c" />
-  <project name="platform/external/ltrace" path="external/ltrace" revision="82ae18484c7b6a8af05354caf6de3a7f1ac5fcf9" />
-  <project name="platform/external/lzma" path="external/lzma" revision="19cf4f773361c09e47a2ffe1613d66cbf632227f" />
-  <project name="platform/external/marisa-trie" path="external/marisa-trie" revision="629ed059b1e85cd8e4de363d8b3dc53c15c3e08a" />
-  <project name="platform/external/markdown" path="external/markdown" revision="6f2e3554ae38cc90518d32e02cb57d05988270a6" />
-  <project groups="pdk" name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="b25c2507ecc3f674e3b4f0a770acf9ad8fd874d0" />
-  <project name="platform/external/mesa3d" path="external/mesa3d" revision="97d3f36a59ea448fa77e47a90bf04f1254670542" />
-  <project name="platform/external/messageformat" path="external/messageformat" revision="180a28770171075aa484729a69d14c7cf0c93fcf" />
-  <project groups="pdk" name="platform/external/mksh" path="external/mksh" revision="2a54bce0ae98f53f0b867e949b26d081691e1493" />
-  <project name="platform/external/mockito" path="external/mockito" revision="4d0dcd53b27a243baf72ee0b127b188a058b318d" />
-  <project name="platform/external/mockwebserver" path="external/mockwebserver" revision="2f7659c426de53122ee7922b0981058a900124a7" />
-  <project name="platform/external/mp4parser" path="external/mp4parser" revision="16051e950485c6b62127c0446a760111de1a0cb9" />
-  <project name="platform/external/mtpd" path="external/mtpd" revision="5ea8006691664b7e6d46d6a6dc889eac91b7fe37" />
-  <project name="platform/external/naver-fonts" path="external/naver-fonts" revision="3bba7d2430bc3ec8105678a27f03fb080f0f8384" />
-  <project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8" />
-  <project name="platform/external/netperf" path="external/netperf" revision="38e47cd883738cb84bdb47a7d263f14f14062d7b" />
-  <project name="platform/external/neven" path="external/neven" revision="504ee5ccaabd8bce4da3430b0f4e9714ac2a8e6c" />
-  <project name="platform/external/nfacct" path="external/nfacct" revision="6f7aae0264821b44e9fe80fb5596c525d3e2f475" />
-  <project name="platform/external/nist-pkits" path="external/nist-pkits" revision="b7a53ad5a587926cb880d9bb6f3d51657596474c" />
-  <project name="platform/external/nist-sip" path="external/nist-sip" revision="b23dbfce7ea84c39cea75b612868a5832cb9af2b" />
-  <project name="platform/external/noto-fonts" path="external/noto-fonts" revision="90372d894b5d9c9f2a111315d2eb3b8de1979ee4" />
-  <project name="platform/external/oauth" path="external/oauth" revision="bc170f58de82000ed6460f111686a850a1890c07" />
-  <project name="platform/external/objenesis" path="external/objenesis" revision="2a7655c0d503fcf5989098f65bf89eae78c32e5a" />
-  <project name="platform/external/okhttp" path="external/okhttp" revision="4909663c795d974d0d4b0e2d1ebd6e179486c897" />
-  <project name="platform/external/open-vcdiff" path="external/open-vcdiff" revision="6d29f2f083baf8250db94ed0b4807e513a84163d" />
-  <project name="platform/external/opencv" path="external/opencv" revision="4a99e243b42afcb885d036bb451eb3c2739275b6" />
-  <project name="platform/external/openfst" path="external/openfst" revision="b7434caa51427a0f5ab5c807e1a92d6ca2af8884" />
-  <project name="platform/external/openssh" path="external/openssh" revision="3c335c9fb9c12375ad62748fa1d1e5ebe4710c94" />
-  <project groups="pdk" name="platform/external/openssl" path="external/openssl" revision="cfe73257599ae4baae3ffb50c2c841d9249d2d16" />
-  <project name="platform/external/oprofile" path="external/oprofile" revision="3722f1053f4cab90c4daf61451713a2d61d79c71" />
-  <project name="platform/external/owasp/sanitizer" path="external/owasp/sanitizer" revision="6a304233f9f2010821a5a1dd40e2832b68353a3c" />
-  <project name="platform/external/pcre" path="external/pcre" revision="993a14b71c8e7af03eb929d44a444137393a5324" />
-  <project name="platform/external/pixman" path="external/pixman" revision="afd5bbd8074cedec8544d07920fa06786d5a4f08" />
-  <project name="platform/external/ppp" path="external/ppp" revision="8b58d9bd02e2c55f547fafbe9ba55b1160665761" />
-  <project groups="pdk-java" name="platform/external/proguard" path="external/proguard" revision="3fd19dba2bdc0c4b64afda4d75836e1dcf7abf97" />
-  <project groups="pdk" name="platform/external/protobuf" path="external/protobuf" revision="95d99df4574c28debcf9646056a0350ff44bc7c9" />
-  <project name="platform/external/qemu" path="external/qemu" revision="539e1f25ecbfe80814dba2ea77feb22087b9d53b" />
-  <project name="platform/external/qemu-pc-bios" path="external/qemu-pc-bios" revision="20349dae98d7de09a7e390d4a706c64f1db6edc2" />
-  <project name="platform/external/regex-re2" path="external/regex-re2" revision="0d4c52358a1af421705c54bd8a9fdd8a30558a2e" />
-  <project name="platform/external/replicaisland" path="external/replicaisland" revision="99e2e54c5d036048caf09bb05eea0969de093104" />
-  <project name="platform/external/robolectric" path="external/robolectric" revision="6bf395c984ed3f69711663b006aeffbb0f7e8a90" />
-  <project groups="pdk" name="platform/external/safe-iop" path="external/safe-iop" revision="aa0725fb1da35e47676b6da30009322eb5ed59be" />
-  <project groups="pdk" name="platform/external/scrypt" path="external/scrypt" revision="dde037b82e5cd6215244e3240dbaad417928eafa" />
-  <project groups="pdk" name="platform/external/sepolicy" path="external/sepolicy" revision="21ada26daea538397029396099dce865267bae2f" />
-  <project name="platform/external/sfntly" path="external/sfntly" revision="6723e5241a45c6de224c96384a595a1bf5bc5449" />
-  <project name="platform/external/sil-fonts" path="external/sil-fonts" revision="795a2f4339f8a82d6cff187e2a77bb01d5911aac" />
-  <project name="platform/external/skia" path="external/skia" revision="d6f2c76fdb9b0469261fa2db0b29ed48c7ac38b5" />
-  <project name="platform/external/smack" path="external/smack" revision="d7955ce24d294fb2014c59d11fca184471056f44" />
-  <project name="platform/external/smali" path="external/smali" revision="5fd395796e215a80c722815bf180728948868f18" />
-  <project groups="pdk" name="platform/external/sonivox" path="external/sonivox" revision="c0723d864b10fbd6c5cbbfa65e886c5e9eb3aafd" />
-  <project groups="pdk" name="platform/external/speex" path="external/speex" revision="eaa4765b8cc6a6dd5ee0d26dc1b61a1044817f32" />
-  <project groups="pdk" name="platform/external/sqlite" path="external/sqlite" revision="50af37d784661b2d54c8e043de52ffc4f02a1a50" />
-  <project name="platform/external/srec" path="external/srec" revision="540e7ee8dbf1d7ee72ef45c92efbebcb89bf6d1a" />
-  <project name="platform/external/srtp" path="external/srtp" revision="98bd63b48a31b4633cdfdc8138577dfa6d8dd2a6" />
-  <project groups="pdk" name="platform/external/stlport" path="external/stlport" revision="dc05ca5be2319f74b41cb429ea50f30fceff4ace" />
-  <project name="platform/external/strace" path="external/strace" revision="a2adbed6e2d3ce85ebb167e16ae370681a8b5188" />
-  <project name="platform/external/stressapptest" path="external/stressapptest" revision="0956427aa995561acb4471764158ae057a36dad5" />
-  <project name="platform/external/svox" path="external/svox" revision="ad0a55bd0e13a27ed11034346eee9c47e3684ef2" />
-  <project name="platform/external/syspatch" path="external/syspatch" revision="358a4f86b8c2cb3d3f879a37f6773dd09d4b77b0" />
-  <project name="platform/external/tagsoup" path="external/tagsoup" revision="a97828cb3f8f3a1af8470e55d3c5cd62d6a7cb4c" />
-  <project name="platform/external/tcpdump" path="external/tcpdump" revision="de49cdcfddf36f2b41ef3278e98a8a550a189952" />
-  <project name="platform/external/timezonepicker-support" path="external/timezonepicker-support" revision="99e91a76fd74bad10266623d67cdb98d011f709e" />
-  <project groups="pdk" name="platform/external/tinyalsa" path="external/tinyalsa" revision="653e7a4015341c87b4d55ec9a94ec7bdee044f6f" />
-  <project groups="pdk" name="platform/external/tinycompress" path="external/tinycompress" revision="aeee2c6a19b9d3765f72bc79555005786a424233" />
-  <project groups="pdk" name="platform/external/tinyxml" path="external/tinyxml" revision="f065a8058659c0e6c5a5ccddcdb4faf0fe645cd0" />
-  <project groups="pdk" name="platform/external/tinyxml2" path="external/tinyxml2" revision="c74b546f5af36968ffa56d7fd4529f4273b96f48" />
-  <project groups="pdk" name="platform/external/tremolo" path="external/tremolo" revision="0fec2aefa8143c83df43752bb0218dfa371cc57e" />
-  <project groups="pdk" name="platform/external/valgrind" path="external/valgrind" revision="893257d6c86a18cc5cf6c92528b7027f327dca70" />
-  <project name="platform/external/vixl" path="external/vixl" revision="e1ab25cde167109efb28fa6a86d5c2c80b762d58" />
-  <project name="platform/external/webp" path="external/webp" revision="0db01fc3411621bec473d50db0071fd2a225962e" />
-  <project groups="pdk" name="platform/external/webrtc" path="external/webrtc" revision="d62aeac391d16d4953a12120c0ff614ccde02a30" />
-  <project groups="pdk" name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="88ef20ce4facae68a3e6b05429bb9f3f73a93996" />
-  <project name="platform/external/xdelta3" path="external/xdelta3" revision="52d9c642e6a307c43881f20a4ed1c10e947234ba" />
-  <project name="platform/external/xmlwriter" path="external/xmlwriter" revision="e95d92246ee35273dde2bee8b00485cc14c12be5" />
-  <project name="platform/external/xmp_toolkit" path="external/xmp_toolkit" revision="42ea4dc6d1fc2206a7778029070ed9213e3b0fbf" />
-  <project groups="pdk" name="platform/external/yaffs2" path="external/yaffs2" revision="a2cff2275e1b501ff478b03757d6e4f05fddc2db" />
-  <project groups="pdk" name="platform/external/zlib" path="external/zlib" revision="8d977782c1cfe9d75cc9a464439c2ff1e27e1665" />
-  <project name="platform/external/zxing" path="external/zxing" revision="7620644768ffc235607b3a94671e49518c18686f" />
-  <project groups="pdk" name="platform/frameworks/av" path="frameworks/av" revision="a018cd4926460f8f5ab30a9a11df9775572d8620" />
-  <project name="platform/frameworks/base" path="frameworks/base" revision="6a58309e734086a21580dd8d9175ac1817ca3ab2" />
-  <project groups="pdk" name="platform/frameworks/compile/libbcc" path="frameworks/compile/libbcc" revision="3fc91521640692f844aece8b1743c4df702d1c66" />
-  <project groups="pdk" name="platform/frameworks/compile/mclinker" path="frameworks/compile/mclinker" revision="e673be8f0526f9cbc83093fb579c0f76de9e4e3c" />
-  <project groups="pdk" name="platform/frameworks/compile/slang" path="frameworks/compile/slang" revision="c957dd47b0a0705a686896b26cd1859d25824552" />
-  <project name="platform/frameworks/ex" path="frameworks/ex" revision="3696df848aa7c574f913c97c3bf415b634934048" />
-  <project name="platform/frameworks/mff" path="frameworks/mff" revision="b9669b8540a1e5c953374d53b115514335e23c27" />
-  <project name="platform/frameworks/ml" path="frameworks/ml" revision="b020ad88ca28ada76a596b5dcc7e6c2854fcc132" />
-  <project name="platform/frameworks/multidex" path="frameworks/multidex" revision="590a07e63868f0a1da311ff22b4a9f35eb48a865" />
-  <project groups="pdk" name="platform/frameworks/native" path="frameworks/native" revision="e8878921db4a51ff5d4e75d9c8958d889a048603" />
-  <project name="platform/frameworks/opt/calendar" path="frameworks/opt/calendar" revision="03b18577f8f8f799e87a62b8e03889ddacf6daa2" />
-  <project name="platform/frameworks/opt/carddav" path="frameworks/opt/carddav" revision="f08aa2df132dd8dc32a0013d3750137d9dd9280a" />
-  <project name="platform/frameworks/opt/colorpicker" path="frameworks/opt/colorpicker" revision="720a40ae24d526268b3c0f2dd8497b5df2cc6f23" />
-  <project name="platform/frameworks/opt/datetimepicker" path="frameworks/opt/datetimepicker" revision="8a1c55baaf5ced7a98b196c689ccdd59238f6e58" />
-  <project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="709f713ebcd62c61defc270d945810efca179621" />
-  <project name="platform/frameworks/opt/inputmethodcommon" path="frameworks/opt/inputmethodcommon" revision="df9dd39c2047992a43b64e13bb0fc348a1630f3b" />
-  <project name="platform/frameworks/opt/mailcommon" path="frameworks/opt/mailcommon" revision="1537812900e59f875cfea0483f0ae261b16d3e4b" />
-  <project name="platform/frameworks/opt/mms" path="frameworks/opt/mms" revision="64817e848552fd0a429a3e026b7b1562103c56bb" />
-  <project name="platform/frameworks/opt/net/voip" path="frameworks/opt/net/voip" revision="0f722c7f09ce67e058eb1cfaabf1d85f1abdf797" />
-  <project name="platform/frameworks/opt/photoviewer" path="frameworks/opt/photoviewer" revision="8c32972911bf73babdb01d30267f57255e242d78" />
-  <project groups="pdk" name="platform/frameworks/opt/telephony" path="frameworks/opt/telephony" revision="93faaed9056491c551ef7046e9e1de7d6397e95c" />
-  <project name="platform/frameworks/opt/timezonepicker" path="frameworks/opt/timezonepicker" revision="3820b87bfbc86d066e9093e78254e1f3728ad77d" />
-  <project name="platform/frameworks/opt/vcard" path="frameworks/opt/vcard" revision="5907243e6cf0603adf266ebfa7ee5ee465b9c596" />
-  <project name="platform/frameworks/opt/widget" path="frameworks/opt/widget" revision="466e0e0307b3f6aa4f4be3d9419b5996bd389da5" />
-  <project groups="pdk" name="platform/frameworks/rs" path="frameworks/rs" revision="ad0544fdf918e64cec05d1c98588880f10b09220" />
-  <project name="platform/frameworks/support" path="frameworks/support" revision="f05c07d3528765076adc16337a1f68f1700955dc" />
-  <project name="platform/frameworks/testing" path="frameworks/testing" revision="5c8e0271db889518f5969b142a37faa01a4ee54d" />
-  <project name="platform/frameworks/volley" path="frameworks/volley" revision="0e406003b5d434d8f16d7d6ad97d446060b788e6" />
-  <project name="platform/frameworks/webview" path="frameworks/webview" revision="6ed700e171cb2ee3303c08a1db2abc0e56fd307a" />
-  <project name="platform/frameworks/wilhelm" path="frameworks/wilhelm" revision="a62c3572e60ae0446632de15418a65089cccf551" />
-  <project name="platform/hardware/akm" path="hardware/akm" revision="32838ef838d1341aa8b77022869b801fb0bbb26c" />
-  <project groups="pdk" name="platform/hardware/broadcom/libbt" path="hardware/broadcom/libbt" revision="55ddd0cce019e88829f92b2fe4e17d5869daa9b9" />
-  <project groups="broadcom_wlan" name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="47a3b8f496e6d2a836ac6b7268e5626c969542ec" />
-  <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="0f5bc7cd710fac85377621a8b9a4c364af80605f" />
-  <project groups="pdk" name="platform/hardware/libhardware" path="hardware/libhardware" revision="3e618a6aa10c783d1536f20edfc3347939cfa18e" />
-  <project groups="pdk" name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="4c20a09e8684657448f0bc97a2da4e56c94d484e" />
-  <project groups="qcom" name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="d47ff224c7b24933c701acae8d5e4c98a1bc80af" />
-  <project groups="qcom" name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="cf314a462ba06f4bd3352d5d4630edcf6edbbe97" />
-  <project groups="qcom" name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="fbf72e519ec5fe2f2720b1a3d119e2d69e172e34" />
-  <project groups="qcom" name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="0a611c6ae11b65fec5ada5ecaa0893541db34156" />
-  <project groups="qcom" name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="70d36107318e1d3f7abf62a56279b3f9da3ff000" />
-  <project groups="qcom" name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="1208a868bcb0ffaa650a7e68b51031254c775d39" />
-  <project groups="qcom_msm8960" name="platform/hardware/qcom/msm8960" path="hardware/qcom/msm8960" revision="ca38ed098b05a79d20e852348f27d7c40a53f801" />
-  <project groups="qcom_msm8x74" name="platform/hardware/qcom/msm8x74" path="hardware/qcom/msm8x74" revision="0c6844ea9ee14fd7bbfd6af0bcc6b6b682f46d1c" />
-  <project groups="qcom" name="platform/hardware/qcom/power" path="hardware/qcom/power" revision="ff9f4538c09399030fa73e3e65a167852cb91e8f" />
-  <project groups="qcom" name="platform/hardware/qcom/sensors" path="hardware/qcom/sensors" revision="07c5bcdb36158e22d33bac02eecd83d4ff1fb2f8" />
-  <project groups="qcom_wlan" name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="daa321b0ad8c10b454dc28d7e6dadc72196a8c7a" />
-  <project groups="pdk" name="platform/hardware/ril" path="hardware/ril" revision="eb2a93458204a928edfe36f043ddb48cf5575143" />
-  <project groups="exynos5" name="platform/hardware/samsung_slsi/exynos5" path="hardware/samsung_slsi/exynos5" revision="d7bd354358ecfb1e52afb3da4fc586c0822c696a" />
-  <project name="platform/hardware/ti/omap3" path="hardware/ti/omap3" revision="949aad363a9cc794f9ac8fd42338ae1678e50bc1" />
-  <project groups="omap4" name="platform/hardware/ti/omap4xxx" path="hardware/ti/omap4xxx" revision="c32caab84ff9edc1489ed6c8079c7d252caafc4d" />
-  <project name="platform/libcore" path="libcore" revision="d343e35535a99bad32eea0defc8a3e9c23c9967f" />
-  <project groups="pdk-java" name="platform/libnativehelper" path="libnativehelper" revision="b37e11d07dec2d49b576709ae8e0568a9daabd07" />
-  <project name="platform/ndk" path="ndk" revision="f584f76882baf374166cf12b99cd5f3dbdf3b6b9" />
-  <project name="platform/packages/apps/BasicSmsReceiver" path="packages/apps/BasicSmsReceiver" revision="80327793c4b4ebf4a6a53b72e46c477afe18f135" />
-  <project name="platform/packages/apps/Bluetooth" path="packages/apps/Bluetooth" revision="7efa9db2129c99475684a2e44c4fb89cce3134bc" />
-  <project name="platform/packages/apps/Browser" path="packages/apps/Browser" revision="fe4083510dc773911651456f150bf5432f81a6c0" />
-  <project name="platform/packages/apps/Calculator" path="packages/apps/Calculator" revision="6c7521bb685c9b7b7c36f2077612d4b1a0e808d4" />
-  <project name="platform/packages/apps/Calendar" path="packages/apps/Calendar" revision="2d72f6bed6a0eeaddbda08393063fe873c1c7922" />
-  <project name="platform/packages/apps/Camera" path="packages/apps/Camera" revision="b0e357d548fb8d10896200add2b932199a96a2ea" />
-  <project name="platform/packages/apps/Camera2" path="packages/apps/Camera2" revision="ece4866dc575b956801f6dab2d6c4923e272c5fa" />
-  <project name="platform/packages/apps/CellBroadcastReceiver" path="packages/apps/CellBroadcastReceiver" revision="21d8baf492007cc01545905de33ecefe5d947843" />
-  <project name="platform/packages/apps/CertInstaller" path="packages/apps/CertInstaller" revision="483a188feda6e9d311aef437d28f30e1fb6afeb0" />
-  <project name="platform/packages/apps/Contacts" path="packages/apps/Contacts" revision="24a4f48dc5c768188143648e267889477e4185e8" />
-  <project name="platform/packages/apps/ContactsCommon" path="packages/apps/ContactsCommon" revision="6ce4a3bc083a7dbcc7ffa2bebff242638d7f8e61" />
-  <project name="platform/packages/apps/DeskClock" path="packages/apps/DeskClock" revision="d3bfe9223f3e70271813f48b8ef5500c3a90c0b3" />
-  <project name="platform/packages/apps/Dialer" path="packages/apps/Dialer" revision="5cb300ef50e9942eef746319dd1b1b6e7c2c05e2" />
-  <project name="platform/packages/apps/Email" path="packages/apps/Email" revision="22766dcf6a44416b2972c053739472317017257d" />
-  <project name="platform/packages/apps/Exchange" path="packages/apps/Exchange" revision="ab03a7f9b197b6ffcc390dd5fb589067a5161148" />
-  <project name="platform/packages/apps/Gallery" path="packages/apps/Gallery" revision="9595006a3347c08e6b8e31d679903bb8f77a343d" />
-  <project name="platform/packages/apps/Gallery2" path="packages/apps/Gallery2" revision="9cde04ed08f3a5201a007d78b3c89f43fb3003e0" />
-  <project name="platform/packages/apps/HTMLViewer" path="packages/apps/HTMLViewer" revision="7498890092c388dc59ca932e09ec79dd568b1a19" />
-  <project name="platform/packages/apps/InCallUI" path="packages/apps/InCallUI" revision="d968d1a28dae45229b1be9f05bef8df13821e94d" />
-  <project name="platform/packages/apps/KeyChain" path="packages/apps/KeyChain" revision="e6243f79f3ce6daeb2d8d879e6e1a684ffc1b2fc" />
-  <project name="platform/packages/apps/Launcher2" path="packages/apps/Launcher2" revision="31569f6dbd44d443ff54c460b733e62fc37d2319" />
-  <project name="platform/packages/apps/Launcher3" path="packages/apps/Launcher3" revision="3a9f3a7806a0153865415d6207c6812915d3f6b1" />
-  <project name="platform/packages/apps/LegacyCamera" path="packages/apps/LegacyCamera" revision="d9b5d8941d1ec47ff391da2b8cc8ec90f902062f" />
-  <project name="platform/packages/apps/Mms" path="packages/apps/Mms" revision="e770738ea4389afddb0b4e6c69749f9456ed0f48" />
-  <project name="platform/packages/apps/Music" path="packages/apps/Music" revision="bfca689bb6605cfcd1e0c1781c707735efb7444e" />
-  <project name="platform/packages/apps/MusicFX" path="packages/apps/MusicFX" revision="aaa2f99caac6f088b23de55fe2eb1e8ee305b1fb" />
-  <project name="platform/packages/apps/Nfc" path="packages/apps/Nfc" revision="f62a9a00a13ba333e88cb9e8ce2553d6acf708ad" />
-  <project name="platform/packages/apps/OneTimeInitializer" path="packages/apps/OneTimeInitializer" revision="01e429c08e51291315890de9677151a7e0b6ad35" />
-  <project name="platform/packages/apps/PackageInstaller" path="packages/apps/PackageInstaller" revision="212398024b4491276ef00cf7fcd829c89200b6ba" />
-  <project name="platform/packages/apps/Phone" path="packages/apps/Phone" revision="bf4ec5b1258628bfa6a82aa0d80f348a77bbf194" />
-  <project name="platform/packages/apps/PhoneCommon" path="packages/apps/PhoneCommon" revision="16f62c5ab5c21981e63d678187ad4b44e686332b" />
-  <project name="platform/packages/apps/Protips" path="packages/apps/Protips" revision="325232e344b257a3c236ead2adc60c7378f226c0" />
-  <project name="platform/packages/apps/Provision" path="packages/apps/Provision" revision="78ca0db658fe6253d506916e36319e620476f809" />
-  <project name="platform/packages/apps/QuickSearchBox" path="packages/apps/QuickSearchBox" revision="cfb7af6652a7fbcc0f86341edfe14dc316c9ff37" />
-  <project name="platform/packages/apps/Settings" path="packages/apps/Settings" revision="2abbacb7d46657e5863eb2ef0035521ffc41a0a8" />
-  <project name="platform/packages/apps/SmartCardService" path="packages/apps/SmartCardService" revision="29eae320a4bd222b5ff1c092f84f1aebba88d0b7" />
-  <project name="platform/packages/apps/SoundRecorder" path="packages/apps/SoundRecorder" revision="b0e671faf142fa0b933b4f1cd7d186b1f37ebe46" />
-  <project name="platform/packages/apps/SpareParts" path="packages/apps/SpareParts" revision="4db997871e3f4c3f84660815096e5276b47c5c91" />
-  <project name="platform/packages/apps/SpeechRecorder" path="packages/apps/SpeechRecorder" revision="536aa74ff3a77186bef29dc9333a34688fa59d13" />
-  <project name="platform/packages/apps/Stk" path="packages/apps/Stk" revision="115b75461f8e1fb432fe1a892549ca1c96cef497" />
-  <project name="platform/packages/apps/Tag" path="packages/apps/Tag" revision="f830b07335bd2dd794b84507b5390f7d893fe428" />
-  <project name="platform/packages/apps/TvSettings" path="packages/apps/TvSettings" revision="24e45eaf3b4badaf02e449e7f6d07c72e743f521" />
-  <project name="platform/packages/apps/UnifiedEmail" path="packages/apps/UnifiedEmail" revision="d4537c907920f4470b70e91c187ef7a0b31632db" />
-  <project name="platform/packages/apps/VideoEditor" path="packages/apps/VideoEditor" revision="a49ea28e1628f507ae3a564215664c29c5fa1215" />
-  <project name="platform/packages/apps/VoiceDialer" path="packages/apps/VoiceDialer" revision="72df4532dfca9a82e8aef55fcdfce3026d3d3312" />
-  <project name="platform/packages/experimental" path="packages/experimental" revision="588c7cda9c62fb77d23bc089a63cba8a96bc9ffb" />
-  <project name="platform/packages/inputmethods/LatinIME" path="packages/inputmethods/LatinIME" revision="159474f2ae5d13308ca1b92b8a5ccd809ec6a450" />
-  <project name="platform/packages/inputmethods/OpenWnn" path="packages/inputmethods/OpenWnn" revision="59aefa242169b7a51c2381daee58ff22fd1834ce" />
-  <project name="platform/packages/inputmethods/PinyinIME" path="packages/inputmethods/PinyinIME" revision="49aebad1c1cfbbcaa9288ffed5161e79e57c3679" />
-  <project name="platform/packages/providers/ApplicationsProvider" path="packages/providers/ApplicationsProvider" revision="3347f31bd268ca3153abe5def9361f625bd73efd" />
-  <project name="platform/packages/providers/CalendarProvider" path="packages/providers/CalendarProvider" revision="20360f2fdd7ad2de1234b7ed61e3ea120f0dc635" />
-  <project name="platform/packages/providers/ContactsProvider" path="packages/providers/ContactsProvider" revision="6ac2395324c0e7539434b7c68ec738f867d7ed37" />
-  <project name="platform/packages/providers/DownloadProvider" path="packages/providers/DownloadProvider" revision="90e7485d68095b5fc5044dd1bc6cd4dfc485eaa3" />
-  <project name="platform/packages/providers/MediaProvider" path="packages/providers/MediaProvider" revision="501b93fb00db86fe4fb53dc000f6f11587afe4b0" />
-  <project name="platform/packages/providers/PartnerBookmarksProvider" path="packages/providers/PartnerBookmarksProvider" revision="96d0a80af45923767baf449fc8c735c2f71d64ae" />
-  <project name="platform/packages/providers/TelephonyProvider" path="packages/providers/TelephonyProvider" revision="91e705bc7662192ea33f2bac6b0a6c79fc9bc7ab" />
-  <project name="platform/packages/providers/UserDictionaryProvider" path="packages/providers/UserDictionaryProvider" revision="361f35b7b1fe758d93e0952536a298b2ed045a89" />
-  <project name="platform/packages/screensavers/Basic" path="packages/screensavers/Basic" revision="4b5d9d8bea733c4e5876541831f27bf40588b516" />
-  <project name="platform/packages/screensavers/PhotoTable" path="packages/screensavers/PhotoTable" revision="a5e0fee8e923cfc8682eb4431bc3997ed15f649a" />
-  <project name="platform/packages/screensavers/WebView" path="packages/screensavers/WebView" revision="6e0a80f6faed6191acc8ce1b6c79eada09e9e042" />
-  <project name="platform/packages/services/Telephony" path="packages/services/Telephony" revision="aa156251eb0414b8c6546c98769789dc28b38140" />
-  <project name="platform/packages/wallpapers/Basic" path="packages/wallpapers/Basic" revision="2e1d8404b87caf13cde644959f28213f2db09843" />
-  <project name="platform/packages/wallpapers/Galaxy4" path="packages/wallpapers/Galaxy4" revision="34b31b45e75b2e73a770fef1a2f9a862b10f1a57" />
-  <project name="platform/packages/wallpapers/HoloSpiral" path="packages/wallpapers/HoloSpiral" revision="63b75996a7cfb713a6a6feb5c774ba4b46c7d6eb" />
-  <project name="platform/packages/wallpapers/LivePicker" path="packages/wallpapers/LivePicker" revision="8082f92e76774607d62412e8e1191dd940f055ba" />
-  <project name="platform/packages/wallpapers/MagicSmoke" path="packages/wallpapers/MagicSmoke" revision="f01ea4c07914010d52a42130acb7e67d4306fbda" />
-  <project name="platform/packages/wallpapers/MusicVisualization" path="packages/wallpapers/MusicVisualization" revision="72fbcf3a8e4ebee42c36a5887432ca823ef0e4e5" />
-  <project name="platform/packages/wallpapers/NoiseField" path="packages/wallpapers/NoiseField" revision="7d3e52a18a1255baffd7c0675a465f1b85b99f56" />
-  <project name="platform/packages/wallpapers/PhaseBeam" path="packages/wallpapers/PhaseBeam" revision="0da76f35378677f1102e0be218ce1993c0e528b6" />
-  <project groups="pdk" name="platform/pdk" path="pdk" revision="d440d4219412981df7ef90bed65acf29b2e7ea6a" />
-  <project name="platform/prebuilts/android-emulator" path="prebuilts/android-emulator" revision="d6a246c24accff42eb433f5e39d14cb24faf1e58" />
-  <project groups="pdk,darwin" name="platform/prebuilts/clang/darwin-x86/3.1" path="prebuilts/clang/darwin-x86/3.1" revision="426233405bef3c7c825095ab14256c3773894b9b" />
-  <project groups="pdk,darwin" name="platform/prebuilts/clang/darwin-x86/3.2" path="prebuilts/clang/darwin-x86/3.2" revision="af856d77b3cbb1f6afccdc531bee991403c28907" />
-  <project groups="darwin,arm" name="platform/prebuilts/clang/darwin-x86/arm/3.3" path="prebuilts/clang/darwin-x86/arm/3.3" revision="54acc51e28850485e380b55916868a4e1ff17998" />
-  <project groups="pdk,darwin" name="platform/prebuilts/clang/darwin-x86/host/3.4" path="prebuilts/clang/darwin-x86/host/3.4" revision="a798fe00dbd92ad4e5f7123a2e2bc1d805db04f6" />
-  <project groups="pdk,darwin" name="platform/prebuilts/clang/darwin-x86/host/3.5" path="prebuilts/clang/darwin-x86/host/3.5" revision="ce812d27fb78972e71482e93241b9770ca54845d" />
-  <project groups="darwin,mips" name="platform/prebuilts/clang/darwin-x86/mips/3.3" path="prebuilts/clang/darwin-x86/mips/3.3" revision="da3dad928542362835082b2eda44e4dc315d65bb" />
-  <project groups="darwin,x86" name="platform/prebuilts/clang/darwin-x86/x86/3.3" path="prebuilts/clang/darwin-x86/x86/3.3" revision="f67a83f35e30f92b312fbee852184c3f6dc38f34" />
-  <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde" />
-  <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8" />
-  <project groups="linux,arm" name="platform/prebuilts/clang/linux-x86/arm/3.3" path="prebuilts/clang/linux-x86/arm/3.3" revision="2f6d2db9e2af3507d132cf5d286a42fe1d47f7bc" />
-  <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.4" path="prebuilts/clang/linux-x86/host/3.4" revision="fae26a039f79d780ddedcad07f164d9e6c05fc87" />
-  <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="485ffdc99707f81f4201e85bbbb937f23e1e04aa" />
-  <project groups="linux,mips" name="platform/prebuilts/clang/linux-x86/mips/3.3" path="prebuilts/clang/linux-x86/mips/3.3" revision="51f8e2760628588fe268438d612d942c30d13fb2" />
-  <project groups="linux,x86" name="platform/prebuilts/clang/linux-x86/x86/3.3" path="prebuilts/clang/linux-x86/x86/3.3" revision="017a8a67f92a66b29ab17772e50642a7b9d0f8e6" />
-  <project name="platform/prebuilts/devtools" path="prebuilts/devtools" revision="be724be535ea50585d8c625b768ccb63aacd2926" />
-  <project groups="pdk" name="platform/prebuilts/eclipse" path="prebuilts/eclipse" revision="cf9f78f8cf41b16edf9f712598a42743d5cea4af" />
-  <project groups="notdefault,eclipse" name="platform/prebuilts/eclipse-build-deps" path="prebuilts/eclipse-build-deps" revision="ceb739d6a7c10f5fb5a6cf6e1f702453b1361ad3" />
-  <project groups="notdefault,eclipse" name="platform/prebuilts/eclipse-build-deps-sources" path="prebuilts/eclipse-build-deps-sources" revision="8b7d8f6033ffe2d22905d10cf6d57d5bdcbe519b" />
-  <project groups="pdk,darwin,arm" name="platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.8" revision="a261d38eaebb7ff406a6bb60237b36fc61714d46" />
-  <project groups="pdk,darwin,arm" name="platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9" path="prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9" revision="32d722d66d7a935a8b6f8e6ab2d5d8bf0e9e0986" />
-  <project groups="pdk,darwin,arm" name="platform/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/darwin-x86/arm/arm-eabi-4.8" revision="6d08ca9f45ff685648fd13c75bf5cac4b11c19bb" />
-  <project groups="pdk,darwin,arm" name="platform/prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.8" revision="264394c23b2686ce52cd4ffb116ced127aa7f8fc" />
-  <project groups="pdk,darwin" name="platform/prebuilts/gcc/darwin-x86/host/headers" path="prebuilts/gcc/darwin-x86/host/headers" revision="4ac4f7cc41cf3c9e36fc3d6cf37fd1cfa9587a68" />
-  <project groups="pdk,darwin" name="platform/prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1" path="prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1" revision="8834958755acc291d126ba7ee38ac731d04f9c9e" />
-  <project groups="pdk,darwin,mips" name="platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.8" path="prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.8" revision="3b5bef47de8017ff39ef5bfbe801e3fa6b272fab" />
-  <project name="platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9" path="prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9" revision="367a6529b0cc9f5ac5ca69226f583420563fd473" />
-  <project groups="pdk,darwin,mips" name="platform/prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.8" path="prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.8" revision="ba97180acd4251d3acf08530faa4a724af74abd3" />
-  <project groups="pdk,darwin,x86" name="platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.8" revision="c3c37a54f07d51a50e17d63dbf1d92da343f45ce" />
-  <project name="platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9" path="prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9" revision="a7c5a1df753fd3a24494d5e1fe00211048be5c1d" />
-  <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="7334f0a7a872700d0aaf00bea75917c077c45530" />
-  <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" revision="a3f0180676c6b6cd9c664704f86855d3404ae4dd" />
-  <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="26e93f6af47f7bd3a9beb5c102a5f45e19bfa38a" />
-  <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="d9735fc81434f2af2c44d86ca57740c673c8d9bc" />
-  <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="eb5c9f0ae36bf964f6855bde54e1b387e2c26bb6" />
-  <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="1b0544da652fda90a41a1f69889d6b137ce20fb9" />
-  <project name="platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" revision="2725a175a32032fb9a63e247c176ecc3d448ea27" />
-  <project groups="pdk,linux,mips" name="platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.8" path="prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.8" revision="38586de6b44714b4adcf21119fe6b267e33f3ca6" />
-  <project name="platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9" path="prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9" revision="eabc7ae8ed527ee3d4517196732fa3f3e8939a28" />
-  <project groups="pdk,linux,mips" name="platform/prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.8" path="prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.8" revision="c06b9b305c365163c99d4ffba49ac37ce2716024" />
-  <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="e08fa7e57a573a9baa5ccd8d4b8d73cc871f9b48" />
-  <project name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9" revision="e99278016e6285363bc20d1b35d4b9b5c4e8b0a0" />
-  <project name="platform/prebuilts/gradle-plugin" path="prebuilts/gradle-plugin" revision="e7814a3cbb96742ff74505a1fc152cb534fbf2f9" />
-  <project name="platform/prebuilts/maven_repo/android" path="prebuilts/maven_repo/android" revision="0dbe3df0f057de9e83e599b9be2ca866c673130d" />
-  <project groups="pdk" name="platform/prebuilts/misc" path="prebuilts/misc" revision="3cc2e316acf9da501479bbfd85159407239994d2" />
-  <project groups="pdk" name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="7a8bc5c36d519c41de61765ff94245f56c4bed7a" />
-  <project groups="darwin" name="platform/prebuilts/python/darwin-x86/2.7.5" path="prebuilts/python/darwin-x86/2.7.5" revision="2bdd4fd418614c7c0101147d02199d0e47c4980e" />
-  <project groups="linux" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="6fbc8802b3b68d24a4ee83f164b22490cf702ff2" />
-  <project groups="pdk" name="platform/prebuilts/qemu-kernel" path="prebuilts/qemu-kernel" revision="5f91f38eac40a8465f3a7e4aa298a75afcf2936a" />
-  <project name="platform/prebuilts/runtime" path="prebuilts/runtime" revision="56e663b8ec9cd0df9ce5afdc7b7d56460faf44c8" />
-  <project groups="pdk" name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="52043ca65e06bc84779dd8d3e55e72ad04bcef59" />
-  <project groups="pdk,tools" name="platform/prebuilts/tools" path="prebuilts/tools" revision="130c3d0a1a484d617531d75ddd50714f68213cbb" />
-  <project name="platform/sdk" path="sdk" revision="1af9ef83f5f6c6fd9202d5bdd8d4248a4eb855aa" />
-  <project groups="pdk" name="platform/system/core" path="system/core" revision="cddc97cb3a927d179a42e0fec77f0d267fcd74d1" />
-  <project groups="pdk" name="platform/system/extras" path="system/extras" revision="97ed949ec7bef088ca3d06fb7b5f3bdad9a5103c" />
-  <project name="platform/system/keymaster" path="system/keymaster" revision="7a70abbf29293b30bb1e7ed3a58deb40f8774a53" />
-  <project groups="pdk" name="platform/system/media" path="system/media" revision="77f0f32b32adc5ba1134e7a68e4d907c4f695eb6" />
-  <project groups="pdk" name="platform/system/netd" path="system/netd" revision="f5d949ef0991737af9daa7ba702cc2ec638e435b" />
-  <project groups="pdk" name="platform/system/security" path="system/security" revision="0387a7fd23021b904612101b727a2060847f6169" />
-  <project groups="pdk" name="platform/system/vold" path="system/vold" revision="c0c2867518eed4539444434c95fad8185a6ac08e" />
-  <project groups="notdefault,tools" name="platform/tools/adt/eclipse" path="tools/adt/eclipse" revision="ede2ed86419bb4c78428f1ac09825b1a247d8e24" />
-  <project groups="notdefault,tools" name="platform/tools/adt/idea" path="tools/adt/idea" revision="50a5da1af3e851df7aff37c291541000685bcad4" />
-  <project groups="notdefault,tools" name="platform/tools/base" path="tools/base" revision="4dc06057ba77596807e2d28c715719f240f71549" />
-  <project groups="notdefault,tools" name="platform/tools/build" path="tools/build" revision="69c4b95102b4b9862bfba68b3eaf5b7537a705ee" />
-  <project groups="notdefault,tools" name="platform/tools/emulator" path="tools/emulator" revision="c427e5d5227ba9413307670a5d758d9ced394a7e" />
-  <project groups="tools" name="platform/tools/external/fat32lib" path="tools/external/fat32lib" revision="3880776e41ff7def06e351720f2d162f88b58a03" />
-  <project groups="tools" name="platform/tools/external/gradle" path="tools/external/gradle" revision="842b7a27df8606faa29b0875a13270701eb78dd8" />
-  <project groups="notdefault,tools" name="platform/tools/idea" path="tools/idea" revision="12356153d01fcde14dd3a06948cfded92c20d068" />
-  <project groups="notdefault,motodev" name="platform/tools/motodev" path="tools/motodev" revision="69989786cefbde82527960a1e100ec9afba46a98" />
-  <project groups="notdefault,tools" name="platform/tools/studio/cloud" path="tools/studio/cloud" revision="839eb097c5fc73f91a722f1457a2e8e11eb4e1a5" />
-  <project groups="notdefault,tools" name="platform/tools/swt" path="tools/swt" revision="aaf3131b0e4b15d39156a6e94e5da06b0183d61d" />
-</manifest>
diff --git a/gyp/buildbot/buildbot_run.py b/gyp/buildbot/buildbot_run.py
deleted file mode 100755
index 9a2b71f1b3..0000000000
--- a/gyp/buildbot/buildbot_run.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 Google Inc. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Argument-less script to select what to run on the buildbots."""
-
-import os
-import shutil
-import subprocess
-import sys
-
-
-BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__))
-TRUNK_DIR = os.path.dirname(BUILDBOT_DIR)
-ROOT_DIR = os.path.dirname(TRUNK_DIR)
-CMAKE_DIR = os.path.join(ROOT_DIR, 'cmake')
-CMAKE_BIN_DIR = os.path.join(CMAKE_DIR, 'bin')
-OUT_DIR = os.path.join(TRUNK_DIR, 'out')
-
-
-def CallSubProcess(*args, **kwargs):
-  """Wrapper around subprocess.call which treats errors as build exceptions."""
-  with open(os.devnull) as devnull_fd:
-    retcode = subprocess.call(stdin=devnull_fd, *args, **kwargs)
-  if retcode != 0:
-    print '@@@STEP_EXCEPTION@@@'
-    sys.exit(1)
-
-
-def PrepareCmake():
-  """Build CMake 2.8.8 since the version in Precise is 2.8.7."""
-  if os.environ['BUILDBOT_CLOBBER'] == '1':
-    print '@@@BUILD_STEP Clobber CMake checkout@@@'
-    shutil.rmtree(CMAKE_DIR)
-
-  # We always build CMake 2.8.8, so no need to do anything
-  # if the directory already exists.
-  if os.path.isdir(CMAKE_DIR):
-    return
-
-  print '@@@BUILD_STEP Initialize CMake checkout@@@'
-  os.mkdir(CMAKE_DIR)
-
-  print '@@@BUILD_STEP Sync CMake@@@'
-  CallSubProcess(
-      ['git', 'clone',
-       '--depth', '1',
-       '--single-branch',
-       '--branch', 'v2.8.8',
-       '--',
-       'git://cmake.org/cmake.git',
-       CMAKE_DIR],
-      cwd=CMAKE_DIR)
-
-  print '@@@BUILD_STEP Build CMake@@@'
-  CallSubProcess(
-      ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR],
-      cwd=CMAKE_DIR)
-
-  CallSubProcess( ['make', 'cmake'], cwd=CMAKE_DIR)
-
-
-def GypTestFormat(title, format=None, msvs_version=None, tests=[]):
-  """Run the gyp tests for a given format, emitting annotator tags.
-
-  See annotator docs at:
-    https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-build-infrastructure/buildbot-annotations
-  Args:
-    format: gyp format to test.
-  Returns:
-    0 for sucesss, 1 for failure.
-  """
-  if not format:
-    format = title
-
-  print '@@@BUILD_STEP ' + title + '@@@'
-  sys.stdout.flush()
-  env = os.environ.copy()
-  if msvs_version:
-    env['GYP_MSVS_VERSION'] = msvs_version
-  command = ' '.join(
-      [sys.executable, 'gyp/gyptest.py',
-       '--all',
-       '--passed',
-       '--format', format,
-       '--path', CMAKE_BIN_DIR,
-       '--chdir', 'gyp'] + tests)
-  retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True)
-  if retcode:
-    # Emit failure tag, and keep going.
-    print '@@@STEP_FAILURE@@@'
-    return 1
-  return 0
-
-
-def GypBuild():
-  # Dump out/ directory.
-  print '@@@BUILD_STEP cleanup@@@'
-  print 'Removing %s...' % OUT_DIR
-  shutil.rmtree(OUT_DIR, ignore_errors=True)
-  print 'Done.'
-
-  retcode = 0
-  if sys.platform.startswith('linux'):
-    retcode += GypTestFormat('ninja')
-    retcode += GypTestFormat('make')
-    PrepareCmake()
-    retcode += GypTestFormat('cmake')
-  elif sys.platform == 'darwin':
-    retcode += GypTestFormat('ninja')
-    retcode += GypTestFormat('xcode')
-    retcode += GypTestFormat('make')
-  elif sys.platform == 'win32':
-    retcode += GypTestFormat('ninja')
-    if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64':
-      retcode += GypTestFormat('msvs-ninja-2013', format='msvs-ninja',
-                               msvs_version='2013',
-                               tests=[
-                                  r'test\generator-output\gyptest-actions.py',
-                                  r'test\generator-output\gyptest-relocate.py',
-                                  r'test\generator-output\gyptest-rules.py'])
-      retcode += GypTestFormat('msvs-2013', format='msvs', msvs_version='2013')
-  else:
-    raise Exception('Unknown platform')
-  if retcode:
-    # TODO(bradnelson): once the annotator supports a postscript (section for
-    #     after the build proper that could be used for cumulative failures),
-    #     use that instead of this. This isolates the final return value so
-    #     that it isn't misattributed to the last stage.
-    print '@@@BUILD_STEP failures@@@'
-    sys.exit(retcode)
-
-
-if __name__ == '__main__':
-  GypBuild()
diff --git a/gyp/buildbot/commit_queue/OWNERS b/gyp/buildbot/commit_queue/OWNERS
deleted file mode 100644
index b269c198b4..0000000000
--- a/gyp/buildbot/commit_queue/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-set noparent
-bradnelson@chromium.org
-bradnelson@google.com
-iannucci@chromium.org
-scottmg@chromium.org
-thakis@chromium.org
diff --git a/gyp/buildbot/commit_queue/README b/gyp/buildbot/commit_queue/README
deleted file mode 100644
index 9428497883..0000000000
--- a/gyp/buildbot/commit_queue/README
+++ /dev/null
@@ -1,3 +0,0 @@
-cq_config.json describes the trybots that must pass in order
-to land a change through the commit queue.
-Comments are here as the file is strictly JSON.
diff --git a/gyp/buildbot/commit_queue/cq_config.json b/gyp/buildbot/commit_queue/cq_config.json
deleted file mode 100644
index 656c21e54f..0000000000
--- a/gyp/buildbot/commit_queue/cq_config.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "trybots": {
-        "launched": {
-            "tryserver.nacl": {
-                "gyp-presubmit": ["defaulttests"],
-                "gyp-linux": ["defaulttests"],
-                "gyp-mac": ["defaulttests"],
-                "gyp-win32": ["defaulttests"],
-                "gyp-win64": ["defaulttests"]
-            }
-        },
-        "triggered": {
-        }
-    }
-}
diff --git a/gyp/gyptest.py b/gyp/gyptest.py
deleted file mode 100755
index 8e4fc47d5c..0000000000
--- a/gyp/gyptest.py
+++ /dev/null
@@ -1,274 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2012 Google Inc. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-__doc__ = """
-gyptest.py -- test runner for GYP tests.
-"""
-
-import os
-import optparse
-import subprocess
-import sys
-
-class CommandRunner(object):
-  """
-  Executor class for commands, including "commands" implemented by
-  Python functions.
-  """
-  verbose = True
-  active = True
-
-  def __init__(self, dictionary={}):
-    self.subst_dictionary(dictionary)
-
-  def subst_dictionary(self, dictionary):
-    self._subst_dictionary = dictionary
-
-  def subst(self, string, dictionary=None):
-    """
-    Substitutes (via the format operator) the values in the specified
-    dictionary into the specified command.
-
-    The command can be an (action, string) tuple.  In all cases, we
-    perform substitution on strings and don't worry if something isn't
-    a string.  (It's probably a Python function to be executed.)
-    """
-    if dictionary is None:
-      dictionary = self._subst_dictionary
-    if dictionary:
-      try:
-        string = string % dictionary
-      except TypeError:
-        pass
-    return string
-
-  def display(self, command, stdout=None, stderr=None):
-    if not self.verbose:
-      return
-    if type(command) == type(()):
-      func = command[0]
-      args = command[1:]
-      s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
-    if type(command) == type([]):
-      # TODO:  quote arguments containing spaces
-      # TODO:  handle meta characters?
-      s = ' '.join(command)
-    else:
-      s = self.subst(command)
-    if not s.endswith('\n'):
-      s += '\n'
-    sys.stdout.write(s)
-    sys.stdout.flush()
-
-  def execute(self, command, stdout=None, stderr=None):
-    """
-    Executes a single command.
-    """
-    if not self.active:
-      return 0
-    if type(command) == type(''):
-      command = self.subst(command)
-      cmdargs = shlex.split(command)
-      if cmdargs[0] == 'cd':
-         command = (os.chdir,) + tuple(cmdargs[1:])
-    if type(command) == type(()):
-      func = command[0]
-      args = command[1:]
-      return func(*args)
-    else:
-      if stdout is sys.stdout:
-        # Same as passing sys.stdout, except python2.4 doesn't fail on it.
-        subout = None
-      else:
-        # Open pipe for anything else so Popen works on python2.4.
-        subout = subprocess.PIPE
-      if stderr is sys.stderr:
-        # Same as passing sys.stderr, except python2.4 doesn't fail on it.
-        suberr = None
-      elif stderr is None:
-        # Merge with stdout if stderr isn't specified.
-        suberr = subprocess.STDOUT
-      else:
-        # Open pipe for anything else so Popen works on python2.4.
-        suberr = subprocess.PIPE
-      p = subprocess.Popen(command,
-                           shell=(sys.platform == 'win32'),
-                           stdout=subout,
-                           stderr=suberr)
-      p.wait()
-      if stdout is None:
-        self.stdout = p.stdout.read()
-      elif stdout is not sys.stdout:
-        stdout.write(p.stdout.read())
-      if stderr not in (None, sys.stderr):
-        stderr.write(p.stderr.read())
-      return p.returncode
-
-  def run(self, command, display=None, stdout=None, stderr=None):
-    """
-    Runs a single command, displaying it first.
-    """
-    if display is None:
-      display = command
-    self.display(display)
-    return self.execute(command, stdout, stderr)
-
-
-class Unbuffered(object):
-  def __init__(self, fp):
-    self.fp = fp
-  def write(self, arg):
-    self.fp.write(arg)
-    self.fp.flush()
-  def __getattr__(self, attr):
-    return getattr(self.fp, attr)
-
-sys.stdout = Unbuffered(sys.stdout)
-sys.stderr = Unbuffered(sys.stderr)
-
-
-def is_test_name(f):
-  return f.startswith('gyptest') and f.endswith('.py')
-
-
-def find_all_gyptest_files(directory):
-  result = []
-  for root, dirs, files in os.walk(directory):
-    if '.svn' in dirs:
-      dirs.remove('.svn')
-    result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ])
-  result.sort()
-  return result
-
-
-def main(argv=None):
-  if argv is None:
-    argv = sys.argv
-
-  usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
-  parser = optparse.OptionParser(usage=usage)
-  parser.add_option("-a", "--all", action="store_true",
-            help="run all tests")
-  parser.add_option("-C", "--chdir", action="store", default=None,
-            help="chdir to the specified directory")
-  parser.add_option("-f", "--format", action="store", default='',
-            help="run tests with the specified formats")
-  parser.add_option("-G", '--gyp_option', action="append", default=[],
-            help="Add -G options to the gyp command line")
-  parser.add_option("-l", "--list", action="store_true",
-            help="list available tests and exit")
-  parser.add_option("-n", "--no-exec", action="store_true",
-            help="no execute, just print the command line")
-  parser.add_option("--passed", action="store_true",
-            help="report passed tests")
-  parser.add_option("--path", action="append", default=[],
-            help="additional $PATH directory")
-  parser.add_option("-q", "--quiet", action="store_true",
-            help="quiet, don't print test command lines")
-  opts, args = parser.parse_args(argv[1:])
-
-  if opts.chdir:
-    os.chdir(opts.chdir)
-
-  if opts.path:
-    extra_path = [os.path.abspath(p) for p in opts.path]
-    extra_path = os.pathsep.join(extra_path)
-    os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH']
-
-  if not args:
-    if not opts.all:
-      sys.stderr.write('Specify -a to get all tests.\n')
-      return 1
-    args = ['test']
-
-  tests = []
-  for arg in args:
-    if os.path.isdir(arg):
-      tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
-    else:
-      if not is_test_name(os.path.basename(arg)):
-        print >>sys.stderr, arg, 'is not a valid gyp test name.'
-        sys.exit(1)
-      tests.append(arg)
-
-  if opts.list:
-    for test in tests:
-      print test
-    sys.exit(0)
-
-  CommandRunner.verbose = not opts.quiet
-  CommandRunner.active = not opts.no_exec
-  cr = CommandRunner()
-
-  os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
-  if not opts.quiet:
-    sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
-
-  passed = []
-  failed = []
-  no_result = []
-
-  if opts.format:
-    format_list = opts.format.split(',')
-  else:
-    # TODO:  not duplicate this mapping from pylib/gyp/__init__.py
-    format_list = {
-      'aix5':     ['make'],
-      'freebsd7': ['make'],
-      'freebsd8': ['make'],
-      'openbsd5': ['make'],
-      'cygwin':   ['msvs'],
-      'win32':    ['msvs', 'ninja'],
-      'linux2':   ['make', 'ninja'],
-      'linux3':   ['make', 'ninja'],
-      'darwin':   ['make', 'ninja', 'xcode', 'xcode-ninja'],
-    }[sys.platform]
-
-  for format in format_list:
-    os.environ['TESTGYP_FORMAT'] = format
-    if not opts.quiet:
-      sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
-
-    gyp_options = []
-    for option in opts.gyp_option:
-      gyp_options += ['-G', option]
-    if gyp_options and not opts.quiet:
-      sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
-
-    for test in tests:
-      status = cr.run([sys.executable, test] + gyp_options,
-                      stdout=sys.stdout,
-                      stderr=sys.stderr)
-      if status == 2:
-        no_result.append(test)
-      elif status:
-        failed.append(test)
-      else:
-        passed.append(test)
-
-  if not opts.quiet:
-    def report(description, tests):
-      if tests:
-        if len(tests) == 1:
-          sys.stdout.write("\n%s the following test:\n" % description)
-        else:
-          fmt = "\n%s the following %d tests:\n"
-          sys.stdout.write(fmt % (description, len(tests)))
-        sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
-
-    if opts.passed:
-      report("Passed", passed)
-    report("Failed", failed)
-    report("No result from", no_result)
-
-  if failed:
-    return 1
-  else:
-    return 0
-
-
-if __name__ == "__main__":
-  sys.exit(main())
diff --git a/gyp/pylib/gyp/MSVSSettings.py b/gyp/pylib/gyp/MSVSSettings.py
index 4985756bdd..8073f92b8d 100644
--- a/gyp/pylib/gyp/MSVSSettings.py
+++ b/gyp/pylib/gyp/MSVSSettings.py
@@ -14,6 +14,10 @@
 MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
 """
 
+from __future__ import print_function
+
+from gyp import string_types
+
 import sys
 import re
 
@@ -106,11 +110,11 @@ class _String(_Type):
   """A setting that's just a string."""
 
   def ValidateMSVS(self, value):
-    if not isinstance(value, basestring):
+    if not isinstance(value, string_types):
       raise ValueError('expected string; got %r' % value)
 
   def ValidateMSBuild(self, value):
-    if not isinstance(value, basestring):
+    if not isinstance(value, string_types):
       raise ValueError('expected string; got %r' % value)
 
   def ConvertToMSBuild(self, value):
@@ -122,11 +126,11 @@ class _StringList(_Type):
   """A settings that's a list of strings."""
 
   def ValidateMSVS(self, value):
-    if not isinstance(value, basestring) and not isinstance(value, list):
+    if not isinstance(value, string_types) and not isinstance(value, list):
       raise ValueError('expected string list; got %r' % value)
 
   def ValidateMSBuild(self, value):
-    if not isinstance(value, basestring) and not isinstance(value, list):
+    if not isinstance(value, string_types) and not isinstance(value, list):
       raise ValueError('expected string list; got %r' % value)
 
   def ConvertToMSBuild(self, value):
@@ -400,7 +404,7 @@ def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
 
   if unrecognized:
     # We don't know this setting. Give a warning.
-    print >> stderr, error_msg
+    print(error_msg, file=stderr)
 
 
 def FixVCMacroSlashes(s):
@@ -417,7 +421,7 @@ def FixVCMacroSlashes(s):
 
 
 def ConvertVCMacrosToMSBuild(s):
-  """Convert the the MSVS macros found in the string to the MSBuild equivalent.
+  """Convert the MSVS macros found in the string to the MSBuild equivalent.
 
   This list is probably not exhaustive.  Add as needed.
   """
@@ -433,7 +437,7 @@ def ConvertVCMacrosToMSBuild(s):
         '$(PlatformName)': '$(Platform)',
         '$(SafeInputName)': '%(Filename)',
     }
-    for old, new in replace_map.iteritems():
+    for old, new in replace_map.items():
       s = s.replace(old, new)
     s = FixVCMacroSlashes(s)
   return s
@@ -453,17 +457,17 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
       dictionaries of settings and their values.
   """
   msbuild_settings = {}
-  for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems():
+  for msvs_tool_name, msvs_tool_settings in msvs_settings.items():
     if msvs_tool_name in _msvs_to_msbuild_converters:
       msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name]
-      for msvs_setting, msvs_value in msvs_tool_settings.iteritems():
+      for msvs_setting, msvs_value in msvs_tool_settings.items():
         if msvs_setting in msvs_tool:
           # Invoke the translation function.
           try:
             msvs_tool[msvs_setting](msvs_value, msbuild_settings)
-          except ValueError, e:
-            print >> stderr, ('Warning: while converting %s/%s to MSBuild, '
-                              '%s' % (msvs_tool_name, msvs_setting, e))
+          except ValueError as e:
+            print('Warning: while converting %s/%s to MSBuild, '
+                              '%s' % (msvs_tool_name, msvs_setting, e), file=stderr)
         else:
           _ValidateExclusionSetting(msvs_setting,
                                     msvs_tool,
@@ -472,8 +476,8 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
                                      (msvs_tool_name, msvs_setting)),
                                     stderr)
     else:
-      print >> stderr, ('Warning: unrecognized tool %s while converting to '
-                        'MSBuild.' % msvs_tool_name)
+      print('Warning: unrecognized tool %s while converting to '
+                        'MSBuild.' % msvs_tool_name, file=stderr)
   return msbuild_settings
 
 
@@ -513,13 +517,13 @@ def _ValidateSettings(validators, settings, stderr):
   for tool_name in settings:
     if tool_name in validators:
       tool_validators = validators[tool_name]
-      for setting, value in settings[tool_name].iteritems():
+      for setting, value in settings[tool_name].items():
         if setting in tool_validators:
           try:
             tool_validators[setting](value)
-          except ValueError, e:
-            print >> stderr, ('Warning: for %s/%s, %s' %
-                              (tool_name, setting, e))
+          except ValueError as e:
+            print('Warning: for %s/%s, %s' %
+                              (tool_name, setting, e), file=stderr)
         else:
           _ValidateExclusionSetting(setting,
                                     tool_validators,
@@ -528,7 +532,7 @@ def _ValidateSettings(validators, settings, stderr):
                                     stderr)
 
     else:
-      print >> stderr, ('Warning: unrecognized tool %s' % tool_name)
+      print('Warning: unrecognized tool %s' % (tool_name), file=stderr)
 
 
 # MSVS and MBuild names of the tools.
diff --git a/gyp/pylib/gyp/MSVSUserFile.py b/gyp/pylib/gyp/MSVSUserFile.py
index 6c07e9a893..2264d64015 100644
--- a/gyp/pylib/gyp/MSVSUserFile.py
+++ b/gyp/pylib/gyp/MSVSUserFile.py
@@ -91,7 +91,7 @@ def AddDebugSettings(self, config_name, command, environment = {},
 
     if environment and isinstance(environment, dict):
       env_list = ['%s="%s"' % (key, val)
-                  for (key,val) in environment.iteritems()]
+                  for (key,val) in environment.items()]
       environment = ' '.join(env_list)
     else:
       environment = ''
@@ -135,7 +135,7 @@ def AddDebugSettings(self, config_name, command, environment = {},
   def WriteIfChanged(self):
     """Writes the user file."""
     configs = ['Configurations']
-    for config, spec in sorted(self.configurations.iteritems()):
+    for config, spec in sorted(self.configurations.items()):
       configs.append(spec)
 
     content = ['VisualStudioUserFile',
diff --git a/gyp/pylib/gyp/MSVSUtil.py b/gyp/pylib/gyp/MSVSUtil.py
index 0b32e91180..c8187eb331 100644
--- a/gyp/pylib/gyp/MSVSUtil.py
+++ b/gyp/pylib/gyp/MSVSUtil.py
@@ -235,7 +235,7 @@ def InsertLargePdbShims(target_list, target_dicts, vars):
 
     # Set up the shim to output its PDB to the same location as the final linker
     # target.
-    for config_name, config in shim_dict.get('configurations').iteritems():
+    for config_name, config in shim_dict.get('configurations').items():
       pdb_path = _GetPdbPath(target_dict, config_name, vars)
 
       # A few keys that we don't want to propagate.
diff --git a/gyp/pylib/gyp/MSVSVersion.py b/gyp/pylib/gyp/MSVSVersion.py
index d9bfa684fa..293b4145c1 100644
--- a/gyp/pylib/gyp/MSVSVersion.py
+++ b/gyp/pylib/gyp/MSVSVersion.py
@@ -158,7 +158,7 @@ def _RegistryQuery(key, value=None):
   text = None
   try:
     text = _RegistryQueryBase('Sysnative', key, value)
-  except OSError, e:
+  except OSError as e:
     if e.errno == errno.ENOENT:
       text = _RegistryQueryBase('System32', key, value)
     else:
@@ -176,12 +176,18 @@ def _RegistryGetValueUsingWinReg(key, value):
     contents of the registry key's value, or None on failure.  Throws
     ImportError if _winreg is unavailable.
   """
-  import _winreg
+  try:
+      # Python 2
+      from _winreg import OpenKey, QueryValueEx
+  except ImportError:
+      # Python 3
+      from winreg import OpenKey, QueryValueEx
+
   try:
     root, subkey = key.split('\\', 1)
     assert root == 'HKLM'  # Only need HKLM for now.
-    with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
-      return _winreg.QueryValueEx(hkey, value)[0]
+    with OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
+      return QueryValueEx(hkey, value)[0]
   except WindowsError:
     return None
 
diff --git a/gyp/pylib/gyp/__init__.py b/gyp/pylib/gyp/__init__.py
index 668f38b60d..d5fa9ecf50 100755
--- a/gyp/pylib/gyp/__init__.py
+++ b/gyp/pylib/gyp/__init__.py
@@ -4,6 +4,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import copy
 import gyp.input
 import optparse
@@ -14,6 +16,13 @@
 import traceback
 from gyp.common import GypError
 
+try:
+    # Python 2
+    string_types = basestring
+except NameError:
+    # Python 3
+    string_types = str
+
 # Default debug modes for GYP
 debug = {}
 
@@ -34,8 +43,8 @@ def DebugOutput(mode, message, *args):
       pass
     if args:
       message %= args
-    print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
-                              ctx[1], ctx[2], message)
+    print('%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
+                              ctx[1], ctx[2], message))
 
 def FindBuildFiles():
   extension = '.gyp'
@@ -207,7 +216,7 @@ def Noop(value):
   # We always want to ignore the environment when regenerating, to avoid
   # duplicate or changed flags in the environment at the time of regeneration.
   flags = ['--ignore-environment']
-  for name, metadata in options._regeneration_metadata.iteritems():
+  for name, metadata in options._regeneration_metadata.items():
     opt = metadata['opt']
     value = getattr(options, name)
     value_predicate = metadata['type'] == 'path' and FixPath or Noop
@@ -226,12 +235,12 @@ def Noop(value):
           (action == 'store_false' and not value)):
         flags.append(opt)
       elif options.use_environment and env_name:
-        print >>sys.stderr, ('Warning: environment regeneration unimplemented '
+        print('Warning: environment regeneration unimplemented '
                              'for %s flag %r env_name %r' % (action, opt,
-                                                             env_name))
+                                                             env_name), file=sys.stderr)
     else:
-      print >>sys.stderr, ('Warning: regeneration unimplemented for action %r '
-                           'flag %r' % (action, opt))
+      print('Warning: regeneration unimplemented for action %r '
+                           'flag %r' % (action, opt), file=sys.stderr)
 
   return flags
 
@@ -410,7 +419,7 @@ def gyp_main(args):
     for option, value in sorted(options.__dict__.items()):
       if option[0] == '_':
         continue
-      if isinstance(value, basestring):
+      if isinstance(value, string_types):
         DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
       else:
         DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)
@@ -432,7 +441,7 @@ def gyp_main(args):
       build_file_dir = os.path.abspath(os.path.dirname(build_file))
       build_file_dir_components = build_file_dir.split(os.path.sep)
       components_len = len(build_file_dir_components)
-      for index in xrange(components_len - 1, -1, -1):
+      for index in range(components_len - 1, -1, -1):
         if build_file_dir_components[index] == 'src':
           options.depth = os.path.sep.join(build_file_dir_components)
           break
@@ -475,7 +484,7 @@ def gyp_main(args):
   if home_dot_gyp != None:
     default_include = os.path.join(home_dot_gyp, 'include.gypi')
     if os.path.exists(default_include):
-      print 'Using overrides found in ' + default_include
+      print('Using overrides found in ' + default_include)
       includes.append(default_include)
 
   # Command-line --include files come after the default include.
@@ -536,7 +545,7 @@ def gyp_main(args):
 def main(args):
   try:
     return gyp_main(args)
-  except GypError, e:
+  except GypError as e:
     sys.stderr.write("gyp: %s\n" % e)
     return 1
 
diff --git a/gyp/pylib/gyp/common.py b/gyp/pylib/gyp/common.py
index 256e3f3a6b..b7bae925f4 100644
--- a/gyp/pylib/gyp/common.py
+++ b/gyp/pylib/gyp/common.py
@@ -363,7 +363,7 @@ def close(self):
         same = False
         try:
           same = filecmp.cmp(self.tmp_path, filename, False)
-        except OSError, e:
+        except OSError as e:
           if e.errno != errno.ENOENT:
             raise
 
@@ -382,9 +382,9 @@ def close(self):
           #
           # No way to get the umask without setting a new one?  Set a safe one
           # and then set it back to the old value.
-          umask = os.umask(077)
+          umask = os.umask(0o77)
           os.umask(umask)
-          os.chmod(self.tmp_path, 0666 & ~umask)
+          os.chmod(self.tmp_path, 0o666 & ~umask)
           if sys.platform == 'win32' and os.path.exists(filename):
             # NOTE: on windows (but not cygwin) rename will not replace an
             # existing file, so it must be preceded with a remove. Sadly there
@@ -429,6 +429,10 @@ def GetFlavor(params):
     return 'netbsd'
   if sys.platform.startswith('aix'):
     return 'aix'
+  if sys.platform.startswith('zos'):
+    return 'zos'
+  if sys.platform.startswith('os390'):
+    return 'zos'
 
   return 'linux'
 
@@ -460,7 +464,7 @@ def CopyTool(flavor, out_path):
         ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:]))
 
   # Make file executable.
-  os.chmod(tool_path, 0755)
+  os.chmod(tool_path, 0o755)
 
 
 # From Alex Martelli,
diff --git a/gyp/pylib/gyp/easy_xml.py b/gyp/pylib/gyp/easy_xml.py
index 2b0bb60cb4..7c3f621f1f 100644
--- a/gyp/pylib/gyp/easy_xml.py
+++ b/gyp/pylib/gyp/easy_xml.py
@@ -4,6 +4,8 @@
 
 import re
 import os
+import locale
+from functools import reduce
 
 
 def XmlToString(content, encoding='utf-8', pretty=False):
@@ -79,7 +81,7 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
   # Optionally in second position is a dictionary of the attributes.
   rest = specification[1:]
   if rest and isinstance(rest[0], dict):
-    for at, val in sorted(rest[0].iteritems()):
+    for at, val in sorted(rest[0].items()):
       xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
     rest = rest[1:]
   if rest:
@@ -115,11 +117,10 @@ def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
   xml_string = XmlToString(content, encoding, pretty)
   if win32 and os.linesep != '\r\n':
     xml_string = xml_string.replace('\n', '\r\n')
-    
-  try:
-    xml_string = xml_string.encode(encoding)
-  except Exception:
-    xml_string = unicode(xml_string, 'latin-1').encode(encoding)
+
+  default_encoding = locale.getdefaultlocale()[1]
+  if default_encoding.upper() != encoding.upper():
+    xml_string = xml_string.decode(default_encoding).encode(encoding)
 
   # Get the old content
   try:
diff --git a/gyp/pylib/gyp/flock_tool.py b/gyp/pylib/gyp/flock_tool.py
index b38d8660f7..81fb79d136 100755
--- a/gyp/pylib/gyp/flock_tool.py
+++ b/gyp/pylib/gyp/flock_tool.py
@@ -39,7 +39,7 @@ def ExecFlock(self, lockfile, *cmd_list):
     # where fcntl.flock(fd, LOCK_EX) always fails
     # with EBADF, that's why we use this F_SETLK
     # hack instead.
-    fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666)
+    fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
     if sys.platform.startswith('aix'):
       # Python on AIX is compiled with LARGEFILE support, which changes the
       # struct size.
diff --git a/gyp/pylib/gyp/generator/analyzer.py b/gyp/pylib/gyp/generator/analyzer.py
index 921c1a6b71..dc17c96524 100644
--- a/gyp/pylib/gyp/generator/analyzer.py
+++ b/gyp/pylib/gyp/generator/analyzer.py
@@ -62,6 +62,8 @@
 then the "all" target includes "b1" and "b2".
 """
 
+from __future__ import print_function
+
 import gyp.common
 import gyp.ninja_syntax as ninja_syntax
 import json
@@ -155,7 +157,7 @@ def _AddSources(sources, base_path, base_path_components, result):
       continue
     result.append(base_path + source)
     if debug:
-      print 'AddSource', org_source, result[len(result) - 1]
+      print('AddSource', org_source, result[len(result) - 1])
 
 
 def _ExtractSourcesFromAction(action, base_path, base_path_components,
@@ -185,7 +187,7 @@ def _ExtractSources(target, target_dict, toplevel_dir):
     base_path += '/'
 
   if debug:
-    print 'ExtractSources', target, base_path
+    print('ExtractSources', target, base_path)
 
   results = []
   if 'sources' in target_dict:
@@ -278,7 +280,7 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir):
   the root of the source tree."""
   if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
     if debug:
-      print 'gyp file modified', build_file
+      print('gyp file modified', build_file)
     return True
 
   # First element of included_files is the file itself.
@@ -291,8 +293,8 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir):
         _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
     if _ToLocalPath(toplevel_dir, rel_include_file) in files:
       if debug:
-        print 'included gyp file modified, gyp_file=', build_file, \
-            'included file=', rel_include_file
+        print('included gyp file modified, gyp_file=', build_file,
+              'included file=', rel_include_file)
       return True
   return False
 
@@ -373,7 +375,7 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
     # If a build file (or any of its included files) is modified we assume all
     # targets in the file are modified.
     if build_file_in_files[build_file]:
-      print 'matching target from modified build file', target_name
+      print('matching target from modified build file', target_name)
       target.match_status = MATCH_STATUS_MATCHES
       matching_targets.append(target)
     else:
@@ -381,7 +383,7 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
                                 toplevel_dir)
       for source in sources:
         if _ToGypPath(os.path.normpath(source)) in files:
-          print 'target', target_name, 'matches', source
+          print('target', target_name, 'matches', source)
           target.match_status = MATCH_STATUS_MATCHES
           matching_targets.append(target)
           break
@@ -433,7 +435,7 @@ def _DoesTargetDependOnMatchingTargets(target):
   for dep in target.deps:
     if _DoesTargetDependOnMatchingTargets(dep):
       target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
-      print '\t', target.name, 'matches by dep', dep.name
+      print('\t', target.name, 'matches by dep', dep.name)
       return True
   target.match_status = MATCH_STATUS_DOESNT_MATCH
   return False
@@ -445,7 +447,7 @@ def _GetTargetsDependingOnMatchingTargets(possible_targets):
   supplied as input to analyzer.
   possible_targets: targets to search from."""
   found = []
-  print 'Targets that matched by dependency:'
+  print('Targets that matched by dependency:')
   for target in possible_targets:
     if _DoesTargetDependOnMatchingTargets(target):
       found.append(target)
@@ -484,12 +486,12 @@ def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
           (add_if_no_ancestor or target.requires_build)) or
          (target.is_static_library and add_if_no_ancestor and
           not target.is_or_has_linked_ancestor)):
-    print '\t\tadding to compile targets', target.name, 'executable', \
-           target.is_executable, 'added_to_compile_targets', \
-           target.added_to_compile_targets, 'add_if_no_ancestor', \
-           add_if_no_ancestor, 'requires_build', target.requires_build, \
-           'is_static_library', target.is_static_library, \
-           'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
+    print('\t\tadding to compile targets', target.name, 'executable',
+           target.is_executable, 'added_to_compile_targets',
+           target.added_to_compile_targets, 'add_if_no_ancestor',
+           add_if_no_ancestor, 'requires_build', target.requires_build,
+           'is_static_library', target.is_static_library,
+           'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor)
     result.add(target)
     target.added_to_compile_targets = True
 
@@ -500,7 +502,7 @@ def _GetCompileTargets(matching_targets, supplied_targets):
   supplied_targets: set of targets supplied to analyzer to search from."""
   result = set()
   for target in matching_targets:
-    print 'finding compile targets for match', target.name
+    print('finding compile targets for match', target.name)
     _AddCompileTargets(target, supplied_targets, True, result)
   return result
 
@@ -508,46 +510,46 @@ def _GetCompileTargets(matching_targets, supplied_targets):
 def _WriteOutput(params, **values):
   """Writes the output, either to stdout or a file is specified."""
   if 'error' in values:
-    print 'Error:', values['error']
+    print('Error:', values['error'])
   if 'status' in values:
-    print values['status']
+    print(values['status'])
   if 'targets' in values:
     values['targets'].sort()
-    print 'Supplied targets that depend on changed files:'
+    print('Supplied targets that depend on changed files:')
     for target in values['targets']:
-      print '\t', target
+      print('\t', target)
   if 'invalid_targets' in values:
     values['invalid_targets'].sort()
-    print 'The following targets were not found:'
+    print('The following targets were not found:')
     for target in values['invalid_targets']:
-      print '\t', target
+      print('\t', target)
   if 'build_targets' in values:
     values['build_targets'].sort()
-    print 'Targets that require a build:'
+    print('Targets that require a build:')
     for target in values['build_targets']:
-      print '\t', target
+      print('\t', target)
   if 'compile_targets' in values:
     values['compile_targets'].sort()
-    print 'Targets that need to be built:'
+    print('Targets that need to be built:')
     for target in values['compile_targets']:
-      print '\t', target
+      print('\t', target)
   if 'test_targets' in values:
     values['test_targets'].sort()
-    print 'Test targets:'
+    print('Test targets:')
     for target in values['test_targets']:
-      print '\t', target
+      print('\t', target)
 
   output_path = params.get('generator_flags', {}).get(
       'analyzer_output_path', None)
   if not output_path:
-    print json.dumps(values)
+    print(json.dumps(values))
     return
   try:
     f = open(output_path, 'w')
     f.write(json.dumps(values) + '\n')
     f.close()
   except IOError as e:
-    print 'Error writing to output file', output_path, str(e)
+    print('Error writing to output file', output_path, str(e))
 
 
 def _WasGypIncludeFileModified(params, files):
@@ -556,7 +558,7 @@ def _WasGypIncludeFileModified(params, files):
   if params['options'].includes:
     for include in params['options'].includes:
       if _ToGypPath(os.path.normpath(include)) in files:
-        print 'Include file modified, assuming all changed', include
+        print('Include file modified, assuming all changed', include)
         return True
   return False
 
@@ -638,13 +640,13 @@ def find_matching_test_target_names(self):
                                   set(self._root_targets))]
     else:
       test_targets = [x for x in test_targets_no_all]
-    print 'supplied test_targets'
+    print('supplied test_targets')
     for target_name in self._test_target_names:
-      print '\t', target_name
-    print 'found test_targets'
+      print('\t', target_name)
+    print('found test_targets')
     for target in test_targets:
-      print '\t', target.name
-    print 'searching for matching test targets'
+      print('\t', target.name)
+    print('searching for matching test targets')
     matching_test_targets = _GetTargetsDependingOnMatchingTargets(test_targets)
     matching_test_targets_contains_all = (test_target_names_contains_all and
                                           set(matching_test_targets) &
@@ -654,14 +656,14 @@ def find_matching_test_target_names(self):
       # 'all' is subsequentely added to the matching names below.
       matching_test_targets = [x for x in (set(matching_test_targets) &
                                            set(test_targets_no_all))]
-    print 'matched test_targets'
+    print('matched test_targets')
     for target in matching_test_targets:
-      print '\t', target.name
+      print('\t', target.name)
     matching_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
                              for target in matching_test_targets]
     if matching_test_targets_contains_all:
       matching_target_names.append('all')
-      print '\tall'
+      print('\tall')
     return matching_target_names
 
   def find_matching_compile_target_names(self):
@@ -677,10 +679,10 @@ def find_matching_compile_target_names(self):
     if 'all' in self._supplied_target_names():
       supplied_targets = [x for x in (set(supplied_targets) |
                                       set(self._root_targets))]
-    print 'Supplied test_targets & compile_targets'
+    print('Supplied test_targets & compile_targets')
     for target in supplied_targets:
-      print '\t', target.name
-    print 'Finding compile targets'
+      print('\t', target.name)
+    print('Finding compile targets')
     compile_targets = _GetCompileTargets(self._changed_targets,
                                          supplied_targets)
     return [gyp.common.ParseQualifiedTarget(target.name)[1]
@@ -699,7 +701,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
 
     toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
     if debug:
-      print 'toplevel_dir', toplevel_dir
+      print('toplevel_dir', toplevel_dir)
 
     if _WasGypIncludeFileModified(params, config.files):
       result_dict = { 'status': all_changed_string,
diff --git a/gyp/pylib/gyp/generator/android.py b/gyp/pylib/gyp/generator/android.py
index 5b26cc785a..b7f9842888 100644
--- a/gyp/pylib/gyp/generator/android.py
+++ b/gyp/pylib/gyp/generator/android.py
@@ -14,6 +14,8 @@
 # variables set potentially clash with other Android build system variables.
 # Try to avoid setting global variables where possible.
 
+from __future__ import print_function
+
 import gyp
 import gyp.common
 import gyp.generator.make as make  # Reuse global functions from make backend.
@@ -250,7 +252,7 @@ def WriteActions(self, actions, extra_sources, extra_outputs):
       dirs = set()
       for out in outputs:
         if not out.startswith('$'):
-          print ('WARNING: Action for target "%s" writes output to local path '
+          print('WARNING: Action for target "%s" writes output to local path '
                  '"%s".' % (self.target, out))
         dir = os.path.split(out)[0]
         if dir:
@@ -355,7 +357,7 @@ def WriteRules(self, rules, extra_sources, extra_outputs):
         dirs = set()
         for out in outputs:
           if not out.startswith('$'):
-            print ('WARNING: Rule for target %s writes output to local path %s'
+            print('WARNING: Rule for target %s writes output to local path %s'
                    % (self.target, out))
           dir = os.path.dirname(out)
           if dir:
@@ -429,7 +431,7 @@ def WriteCopies(self, copies, extra_outputs):
         # $(gyp_shared_intermediate_dir). Note that we can't use an assertion
         # because some of the gyp tests depend on this.
         if not copy['destination'].startswith('$'):
-          print ('WARNING: Copy rule for target %s writes output to '
+          print('WARNING: Copy rule for target %s writes output to '
                  'local path %s' % (self.target, copy['destination']))
 
         # LocalPathify() calls normpath, stripping trailing slashes.
@@ -458,7 +460,7 @@ def WriteSourceFlags(self, spec, configs):
     Args:
       spec, configs: input from gyp.
     """
-    for configname, config in sorted(configs.iteritems()):
+    for configname, config in sorted(configs.items()):
       extracted_includes = []
 
       self.WriteLn('\n# Flags passed to both C and C++ files.')
@@ -636,7 +638,7 @@ def ComputeOutputParts(self, spec):
     elif self.type == 'none':
       target_ext = '.stamp'
     elif self.type != 'executable':
-      print ("ERROR: What output file should be generated?",
+      print("ERROR: What output file should be generated?",
              "type", self.type, "target", target)
 
     if self.type != 'static_library' and self.type != 'shared_library':
@@ -788,7 +790,7 @@ def WriteTargetFlags(self, spec, configs, link_deps):
     static_libs, dynamic_libs, ldflags_libs = self.FilterLibraries(libraries)
 
     if self.type != 'static_library':
-      for configname, config in sorted(configs.iteritems()):
+      for configname, config in sorted(configs.items()):
         ldflags = list(config.get('ldflags', []))
         self.WriteLn('')
         self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname)
@@ -837,7 +839,7 @@ def WriteTarget(self, spec, configs, deps, link_deps, part_of_all,
     settings = spec.get('aosp_build_settings', {})
     if settings:
       self.WriteLn('### Set directly by aosp_build_settings.')
-      for k, v in settings.iteritems():
+      for k, v in settings.items():
         if isinstance(v, list):
           self.WriteList(v, k)
         else:
@@ -956,7 +958,7 @@ def PerformBuild(data, configurations, params):
   env = dict(os.environ)
   env['ONE_SHOT_MAKEFILE'] = makefile
   arguments = ['make', '-C', os.environ['ANDROID_BUILD_TOP'], 'gyp_all_modules']
-  print 'Building: %s' % arguments
+  print('Building: %s' % arguments)
   subprocess.check_call(arguments, env=env)
 
 
@@ -1065,7 +1067,7 @@ def CalculateMakefilePath(build_file, base_name):
                                   write_alias_target=write_alias_targets,
                                   sdk_version=sdk_version)
     if android_module in android_modules:
-      print ('ERROR: Android module names must be unique. The following '
+      print('ERROR: Android module names must be unique. The following '
              'targets both generate Android module name %s.\n  %s\n  %s' %
              (android_module, android_modules[android_module],
               qualified_target))
diff --git a/gyp/pylib/gyp/generator/cmake.py b/gyp/pylib/gyp/generator/cmake.py
index 17f5e6396c..7aabddb633 100644
--- a/gyp/pylib/gyp/generator/cmake.py
+++ b/gyp/pylib/gyp/generator/cmake.py
@@ -28,6 +28,8 @@
 CMakeLists.txt file.
 """
 
+from __future__ import print_function
+
 import multiprocessing
 import os
 import signal
@@ -639,8 +641,8 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
 
   cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
   if cmake_target_type is None:
-    print ('Target %s has unknown target type %s, skipping.' %
-          (        target_name,               target_type  ) )
+    print('Target %s has unknown target type %s, skipping.' %
+          (        target_name,               target_type  ))
     return
 
   SetVariable(output, 'TARGET', target_name)
@@ -863,7 +865,7 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
       default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
 
     elif target_type != 'executable':
-      print ('ERROR: What output file should be generated?',
+      print('ERROR: What output file should be generated?',
               'type', target_type, 'target', target_name)
 
     product_prefix = spec.get('product_prefix', default_product_prefix)
@@ -1180,11 +1182,11 @@ def PerformBuild(data, configurations, params):
                                               output_dir,
                                               config_name))
     arguments = ['cmake', '-G', 'Ninja']
-    print 'Generating [%s]: %s' % (config_name, arguments)
+    print('Generating [%s]: %s' % (config_name, arguments))
     subprocess.check_call(arguments, cwd=build_dir)
 
     arguments = ['ninja', '-C', build_dir]
-    print 'Building [%s]: %s' % (config_name, arguments)
+    print('Building [%s]: %s' % (config_name, arguments))
     subprocess.check_call(arguments)
 
 
@@ -1212,7 +1214,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           arglists.append((target_list, target_dicts, data,
                            params, config_name))
           pool.map(CallGenerateOutputForConfig, arglists)
-      except KeyboardInterrupt, e:
+      except KeyboardInterrupt as e:
         pool.terminate()
         raise e
     else:
diff --git a/gyp/pylib/gyp/generator/dump_dependency_json.py b/gyp/pylib/gyp/generator/dump_dependency_json.py
index 160eafe2ef..8e4f3168f3 100644
--- a/gyp/pylib/gyp/generator/dump_dependency_json.py
+++ b/gyp/pylib/gyp/generator/dump_dependency_json.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 # Copyright (c) 2012 Google Inc. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -96,4 +97,4 @@ def GenerateOutput(target_list, target_dicts, data, params):
   f = open(filename, 'w')
   json.dump(edges, f)
   f.close()
-  print 'Wrote json to %s.' % filename
+  print('Wrote json to %s.' % filename)
diff --git a/gyp/pylib/gyp/generator/eclipse.py b/gyp/pylib/gyp/generator/eclipse.py
index 3544347b3b..b7c6aa951f 100644
--- a/gyp/pylib/gyp/generator/eclipse.py
+++ b/gyp/pylib/gyp/generator/eclipse.py
@@ -141,7 +141,7 @@ def GetAllIncludeDirectories(target_list, target_dicts,
             compiler_includes_list.append(include_dir)
 
       # Find standard gyp include dirs.
-      if config.has_key('include_dirs'):
+      if 'include_dirs' in config:
         include_dirs = config['include_dirs']
         for shared_intermediate_dir in shared_intermediate_dirs:
           for include_dir in include_dirs:
diff --git a/gyp/pylib/gyp/generator/gypd.py b/gyp/pylib/gyp/generator/gypd.py
index 3efdb9966a..78eeaa61b2 100644
--- a/gyp/pylib/gyp/generator/gypd.py
+++ b/gyp/pylib/gyp/generator/gypd.py
@@ -88,7 +88,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     if not output_file in output_files:
       output_files[output_file] = input_file
 
-  for output_file, input_file in output_files.iteritems():
+  for output_file, input_file in output_files.items():
     output = open(output_file, 'w')
     pprint.pprint(data[input_file], output)
     output.close()
diff --git a/gyp/pylib/gyp/generator/make.py b/gyp/pylib/gyp/generator/make.py
index 64b9dd267b..d549e899d8 100644
--- a/gyp/pylib/gyp/generator/make.py
+++ b/gyp/pylib/gyp/generator/make.py
@@ -19,7 +19,9 @@
 #
 # Global settings and utility functions are currently stuffed in the
 # toplevel Makefile.  It may make sense to generate some .mk files on
-# the side to keep the the files readable.
+# the side to keep the files readable.
+
+from __future__ import print_function
 
 import os
 import re
@@ -31,6 +33,8 @@
 from gyp.common import GetEnvironFallback
 from gyp.common import GypError
 
+import hashlib
+
 generator_default_variables = {
   'EXECUTABLE_PREFIX': '',
   'EXECUTABLE_SUFFIX': '',
@@ -90,7 +94,10 @@ def CalculateVariables(default_variables, params):
     if flavor == 'android':
       operating_system = 'linux'  # Keep this legacy behavior for now.
     default_variables.setdefault('OS', operating_system)
-    default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
+    if flavor == 'aix':
+      default_variables.setdefault('SHARED_LIB_SUFFIX', '.a')
+    else:
+      default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
     default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)')
     default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)')
 
@@ -142,7 +149,7 @@ def CalculateGeneratorInputInfo(params):
 # special "figure out circular dependencies" flags around the entire
 # input list during linking.
 quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group
 
 # We support two kinds of shared objects (.so):
 # 1) shared_library, which is just bundling together many dependent libraries
@@ -227,6 +234,25 @@ def CalculateGeneratorInputInfo(params):
 """
 
 
+LINK_COMMANDS_OS390 = """\
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) -Wl,DLL
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -Wl,DLL
+
+"""
+
+
 # Header of toplevel Makefile.
 # This should go into the build tree, but it's easier to keep it here for now.
 SHARED_HEADER = ("""\
@@ -310,7 +336,7 @@ def CalculateGeneratorInputInfo(params):
 # We write to a dep file on the side first and then rename at the end
 # so we can't end up with a broken dep file.
 depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
+DEPFLAGS = %(makedep_args)s -MF $(depfile).raw
 
 # We have to fixup the deps output in a few ways.
 # (1) the file output should mention the proper .o file.
@@ -623,6 +649,9 @@ def Sourceify(path):
 def QuoteSpaces(s, quote=r'\ '):
   return s.replace(' ', quote)
 
+def SourceifyAndQuoteSpaces(path):
+  """Convert a path to its source directory form and quote spaces."""
+  return QuoteSpaces(Sourceify(path))
 
 # TODO: Avoid code duplication with _ValidateSourcesForMSVSProject in msvs.py.
 def _ValidateSourcesForOSX(spec, all_sources):
@@ -645,14 +674,13 @@ def _ValidateSourcesForOSX(spec, all_sources):
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
       error += '  %s: %s\n' % (basename, ' '.join(files))
 
   if error:
-    print('static library %s has several files with the same basename:\n' %
-          spec['target_name'] + error + 'libtool on OS X will generate' +
-          ' warnings for them.')
+    print(('static library %s has several files with the same basename:\n' % spec['target_name'])
+           + error + 'libtool on OS X will generate' + ' warnings for them.')
     raise GypError('Duplicate basenames in sources section, see list above')
 
 
@@ -1347,11 +1375,14 @@ def ComputeOutputBasename(self, spec):
       if target[:3] == 'lib':
         target = target[3:]
       target_prefix = 'lib'
-      target_ext = '.so'
+      if self.flavor == 'aix':
+        target_ext = '.a'
+      else:
+        target_ext = '.so'
     elif self.type == 'none':
       target = '%s.stamp' % target
     elif self.type != 'executable':
-      print ("ERROR: What output file should be generated?",
+      print("ERROR: What output file should be generated?",
              "type", self.type, "target", target)
 
     target_prefix = spec.get('product_prefix', target_prefix)
@@ -1516,7 +1547,7 @@ def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps,
       # Postbuilds expect to be run in the gyp file's directory, so insert an
       # implicit postbuild to cd to there.
       postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path]))
-      for i in xrange(len(postbuilds)):
+      for i in range(len(postbuilds)):
         if not postbuilds[i].startswith('$'):
           postbuilds[i] = EscapeShellArgument(postbuilds[i])
       self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output))
@@ -1608,7 +1639,7 @@ def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps,
       self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all,
                       postbuilds=postbuilds)
     else:
-      print "WARNING: no output for", self.type, target
+      print("WARNING: no output for", self.type, self.target)
 
     # Add an alias for each target (if there are any outputs).
     # Installable target aliases are created below.
@@ -1743,7 +1774,10 @@ def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
       #   actual command.
       # - The intermediate recipe will 'touch' the intermediate file.
       # - The multi-output rule will have an do-nothing recipe.
-      intermediate = "%s.intermediate" % (command if command else self.target)
+
+      # Hash the target name to avoid generating overlong filenames.
+      cmddigest = hashlib.sha1(command if command else self.target).hexdigest()
+      intermediate = "%s.intermediate" % cmddigest
       self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
       self.WriteLn('\t%s' % '@:');
       self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
@@ -1945,7 +1979,7 @@ def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
       "%(makefile_name)s: %(deps)s\n"
       "\t$(call do_cmd,regen_makefile)\n\n" % {
           'makefile_name': makefile_name,
-          'deps': ' '.join(map(Sourceify, build_files)),
+          'deps': ' '.join(map(SourceifyAndQuoteSpaces, build_files)),
           'cmd': gyp.common.EncodePOSIXShellList(
                      [gyp_binary, '-fmake'] +
                      gyp.RegenerateFlags(options) +
@@ -1959,7 +1993,7 @@ def PerformBuild(data, configurations, params):
     if options.toplevel_dir and options.toplevel_dir != '.':
       arguments += '-C', options.toplevel_dir
     arguments.append('BUILDTYPE=' + config)
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [%s]: %s' % (config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -2013,6 +2047,7 @@ def CalculateMakefilePath(build_file, base_name):
 
   flock_command= 'flock'
   copy_archive_arguments = '-af'
+  makedep_arguments = '-MMD'
   header_params = {
       'default_target': default_target,
       'builddir': builddir_name,
@@ -2023,6 +2058,7 @@ def CalculateMakefilePath(build_file, base_name):
       'extra_commands': '',
       'srcdir': srcdir,
       'copy_archive_args': copy_archive_arguments,
+      'makedep_args': makedep_arguments,
     }
   if flavor == 'mac':
     flock_command = './gyp-mac-tool flock'
@@ -2036,6 +2072,14 @@ def CalculateMakefilePath(build_file, base_name):
     header_params.update({
         'link_commands': LINK_COMMANDS_ANDROID,
     })
+  elif flavor == 'zos':
+    copy_archive_arguments = '-fPR'
+    makedep_arguments = '-qmakedep=gcc'
+    header_params.update({
+        'copy_archive_args': copy_archive_arguments,
+        'makedep_args': makedep_arguments,
+        'link_commands': LINK_COMMANDS_OS390,
+    })
   elif flavor == 'solaris':
     header_params.update({
         'flock': './gyp-flock-tool flock',
diff --git a/gyp/pylib/gyp/generator/msvs.py b/gyp/pylib/gyp/generator/msvs.py
index 6bfad0f3bd..fb2549d025 100644
--- a/gyp/pylib/gyp/generator/msvs.py
+++ b/gyp/pylib/gyp/generator/msvs.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import copy
 import ntpath
 import os
@@ -449,7 +451,7 @@ def _AddCustomBuildToolForMSVS(p, spec, primary_input,
        'CommandLine': cmd,
       })
   # Add to the properties of primary input for each config.
-  for config_name, c_data in spec['configurations'].iteritems():
+  for config_name, c_data in spec['configurations'].items():
     p.AddFileConfig(_FixPath(primary_input),
                     _ConfigFullName(config_name, c_data), tools=[tool])
 
@@ -755,8 +757,8 @@ def _Replace(match):
     # the VCProj but cause the same problem on the final command-line. Moving
     # the item to the end of the list does works, but that's only possible if
     # there's only one such item. Let's just warn the user.
-    print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' +
-                          'quotes in ' + s)
+    print('Warning: MSVS may misinterpret the odd number of ' +
+                          'quotes in ' + s, file=sys.stderr)
   return s
 
 
@@ -969,13 +971,13 @@ def _ValidateSourcesForMSVSProject(spec, version):
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
       error += '  %s: %s\n' % (basename, ' '.join(files))
 
   if error:
-    print('static library %s has several files with the same basename:\n' %
-          spec['target_name'] + error + 'MSVC08 cannot handle that.')
+    print('static library %s has several files with the same basename:\n' % spec['target_name']
+          + error + 'MSVC08 cannot handle that.')
     raise GypError('Duplicate basenames in sources section, see list above')
 
 
@@ -1001,7 +1003,7 @@ def _GenerateMSVSProject(project, options, version, generator_flags):
   relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
 
   config_type = _GetMSVSConfigurationType(spec, project.build_file)
-  for config_name, config in spec['configurations'].iteritems():
+  for config_name, config in spec['configurations'].items():
     _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config)
 
   # MSVC08 and prior version cannot handle duplicate basenames in the same
@@ -1367,10 +1369,10 @@ def _ConvertToolsToExpectedForm(tools):
     A list of Tool objects.
   """
   tool_list = []
-  for tool, settings in tools.iteritems():
+  for tool, settings in tools.items():
     # Collapse settings with lists.
     settings_fixed = {}
-    for setting, value in settings.iteritems():
+    for setting, value in settings.items():
       if type(value) == list:
         if ((tool == 'VCLinkerTool' and
              setting == 'AdditionalDependencies') or
@@ -1545,7 +1547,7 @@ def _IdlFilesHandledNonNatively(spec, sources):
 def _GetPrecompileRelatedFiles(spec):
   # Gather a list of precompiled header related sources.
   precompiled_related = []
-  for _, config in spec['configurations'].iteritems():
+  for _, config in spec['configurations'].items():
     for k in precomp_keys:
       f = config.get(k)
       if f:
@@ -1556,7 +1558,7 @@ def _GetPrecompileRelatedFiles(spec):
 def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl,
                                 list_excluded):
   exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
-  for file_name, excluded_configs in exclusions.iteritems():
+  for file_name, excluded_configs in exclusions.items():
     if (not list_excluded and
             len(excluded_configs) == len(spec['configurations'])):
       # If we're not listing excluded files, then they won't appear in the
@@ -1573,7 +1575,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
   # Exclude excluded sources from being built.
   for f in excluded_sources:
     excluded_configs = []
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       precomped = [_FixPath(config.get(i, '')) for i in precomp_keys]
       # Don't do this for ones that are precompiled header related.
       if f not in precomped:
@@ -1583,7 +1585,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
   # Exclude them now.
   for f in excluded_idl:
     excluded_configs = []
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       excluded_configs.append((config_name, config))
     exclusions[f] = excluded_configs
   return exclusions
@@ -1592,7 +1594,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
 def _AddToolFilesToMSVS(p, spec):
   # Add in tool files (rules).
   tool_files = OrderedSet()
-  for _, config in spec['configurations'].iteritems():
+  for _, config in spec['configurations'].items():
     for f in config.get('msvs_tool_files', []):
       tool_files.add(f)
   for f in tool_files:
@@ -1605,7 +1607,7 @@ def _HandlePreCompiledHeaders(p, sources, spec):
   # kind (i.e. C vs. C++) as the precompiled header source stub needs
   # to have use of precompiled headers disabled.
   extensions_excluded_from_precompile = []
-  for config_name, config in spec['configurations'].iteritems():
+  for config_name, config in spec['configurations'].items():
     source = config.get('msvs_precompiled_source')
     if source:
       source = _FixPath(source)
@@ -1626,7 +1628,7 @@ def DisableForSourceTree(source_tree):
       else:
         basename, extension = os.path.splitext(source)
         if extension in extensions_excluded_from_precompile:
-          for config_name, config in spec['configurations'].iteritems():
+          for config_name, config in spec['configurations'].items():
             tool = MSVSProject.Tool('VCCLCompilerTool',
                                     {'UsePrecompiledHeader': '0',
                                      'ForcedIncludeFiles': '$(NOINHERIT)'})
@@ -1677,7 +1679,7 @@ def _WriteMSVSUserFile(project_path, version, spec):
     return  # Nothing to add
   # Write out the user file.
   user_file = _CreateMSVSUserFile(project_path, version, spec)
-  for config_name, c_data in spec['configurations'].iteritems():
+  for config_name, c_data in spec['configurations'].items():
     user_file.AddDebugSettings(_ConfigFullName(config_name, c_data),
                                action, environment, working_directory)
   user_file.WriteIfChanged()
@@ -1728,7 +1730,7 @@ def _GetPathDict(root, path):
 def _DictsToFolders(base_path, bucket, flat):
   # Convert to folders recursively.
   children = []
-  for folder, contents in bucket.iteritems():
+  for folder, contents in bucket.items():
     if type(contents) == dict:
       folder_children = _DictsToFolders(os.path.join(base_path, folder),
                                         contents, flat)
@@ -1800,7 +1802,7 @@ def _GetPlatformOverridesOfProject(spec):
   # Prepare a dict indicating which project configurations are used for which
   # solution configurations for this target.
   config_platform_overrides = {}
-  for config_name, c in spec['configurations'].iteritems():
+  for config_name, c in spec['configurations'].items():
     config_fullname = _ConfigFullName(config_name, c)
     platform = c.get('msvs_target_platform', _ConfigPlatform(c))
     fixed_config_fullname = '%s|%s' % (
@@ -1939,7 +1941,7 @@ def PerformBuild(data, configurations, params):
   msvs_version = params['msvs_version']
   devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com')
 
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -1949,7 +1951,7 @@ def PerformBuild(data, configurations, params):
 
   for config in configurations:
     arguments = [devenv, sln_path, '/Build', config]
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [%s]: %s' % (config, arguments))
     rtn = subprocess.check_call(arguments)
 
 
@@ -1988,7 +1990,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
   configs = set()
   for qualified_target in target_list:
     spec = target_dicts[qualified_target]
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       configs.add(_ConfigFullName(config_name, config))
   configs = list(configs)
 
@@ -2031,7 +2033,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     if generator_flags.get('msvs_error_on_missing_sources', False):
       raise GypError(error_message)
     else:
-      print >> sys.stdout, "Warning: " + error_message
+      print("Warning: " + error_message, file=sys.stdout)
 
 
 def _GenerateMSBuildFiltersFile(filters_path, source_files,
@@ -2118,7 +2120,7 @@ def _MapFileToMsBuildSourceType(source, rule_dependencies,
   if ext in extension_to_rule_name:
     group = 'rule'
     element = extension_to_rule_name[ext]
-  elif ext in ['.cc', '.cpp', '.c', '.cxx']:
+  elif ext in ['.cc', '.cpp', '.c', '.cxx', '.mm']:
     group = 'compile'
     element = 'ClCompile'
   elif ext in ['.h', '.hxx']:
@@ -2628,7 +2630,7 @@ def _GetConfigurationCondition(name, settings):
 
 def _GetMSBuildProjectConfigurations(configurations):
   group = ['ItemGroup', {'Label': 'ProjectConfigurations'}]
-  for (name, settings) in sorted(configurations.iteritems()):
+  for (name, settings) in sorted(configurations.items()):
     configuration, platform = _GetConfigurationAndPlatform(name, settings)
     designation = '%s|%s' % (configuration, platform)
     group.append(
@@ -2698,7 +2700,7 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
 
 def _GetMSBuildConfigurationDetails(spec, build_file):
   properties = {}
-  for name, settings in spec['configurations'].iteritems():
+  for name, settings in spec['configurations'].items():
     msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file)
     condition = _GetConfigurationCondition(name, settings)
     character_set = msbuild_attributes.get('CharacterSet')
@@ -2727,9 +2729,9 @@ def _GetMSBuildPropertySheets(configurations):
   user_props = r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props'
   additional_props = {}
   props_specified = False
-  for name, settings in sorted(configurations.iteritems()):
+  for name, settings in sorted(configurations.items()):
     configuration = _GetConfigurationCondition(name, settings)
-    if settings.has_key('msbuild_props'):
+    if 'msbuild_props' in settings:
       additional_props[configuration] = _FixPaths(settings['msbuild_props'])
       props_specified = True
     else:
@@ -2749,7 +2751,7 @@ def _GetMSBuildPropertySheets(configurations):
     ]
   else:
     sheets = []
-    for condition, props in additional_props.iteritems():
+    for condition, props in additional_props.items():
       import_group = [
         'ImportGroup',
         {'Label': 'PropertySheets',
@@ -2782,7 +2784,7 @@ def _ConvertMSVSBuildAttributes(spec, config, build_file):
     elif a == 'ConfigurationType':
       msbuild_attributes[a] = _ConvertMSVSConfigurationType(msvs_attributes[a])
     else:
-      print 'Warning: Do not know how to convert MSVS attribute ' + a
+      print('Warning: Do not know how to convert MSVS attribute ' + a)
   return msbuild_attributes
 
 
@@ -2876,7 +2878,7 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
       new_paths = '$(ExecutablePath);' + ';'.join(new_paths)
 
   properties = {}
-  for (name, configuration) in sorted(configurations.iteritems()):
+  for (name, configuration) in sorted(configurations.items()):
     condition = _GetConfigurationCondition(name, configuration)
     attributes = _GetMSBuildAttributes(spec, configuration, build_file)
     msbuild_settings = configuration['finalized_msbuild_settings']
@@ -2901,7 +2903,7 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
       _AddConditionalProperty(properties, condition, 'ExecutablePath',
                               new_paths)
     tool_settings = msbuild_settings.get('', {})
-    for name, value in sorted(tool_settings.iteritems()):
+    for name, value in sorted(tool_settings.items()):
       formatted_value = _GetValueFormattedForMSBuild('', name, value)
       _AddConditionalProperty(properties, condition, name, formatted_value)
   return _GetMSBuildPropertyGroup(spec, None, properties)
@@ -2970,7 +2972,7 @@ def GetEdges(node):
   # NOTE: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
   for name in reversed(properties_ordered):
     values = properties[name]
-    for value, conditions in sorted(values.iteritems()):
+    for value, conditions in sorted(values.items()):
       if len(conditions) == num_configurations:
         # If the value is the same all configurations,
         # just add one unconditional entry.
@@ -2983,18 +2985,18 @@ def GetEdges(node):
 
 def _GetMSBuildToolSettingsSections(spec, configurations):
   groups = []
-  for (name, configuration) in sorted(configurations.iteritems()):
+  for (name, configuration) in sorted(configurations.items()):
     msbuild_settings = configuration['finalized_msbuild_settings']
     group = ['ItemDefinitionGroup',
              {'Condition': _GetConfigurationCondition(name, configuration)}
             ]
-    for tool_name, tool_settings in sorted(msbuild_settings.iteritems()):
+    for tool_name, tool_settings in sorted(msbuild_settings.items()):
       # Skip the tool named '' which is a holder of global settings handled
       # by _GetMSBuildConfigurationGlobalProperties.
       if tool_name:
         if tool_settings:
           tool = [tool_name]
-          for name, value in sorted(tool_settings.iteritems()):
+          for name, value in sorted(tool_settings.items()):
             formatted_value = _GetValueFormattedForMSBuild(tool_name, name,
                                                            value)
             tool.append([name, formatted_value])
@@ -3027,7 +3029,7 @@ def _FinalizeMSBuildSettings(spec, configuration):
     for ignored_setting in ignored_settings:
       value = configuration.get(ignored_setting)
       if value:
-        print ('Warning: The automatic conversion to MSBuild does not handle '
+        print('Warning: The automatic conversion to MSBuild does not handle '
                '%s.  Ignoring setting of %s' % (ignored_setting, str(value)))
 
   defines = [_EscapeCppDefineForMSBuild(d) for d in defines]
@@ -3194,7 +3196,7 @@ def _AddSources2(spec, sources, exclusions, grouped_sources,
                            {'Condition': condition},
                            'true'])
         # Add precompile if needed
-        for config_name, configuration in spec['configurations'].iteritems():
+        for config_name, configuration in spec['configurations'].items():
           precompiled_source = configuration.get('msvs_precompiled_source', '')
           if precompiled_source != '':
             precompiled_source = _FixPath(precompiled_source)
@@ -3434,7 +3436,7 @@ def _GenerateActionsForMSBuild(spec, actions_to_add):
   """
   sources_handled_by_action = OrderedSet()
   actions_spec = []
-  for primary_input, actions in actions_to_add.iteritems():
+  for primary_input, actions in actions_to_add.items():
     inputs = OrderedSet()
     outputs = OrderedSet()
     descriptions = []
diff --git a/gyp/pylib/gyp/generator/ninja.py b/gyp/pylib/gyp/generator/ninja.py
index 841067ed34..aae5b71310 100644
--- a/gyp/pylib/gyp/generator/ninja.py
+++ b/gyp/pylib/gyp/generator/ninja.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 # Copyright (c) 2013 Google Inc. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -140,7 +141,7 @@ def __init__(self, type):
     # On Windows, incremental linking requires linking against all the .objs
     # that compose a .lib (rather than the .lib itself). That list is stored
     # here. In this case, we also need to save the compile_deps for the target,
-    # so that the the target that directly depends on the .objs can also depend
+    # so that the target that directly depends on the .objs can also depend
     # on those.
     self.component_objs = None
     self.compile_deps = None
@@ -472,8 +473,8 @@ def WriteSpec(self, spec, config_name, generator_flags):
         if self.flavor != 'mac' or len(self.archs) == 1:
           link_deps += [self.GypPathToNinja(o) for o in obj_outputs]
         else:
-          print "Warning: Actions/rules writing object files don't work with " \
-                "multiarch targets, dropping. (target %s)" % spec['target_name']
+          print("Warning: Actions/rules writing object files don't work with " \
+                "multiarch targets, dropping. (target %s)" % spec['target_name'])
     elif self.flavor == 'mac' and len(self.archs) > 1:
       link_deps = collections.defaultdict(list)
 
@@ -796,7 +797,7 @@ def WriteMacXCassets(self, xcassets, bundle_depends):
         'XCASSETS_LAUNCH_IMAGE': 'launch-image',
     }
     settings = self.xcode_settings.xcode_settings[self.config_name]
-    for settings_key, arg_name in settings_to_arg.iteritems():
+    for settings_key, arg_name in settings_to_arg.items():
       value = settings.get(settings_key)
       if value:
         extra_arguments[arg_name] = value
@@ -1873,6 +1874,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
       ld = os.path.join(build_to_root, value)
     if key == 'LD.host':
       ld_host = os.path.join(build_to_root, value)
+    if key == 'LDXX':
+      ldxx = os.path.join(build_to_root, value)
+    if key == 'LDXX.host':
+      ldxx_host = os.path.join(build_to_root, value)
     if key == 'NM':
       nm = os.path.join(build_to_root, value)
     if key == 'NM.host':
@@ -1885,7 +1890,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
       wrappers[key[:-len('_wrapper')]] = os.path.join(build_to_root, value)
 
   # Support wrappers from environment variables too.
-  for key, value in os.environ.iteritems():
+  for key, value in os.environ.items():
     if key.lower().endswith('_wrapper'):
       key_prefix = key[:-len('_wrapper')]
       key_prefix = re.sub(r'\.HOST$', '.host', key_prefix)
@@ -1901,7 +1906,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
               configs, generator_flags)
     cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
         toplevel_build, generator_flags, shared_system_includes, OpenOutput)
-    for arch, path in cl_paths.iteritems():
+    for arch, path in cl_paths.items():
       if clang_cl:
         # If we have selected clang-cl, use that instead.
         path = clang_cl
@@ -1962,6 +1967,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
                           CommandWithWrapper('CXX.host', wrappers, cxx_host))
     if flavor == 'win':
       master_ninja.variable('ld_host', ld_host)
+      master_ninja.variable('ldxx_host', ldxx_host)
     else:
       master_ninja.variable('ld_host', CommandWithWrapper(
           'LINK', wrappers, ld_host))
@@ -2086,13 +2092,13 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
       restat=True,
       command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'},
       rspfile='$link_file_list',
-      rspfile_content='-Wl,--start-group $in -Wl,--end-group $solibs $libs',
+      rspfile_content='-Wl,--start-group $in $solibs $libs -Wl,--end-group',
       pool='link_pool')
     master_ninja.rule(
       'link',
       description='LINK $out',
       command=('$ld $ldflags -o $out '
-               '-Wl,--start-group $in -Wl,--end-group $solibs $libs'),
+               '-Wl,--start-group $in $solibs $libs -Wl,--end-group'),
       pool='link_pool')
   elif flavor == 'win':
     master_ninja.rule(
@@ -2238,15 +2244,22 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
       'stamp',
       description='STAMP $out',
       command='%s gyp-win-tool stamp $out' % sys.executable)
-    master_ninja.rule(
-      'copy',
-      description='COPY $in $out',
-      command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable)
   else:
     master_ninja.rule(
       'stamp',
       description='STAMP $out',
       command='${postbuilds}touch $out')
+  if flavor == 'win':
+    master_ninja.rule(
+      'copy',
+      description='COPY $in $out',
+      command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable)
+  elif flavor == 'zos':
+    master_ninja.rule(
+      'copy',
+      description='COPY $in $out',
+      command='rm -rf $out && cp -fRP $in $out')
+  else:
     master_ninja.rule(
       'copy',
       description='COPY $in $out',
@@ -2364,7 +2377,7 @@ def PerformBuild(data, configurations, params):
   for config in configurations:
     builddir = os.path.join(options.toplevel_dir, 'out', config)
     arguments = ['ninja', '-C', builddir]
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [%s]: %s' % (config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -2401,7 +2414,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           arglists.append(
               (target_list, target_dicts, data, params, config_name))
         pool.map(CallGenerateOutputForConfig, arglists)
-      except KeyboardInterrupt, e:
+      except KeyboardInterrupt as e:
         pool.terminate()
         raise e
     else:
diff --git a/gyp/pylib/gyp/generator/xcode.py b/gyp/pylib/gyp/generator/xcode.py
index 0e3fb9301e..694a28afb1 100644
--- a/gyp/pylib/gyp/generator/xcode.py
+++ b/gyp/pylib/gyp/generator/xcode.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 # Copyright (c) 2012 Google Inc. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -128,7 +129,7 @@ def __init__(self, gyp_path, path, build_file_dict):
     try:
       os.makedirs(self.path)
       self.created_dir = True
-    except OSError, e:
+    except OSError as e:
       if e.errno != errno.EEXIST:
         raise
 
@@ -182,7 +183,7 @@ def Finalize1(self, xcode_targets, serialize_all_tests):
     # the tree tree view for UI display.
     # Any values set globally are applied to all configurations, then any
     # per-configuration values are applied.
-    for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems():
+    for xck, xcv in self.build_file_dict.get('xcode_settings', {}).items():
       xccl.SetBuildSetting(xck, xcv)
     if 'xcode_config_file' in self.build_file_dict:
       config_ref = self.project.AddOrGetFileInRootGroup(
@@ -196,7 +197,7 @@ def Finalize1(self, xcode_targets, serialize_all_tests):
         if build_file_configuration_named:
           xcc = xccl.ConfigurationNamed(config_name)
           for xck, xcv in build_file_configuration_named.get('xcode_settings',
-                                                             {}).iteritems():
+                                                             {}).items():
             xcc.SetBuildSetting(xck, xcv)
           if 'xcode_config_file' in build_file_configuration_named:
             config_ref = self.project.AddOrGetFileInRootGroup(
@@ -272,7 +273,7 @@ def Finalize1(self, xcode_targets, serialize_all_tests):
           script = script + "\n".join(
             ['export %s="%s"' %
              (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val))
-             for (key, val) in command.get('environment').iteritems()]) + "\n"
+             for (key, val) in command.get('environment').items()]) + "\n"
 
         # Some test end up using sockets, files on disk, etc. and can get
         # confused if more then one test runs at a time.  The generator
@@ -453,7 +454,7 @@ def Write(self):
       same = False
       try:
         same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False)
-      except OSError, e:
+      except OSError as e:
         if e.errno != errno.ENOENT:
           raise
 
@@ -472,10 +473,10 @@ def Write(self):
         #
         # No way to get the umask without setting a new one?  Set a safe one
         # and then set it back to the old value.
-        umask = os.umask(077)
+        umask = os.umask(0o77)
         os.umask(umask)
 
-        os.chmod(new_pbxproj_path, 0666 & ~umask)
+        os.chmod(new_pbxproj_path, 0o666 & ~umask)
         os.rename(new_pbxproj_path, pbxproj_path)
 
     except Exception:
@@ -565,7 +566,7 @@ def EscapeXcodeDefine(s):
 def PerformBuild(data, configurations, params):
   options = params['options']
 
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -576,7 +577,7 @@ def PerformBuild(data, configurations, params):
   for config in configurations:
     arguments = ['xcodebuild', '-project', xcodeproj_path]
     arguments += ['-configuration', config]
-    print "Building [%s]: %s" % (config, arguments)
+    print("Building [%s]: %s" % (config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -624,7 +625,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
   skip_excluded_files = \
       not generator_flags.get('xcode_list_excluded_files', True)
   xcode_projects = {}
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -736,7 +737,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
       xctarget_type = gyp.xcodeproj_file.PBXNativeTarget
       try:
         target_properties['productType'] = _types[type_bundle_key]
-      except KeyError, e:
+      except KeyError as e:
         gyp.common.ExceptionAppend(e, "-- unknown product type while "
                                    "writing target %s" % target_name)
         raise
@@ -1013,7 +1014,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
         # target.
         makefile.write('all: \\\n')
         for concrete_output_index in \
-            xrange(0, len(concrete_outputs_by_rule_source)):
+            range(0, len(concrete_outputs_by_rule_source)):
           # Only list the first (index [0]) concrete output of each input
           # in the "all" target.  Otherwise, a parallel make (-j > 1) would
           # attempt to process each input multiple times simultaneously.
@@ -1036,7 +1037,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           # rule source.  Collect the names of the directories that are
           # required.
           concrete_output_dirs = []
-          for concrete_output_index in xrange(0, len(concrete_outputs)):
+          for concrete_output_index in range(0, len(concrete_outputs)):
             concrete_output = concrete_outputs[concrete_output_index]
             if concrete_output_index == 0:
               bol = ''
@@ -1055,7 +1056,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           # the set of additional rule inputs, if any.
           prerequisites = [rule_source]
           prerequisites.extend(rule.get('inputs', []))
-          for prerequisite_index in xrange(0, len(prerequisites)):
+          for prerequisite_index in range(0, len(prerequisites)):
             prerequisite = prerequisites[prerequisite_index]
             if prerequisite_index == len(prerequisites) - 1:
               eol = ''
@@ -1277,7 +1278,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           set_define = EscapeXcodeDefine(define)
           xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define)
       if 'xcode_settings' in configuration:
-        for xck, xcv in configuration['xcode_settings'].iteritems():
+        for xck, xcv in configuration['xcode_settings'].items():
           xcbc.SetBuildSetting(xck, xcv)
       if 'xcode_config_file' in configuration:
         config_ref = pbxp.AddOrGetFileInRootGroup(
@@ -1285,7 +1286,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
         xcbc.SetBaseConfiguration(config_ref)
 
   build_files = []
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     if build_file.endswith('.gyp'):
       build_files.append(build_file)
 
diff --git a/gyp/pylib/gyp/input.py b/gyp/pylib/gyp/input.py
index 7567d0a05b..68e51131d8 100644
--- a/gyp/pylib/gyp/input.py
+++ b/gyp/pylib/gyp/input.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 from compiler.ast import Const
 from compiler.ast import Dict
 from compiler.ast import Discard
@@ -233,7 +235,12 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
     # Open the build file for read ('r') with universal-newlines mode ('U')
     # to make sure platform specific newlines ('\r\n' or '\r') are converted to '\n'
     # which otherwise will fail eval()
-    build_file_contents = open(build_file_path, 'rU').read()
+    if sys.platform == 'zos':
+      # On z/OS, universal-newlines mode treats the file as an ascii file. But since
+      # node-gyp produces ebcdic files, do not use that mode.
+      build_file_contents = open(build_file_path, 'r').read()
+    else:
+      build_file_contents = open(build_file_path, 'rU').read()
   else:
     raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
 
@@ -244,10 +251,10 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
     else:
       build_file_data = eval(build_file_contents, {'__builtins__': None},
                              None)
-  except SyntaxError, e:
+  except SyntaxError as e:
     e.filename = build_file_path
     raise
-  except Exception, e:
+  except Exception as e:
     gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path)
     raise
 
@@ -267,7 +274,7 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
       else:
         LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
                                       aux_data, None, check)
-    except Exception, e:
+    except Exception as e:
       gyp.common.ExceptionAppend(e,
                                  'while reading includes of ' + build_file_path)
       raise
@@ -304,7 +311,7 @@ def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
                subdict_path, include)
 
   # Recurse into subdictionaries.
-  for k, v in subdict.iteritems():
+  for k, v in subdict.items():
     if type(v) is dict:
       LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data,
                                     None, check)
@@ -469,7 +476,7 @@ def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
       try:
         LoadTargetBuildFile(dependency, data, aux_data, variables,
                             includes, depth, check, load_dependencies)
-      except Exception, e:
+      except Exception as e:
         gyp.common.ExceptionAppend(
           e, 'while loading dependencies of %s' % build_file_path)
         raise
@@ -490,7 +497,7 @@ def CallLoadTargetBuildFile(global_flags,
     signal.signal(signal.SIGINT, signal.SIG_IGN)
 
     # Apply globals so that the worker process behaves the same.
-    for key, value in global_flags.iteritems():
+    for key, value in global_flags.items():
       globals()[key] = value
 
     SetGeneratorGlobals(generator_input_info)
@@ -512,12 +519,12 @@ def CallLoadTargetBuildFile(global_flags,
     return (build_file_path,
             build_file_data,
             dependencies)
-  except GypError, e:
+  except GypError as e:
     sys.stderr.write("gyp: %s\n" % e)
     return None
-  except Exception, e:
-    print >>sys.stderr, 'Exception:', e
-    print >>sys.stderr, traceback.format_exc()
+  except Exception as e:
+    print('Exception:', e, file=sys.stderr)
+    print(traceback.format_exc(), file=sys.stderr)
     return None
 
 
@@ -607,7 +614,7 @@ def LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
           args = (global_flags, dependency,
                   variables, includes, depth, check, generator_input_info),
           callback = parallel_state.LoadTargetBuildFileCallback)
-  except KeyboardInterrupt, e:
+  except KeyboardInterrupt as e:
     parallel_state.pool.terminate()
     raise e
 
@@ -907,7 +914,7 @@ def ExpandVariables(input, phase, variables, build_file):
                                  stderr=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  cwd=build_file_dir)
-          except Exception, e:
+          except Exception as e:
             raise GypError("%s while executing command '%s' in %s" %
                            (e, contents, build_file))
 
@@ -1021,7 +1028,7 @@ def ExpandVariables(input, phase, variables, build_file):
 
   # Convert all strings that are canonically-represented integers into integers.
   if type(output) is list:
-    for index in xrange(0, len(output)):
+    for index in range(0, len(output)):
       if IsStrCanonicalInt(output[index]):
         output[index] = int(output[index])
   elif IsStrCanonicalInt(output):
@@ -1092,13 +1099,13 @@ def EvalSingleCondition(
     if eval(ast_code, {'__builtins__': None}, variables):
       return true_dict
     return false_dict
-  except SyntaxError, e:
+  except SyntaxError as e:
     syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
                                'at character %d.' %
                                (str(e.args[0]), e.text, build_file, e.offset),
                                e.filename, e.lineno, e.offset, e.text)
     raise syntax_error
-  except NameError, e:
+  except NameError as e:
     gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
                                (cond_expr_expanded, build_file))
     raise GypError(e)
@@ -1153,7 +1160,7 @@ def ProcessConditionsInDict(the_dict, phase, variables, build_file):
 def LoadAutomaticVariablesFromDict(variables, the_dict):
   # Any keys with plain string values in the_dict become automatic variables.
   # The variable name is the key name with a "_" character prepended.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     if type(value) in (str, int, list):
       variables['_' + key] = value
 
@@ -1166,7 +1173,7 @@ def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
   # the_dict in the_dict's parent dict.  If the_dict's parent is not a dict
   # (it could be a list or it could be parentless because it is a root dict),
   # the_dict_key will be None.
-  for key, value in the_dict.get('variables', {}).iteritems():
+  for key, value in the_dict.get('variables', {}).items():
     if type(value) not in (str, int, list):
       continue
 
@@ -1205,7 +1212,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
     # list before we process them so that you can reference one
     # variable from another.  They will be fully expanded by recursion
     # in ExpandVariables.
-    for key, value in the_dict['variables'].iteritems():
+    for key, value in the_dict['variables'].items():
       variables[key] = value
 
     # Handle the associated variables dict first, so that any variable
@@ -1218,7 +1225,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
 
   LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
 
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     # Skip "variables", which was already processed if present.
     if key != 'variables' and type(value) is str:
       expanded = ExpandVariables(value, phase, variables, build_file)
@@ -1276,7 +1283,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
 
   # Recurse into child dicts, or process child lists which may result in
   # further recursion into descendant dicts.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     # Skip "variables" and string values, which were already processed if
     # present.
     if key == 'variables' or type(value) is str:
@@ -1373,12 +1380,12 @@ def QualifyDependencies(targets):
                              for dep in dependency_sections
                              for op in ('', '!', '/')]
 
-  for target, target_dict in targets.iteritems():
+  for target, target_dict in targets.items():
     target_build_file = gyp.common.BuildFile(target)
     toolset = target_dict['toolset']
     for dependency_key in all_dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
-      for index in xrange(0, len(dependencies)):
+      for index in range(0, len(dependencies)):
         dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
             target_build_file, dependencies[index], toolset)
         if not multiple_toolsets:
@@ -1413,13 +1420,13 @@ def ExpandWildcardDependencies(targets, data):
   dependency list, must be qualified when this function is called.
   """
 
-  for target, target_dict in targets.iteritems():
+  for target, target_dict in targets.items():
     toolset = target_dict['toolset']
     target_build_file = gyp.common.BuildFile(target)
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
 
-      # Loop this way instead of "for dependency in" or "for index in xrange"
+      # Loop this way instead of "for dependency in" or "for index in range"
       # because the dependencies list will be modified within the loop body.
       index = 0
       while index < len(dependencies):
@@ -1475,7 +1482,7 @@ def Unify(l):
 def RemoveDuplicateDependencies(targets):
   """Makes sure every dependency appears only once in all targets's dependency
   lists."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1491,7 +1498,7 @@ def Filter(l, item):
 def RemoveSelfDependencies(targets):
   """Remove self dependencies from targets that have the prune_self_dependency
   variable set."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1504,7 +1511,7 @@ def RemoveSelfDependencies(targets):
 def RemoveLinkDependenciesFromNoneTargets(targets):
   """Remove dependencies having the 'link_dependency' attribute from the 'none'
   targets."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1790,14 +1797,14 @@ def BuildDependencyList(targets):
   # Create a DependencyGraphNode for each target.  Put it into a dict for easy
   # access.
   dependency_nodes = {}
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     if target not in dependency_nodes:
       dependency_nodes[target] = DependencyGraphNode(target)
 
   # Set up the dependency links.  Targets that have no dependencies are treated
   # as dependent on root_node.
   root_node = DependencyGraphNode(None)
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     target_node = dependency_nodes[target]
     target_build_file = gyp.common.BuildFile(target)
     dependencies = spec.get('dependencies')
@@ -1846,14 +1853,14 @@ def VerifyNoGYPFileCircularDependencies(targets):
       dependency_nodes[build_file] = DependencyGraphNode(build_file)
 
   # Set up the dependency links.
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     build_file = gyp.common.BuildFile(target)
     build_file_node = dependency_nodes[build_file]
     target_dependencies = spec.get('dependencies', [])
     for dependency in target_dependencies:
       try:
         dependency_build_file = gyp.common.BuildFile(dependency)
-      except GypError, e:
+      except GypError as e:
         gyp.common.ExceptionAppend(
             e, 'while computing dependencies of .gyp file %s' % build_file)
         raise
@@ -2033,7 +2040,7 @@ def MakePathRelative(to_file, fro_file, item):
         gyp.common.RelativePath(os.path.dirname(fro_file),
                                 os.path.dirname(to_file)),
                                 item)).replace('\\', '/')
-    if item[-1] == '/':
+    if item[-1:] == '/':
       ret += '/'
     return ret
 
@@ -2111,7 +2118,7 @@ def is_in_set_or_list(x, s, l):
 
 def MergeDicts(to, fro, to_file, fro_file):
   # I wanted to name the parameter "from" but it's a Python keyword...
-  for k, v in fro.iteritems():
+  for k, v in fro.items():
     # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
     # copy semantics.  Something else may want to merge from the |fro| dict
     # later, and having the same dict ref pointed to twice in the tree isn't
@@ -2246,13 +2253,13 @@ def SetUpConfigurations(target, target_dict):
   if not 'configurations' in target_dict:
     target_dict['configurations'] = {'Default': {}}
   if not 'default_configuration' in target_dict:
-    concrete = [i for (i, config) in target_dict['configurations'].iteritems()
+    concrete = [i for (i, config) in target_dict['configurations'].items()
                 if not config.get('abstract')]
     target_dict['default_configuration'] = sorted(concrete)[0]
 
   merged_configurations = {}
   configs = target_dict['configurations']
-  for (configuration, old_configuration_dict) in configs.iteritems():
+  for (configuration, old_configuration_dict) in configs.items():
     # Skip abstract configurations (saves work only).
     if old_configuration_dict.get('abstract'):
       continue
@@ -2260,7 +2267,7 @@ def SetUpConfigurations(target, target_dict):
     # Get the inheritance relationship right by making a copy of the target
     # dict.
     new_configuration_dict = {}
-    for (key, target_val) in target_dict.iteritems():
+    for (key, target_val) in target_dict.items():
       key_ext = key[-1:]
       if key_ext in key_suffixes:
         key_base = key[:-1]
@@ -2344,7 +2351,7 @@ def ProcessListFiltersInDict(name, the_dict):
 
   lists = []
   del_lists = []
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     operation = key[-1]
     if operation != '!' and operation != '/':
       continue
@@ -2392,7 +2399,7 @@ def ProcessListFiltersInDict(name, the_dict):
     exclude_key = list_key + '!'
     if exclude_key in the_dict:
       for exclude_item in the_dict[exclude_key]:
-        for index in xrange(0, len(the_list)):
+        for index in range(0, len(the_list)):
           if exclude_item == the_list[index]:
             # This item matches the exclude_item, so set its action to 0
             # (exclude).
@@ -2418,7 +2425,7 @@ def ProcessListFiltersInDict(name, the_dict):
           raise ValueError('Unrecognized action ' + action + ' in ' + name + \
                            ' key ' + regex_key)
 
-        for index in xrange(0, len(the_list)):
+        for index in range(0, len(the_list)):
           list_item = the_list[index]
           if list_actions[index] == action_value:
             # Even if the regex matches, nothing will change so continue (regex
@@ -2449,7 +2456,7 @@ def ProcessListFiltersInDict(name, the_dict):
     # the indices of items that haven't been seen yet don't shift.  That means
     # that things need to be prepended to excluded_list to maintain them in the
     # same order that they existed in the_list.
-    for index in xrange(len(list_actions) - 1, -1, -1):
+    for index in range(len(list_actions) - 1, -1, -1):
       if list_actions[index] == 0:
         # Dump anything with action 0 (exclude).  Keep anything with action 1
         # (include) or -1 (no include or exclude seen for the item).
@@ -2462,7 +2469,7 @@ def ProcessListFiltersInDict(name, the_dict):
       the_dict[excluded_key] = excluded_list
 
   # Now recurse into subdicts and lists that may contain dicts.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     if type(value) is dict:
       ProcessListFiltersInDict(key, value)
     elif type(value) is list:
@@ -2519,13 +2526,13 @@ def ValidateSourcesInTarget(target, target_dict, build_file,
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
       error += '  %s: %s\n' % (basename, ' '.join(files))
 
   if error:
-    print('static library %s has several files with the same basename:\n' %
-          target + error + 'libtool on Mac cannot handle that. Use '
+    print('static library %s has several files with the same basename:\n' % target
+          + error + 'libtool on Mac cannot handle that. Use '
           '--no-duplicate-basename-check to disable this validation.')
     raise GypError('Duplicate basenames in sources section, see list above')
 
@@ -2639,7 +2646,7 @@ def ValidateActionsInTarget(target, target_dict, build_file):
 def TurnIntIntoStrInDict(the_dict):
   """Given dict the_dict, recursively converts all integers into strings.
   """
-  # Use items instead of iteritems because there's no need to try to look at
+  # Use items instead of items because there's no need to try to look at
   # reinserted keys and their associated values.
   for k, v in the_dict.items():
     if type(v) is int:
@@ -2658,7 +2665,7 @@ def TurnIntIntoStrInDict(the_dict):
 def TurnIntIntoStrInList(the_list):
   """Given list the_list, recursively converts all integers into strings.
   """
-  for index in xrange(0, len(the_list)):
+  for index in range(0, len(the_list)):
     item = the_list[index]
     if type(item) is int:
       the_list[index] = str(item)
@@ -2776,7 +2783,7 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
       try:
         LoadTargetBuildFile(build_file, data, aux_data,
                             variables, includes, depth, check, True)
-      except Exception, e:
+      except Exception as e:
         gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
         raise
 
@@ -2798,7 +2805,7 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
   RemoveLinkDependenciesFromNoneTargets(targets)
 
   # Apply exclude (!) and regex (/) list filters only for dependency_sections.
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     tmp_dict = {}
     for key_base in dependency_sections:
       for op in ('', '!', '/'):
diff --git a/gyp/pylib/gyp/input_test.py b/gyp/pylib/gyp/input_test.py
index 4234fbb830..1bc5e3d308 100755
--- a/gyp/pylib/gyp/input_test.py
+++ b/gyp/pylib/gyp/input_test.py
@@ -22,38 +22,38 @@ def _create_dependency(self, dependent, dependency):
     dependency.dependents.append(dependent)
 
   def test_no_cycle_empty_graph(self):
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_no_cycle_line(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['b'], self.nodes['c'])
     self._create_dependency(self.nodes['c'], self.nodes['d'])
 
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_no_cycle_dag(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['a'], self.nodes['c'])
     self._create_dependency(self.nodes['b'], self.nodes['c'])
 
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_cycle_self_reference(self):
     self._create_dependency(self.nodes['a'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'], self.nodes['a']]],
+    self.assertEqual([[self.nodes['a'], self.nodes['a']]],
                       self.nodes['a'].FindCycles())
 
   def test_cycle_two_nodes(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['b'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
+    self.assertEqual([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
                       self.nodes['a'].FindCycles())
-    self.assertEquals([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
+    self.assertEqual([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
                       self.nodes['b'].FindCycles())
 
   def test_two_cycles(self):
@@ -68,7 +68,7 @@ def test_two_cycles(self):
        [self.nodes['a'], self.nodes['b'], self.nodes['a']] in cycles)
     self.assertTrue(
        [self.nodes['b'], self.nodes['c'], self.nodes['b']] in cycles)
-    self.assertEquals(2, len(cycles))
+    self.assertEqual(2, len(cycles))
 
   def test_big_cycle(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
@@ -77,7 +77,7 @@ def test_big_cycle(self):
     self._create_dependency(self.nodes['d'], self.nodes['e'])
     self._create_dependency(self.nodes['e'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'],
+    self.assertEqual([[self.nodes['a'],
                         self.nodes['b'],
                         self.nodes['c'],
                         self.nodes['d'],
diff --git a/gyp/pylib/gyp/mac_tool.py b/gyp/pylib/gyp/mac_tool.py
index eeeaceb0c7..b8b7344eff 100755
--- a/gyp/pylib/gyp/mac_tool.py
+++ b/gyp/pylib/gyp/mac_tool.py
@@ -8,6 +8,8 @@
 These functions are executed via gyp-mac-tool when using the Makefile generator.
 """
 
+from __future__ import print_function
+
 import fcntl
 import fnmatch
 import glob
@@ -125,7 +127,7 @@ def _DetectInputEncoding(self, file_name):
     fp = open(file_name, 'rb')
     try:
       header = fp.read(3)
-    except e:
+    except Exception:
       fp.close()
       return None
     fp.close()
@@ -243,7 +245,7 @@ def ExecFilterLibtool(self, *cmd_list):
     _, err = libtoolout.communicate()
     for line in err.splitlines():
       if not libtool_re.match(line) and not libtool_re5.match(line):
-        print >>sys.stderr, line
+        print(line, file=sys.stderr)
     # Unconditionally touch the output .a file on the command line if present
     # and the command succeeded. A bit hacky.
     if not libtoolout.returncode:
@@ -324,7 +326,7 @@ def ExecCompileXcassets(self, keys, *inputs):
       ])
     if keys:
       keys = json.loads(keys)
-      for key, value in keys.iteritems():
+      for key, value in keys.items():
         arg_name = '--' + key
         if isinstance(value, bool):
           if value:
@@ -440,8 +442,7 @@ def _FindProvisioningProfile(self, profile, bundle_identifier):
     profiles_dir = os.path.join(
         os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
     if not os.path.isdir(profiles_dir):
-      print >>sys.stderr, (
-          'cannot find mobile provisioning for %s' % bundle_identifier)
+      print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr)
       sys.exit(1)
     provisioning_profiles = None
     if profile:
@@ -462,8 +463,7 @@ def _FindProvisioningProfile(self, profile, bundle_identifier):
           valid_provisioning_profiles[app_id_pattern] = (
               profile_path, profile_data, team_identifier)
     if not valid_provisioning_profiles:
-      print >>sys.stderr, (
-          'cannot find mobile provisioning for %s' % bundle_identifier)
+      print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr)
       sys.exit(1)
     # If the user has multiple provisioning profiles installed that can be
     # used for ${bundle_identifier}, pick the most specific one (ie. the
@@ -487,7 +487,7 @@ def _LoadProvisioningProfile(self, profile_path):
 
   def _MergePlist(self, merged_plist, plist):
     """Merge |plist| into |merged_plist|."""
-    for key, value in plist.iteritems():
+    for key, value in plist.items():
       if isinstance(value, dict):
         merged_value = merged_plist.get(key, {})
         if isinstance(merged_value, dict):
@@ -597,7 +597,7 @@ def _ExpandVariables(self, data, substitutions):
       the key was not found.
     """
     if isinstance(data, str):
-      for key, value in substitutions.iteritems():
+      for key, value in substitutions.items():
         data = data.replace('$(%s)' % key, value)
       return data
     if isinstance(data, list):
diff --git a/gyp/pylib/gyp/msvs_emulation.py b/gyp/pylib/gyp/msvs_emulation.py
index ca67b122f0..75da78526c 100644
--- a/gyp/pylib/gyp/msvs_emulation.py
+++ b/gyp/pylib/gyp/msvs_emulation.py
@@ -205,7 +205,7 @@ def __init__(self, spec, generator_flags):
     configs = spec['configurations']
     for field, default in supported_fields:
       setattr(self, field, {})
-      for configname, config in configs.iteritems():
+      for configname, config in configs.items():
         getattr(self, field)[configname] = config.get(field, default())
 
     self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
@@ -941,7 +941,7 @@ def ExpandMacros(string, expansions):
   """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
   for the canonical way to retrieve a suitable dict."""
   if '$' in string:
-    for old, new in expansions.iteritems():
+    for old, new in expansions.items():
       assert '$(' not in new, new
       string = string.replace(old, new)
   return string
@@ -985,7 +985,7 @@ def _FormatAsEnvironmentBlock(envvar_dict):
   CreateProcess documentation for more details."""
   block = ''
   nul = '\0'
-  for key, value in envvar_dict.iteritems():
+  for key, value in envvar_dict.items():
     block += key + '=' + value + nul
   block += nul
   return block
diff --git a/gyp/pylib/gyp/ordered_dict.py b/gyp/pylib/gyp/ordered_dict.py
index a1e89f9199..6fe9c1f6c7 100644
--- a/gyp/pylib/gyp/ordered_dict.py
+++ b/gyp/pylib/gyp/ordered_dict.py
@@ -161,8 +161,8 @@ def itervalues(self):
         for k in self:
             yield self[k]
 
-    def iteritems(self):
-        'od.iteritems -> an iterator over the (key, value) items in od'
+    def items(self):
+        'od.items -> an iterator over the (key, value) items in od'
         for k in self:
             yield (k, self[k])
 
diff --git a/gyp/pylib/gyp/simple_copy.py b/gyp/pylib/gyp/simple_copy.py
index 74c98c5a79..463929386e 100644
--- a/gyp/pylib/gyp/simple_copy.py
+++ b/gyp/pylib/gyp/simple_copy.py
@@ -38,7 +38,7 @@ def _deepcopy_list(x):
 
 def _deepcopy_dict(x):
   y = {}
-  for key, value in x.iteritems():
+  for key, value in x.items():
     y[deepcopy(key)] = deepcopy(value)
   return y
 d[dict] = _deepcopy_dict
diff --git a/gyp/pylib/gyp/win_tool.py b/gyp/pylib/gyp/win_tool.py
index bb6f1ea436..bca0b9e346 100755
--- a/gyp/pylib/gyp/win_tool.py
+++ b/gyp/pylib/gyp/win_tool.py
@@ -9,6 +9,8 @@
 These functions are executed via gyp-win-tool when using the ninja generator.
 """
 
+from __future__ import print_function
+
 import os
 import re
 import shutil
@@ -126,7 +128,7 @@ def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args):
       if (not line.startswith('   Creating library ') and
           not line.startswith('Generating code') and
           not line.startswith('Finished generating code')):
-        print line
+        print(line)
     return link.returncode
 
   def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname,
@@ -215,7 +217,7 @@ def ExecManifestWrapper(self, arch, *args):
     out, _ = popen.communicate()
     for line in out.splitlines():
       if line and 'manifest authoring warning 81010002' not in line:
-        print line
+        print(line)
     return popen.returncode
 
   def ExecManifestToRc(self, arch, *args):
@@ -255,7 +257,7 @@ def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl,
                      for x in lines if x.startswith(prefixes))
     for line in lines:
       if not line.startswith(prefixes) and line not in processing:
-        print line
+        print(line)
     return popen.returncode
 
   def ExecAsmWrapper(self, arch, *args):
@@ -269,7 +271,7 @@ def ExecAsmWrapper(self, arch, *args):
           not line.startswith('Microsoft (R) Macro Assembler') and
           not line.startswith(' Assembling: ') and
           line):
-        print line
+        print(line)
     return popen.returncode
 
   def ExecRcWrapper(self, arch, *args):
@@ -283,7 +285,7 @@ def ExecRcWrapper(self, arch, *args):
       if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
           not line.startswith('Copyright (C) Microsoft Corporation') and
           line):
-        print line
+        print(line)
     return popen.returncode
 
   def ExecActionWrapper(self, arch, rspfile, *dir):
@@ -292,7 +294,7 @@ def ExecActionWrapper(self, arch, rspfile, *dir):
     env = self._GetEnv(arch)
     # TODO(scottmg): This is a temporary hack to get some specific variables
     # through to actions that are set after gyp-time. http://crbug.com/333738.
-    for k, v in os.environ.iteritems():
+    for k, v in os.environ.items():
       if k not in env:
         env[k] = v
     args = open(rspfile).read()
diff --git a/gyp/pylib/gyp/xcode_emulation.py b/gyp/pylib/gyp/xcode_emulation.py
index b06bdc4e8b..66f325932a 100644
--- a/gyp/pylib/gyp/xcode_emulation.py
+++ b/gyp/pylib/gyp/xcode_emulation.py
@@ -7,6 +7,8 @@
 other build systems, such as make and ninja.
 """
 
+from __future__ import print_function
+
 import copy
 import gyp.common
 import os
@@ -73,7 +75,7 @@ def _ExpandArchs(self, archs, sdkroot):
             if arch not in expanded_archs:
               expanded_archs.append(arch)
         except KeyError as e:
-          print 'Warning: Ignoring unsupported variable "%s".' % variable
+          print('Warning: Ignoring unsupported variable "%s".' % variable)
       elif arch not in expanded_archs:
         expanded_archs.append(arch)
     return expanded_archs
@@ -168,7 +170,7 @@ def __init__(self, spec):
     # the same for all configs are implicitly per-target settings.
     self.xcode_settings = {}
     configs = spec['configurations']
-    for configname, config in configs.iteritems():
+    for configname, config in configs.items():
       self.xcode_settings[configname] = config.get('xcode_settings', {})
       self._ConvertConditionalKeys(configname)
       if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET',
@@ -194,8 +196,8 @@ def _ConvertConditionalKeys(self, configname):
           new_key = key.split("[")[0]
           settings[new_key] = settings[key]
       else:
-        print 'Warning: Conditional keys not implemented, ignoring:', \
-              ' '.join(conditional_keys)
+        print('Warning: Conditional keys not implemented, ignoring:', \
+              ' '.join(conditional_keys))
       del settings[key]
 
   def _Settings(self):
@@ -213,7 +215,7 @@ def _Appendf(self, lst, test_key, format_str, default=None):
 
   def _WarnUnimplemented(self, test_key):
     if test_key in self._Settings():
-      print 'Warning: Ignoring not yet implemented key "%s".' % test_key
+      print('Warning: Ignoring not yet implemented key "%s".' % test_key)
 
   def IsBinaryOutputFormat(self, configname):
     default = "binary" if self.isIOS else "xml"
@@ -233,6 +235,9 @@ def _IsIosWatchKitExtension(self):
   def _IsIosWatchApp(self):
     return int(self.spec.get('ios_watch_app', 0)) != 0
 
+  def _IsXCTest(self):
+    return int(self.spec.get('mac_xctest_bundle', 0)) != 0
+
   def GetFrameworkVersion(self):
     """Returns the framework version of the current target. Only valid for
     bundles."""
@@ -429,7 +434,7 @@ def _GetSdkVersionInfoItem(self, sdk, infoitem):
     # Since the CLT has no SDK paths anyway, returning None is the
     # most sensible route and should still do the right thing.
     try:
-      return GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem])
+      return GetStdoutQuiet(['xcodebuild', '-version', '-sdk', sdk, infoitem])
     except:
       pass
 
@@ -568,6 +573,11 @@ def GetCflags(self, configname, arch=None):
 
     cflags += self._Settings().get('WARNING_CFLAGS', [])
 
+    if self._IsXCTest():
+      platform_root = self._XcodePlatformPath(configname)
+      if platform_root:
+        cflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
+
     if sdk_root:
       framework_root = sdk_root
     else:
@@ -831,6 +841,11 @@ def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
     for directory in framework_dirs:
       ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
 
+    if self._IsXCTest():
+      platform_root = self._XcodePlatformPath(configname)
+      if platform_root:
+        cflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
+
     is_extension = self._IsIosAppExtension() or self._IsIosWatchKitExtension()
     if sdk_root and is_extension:
       # Adds the link flags for extensions. These flags are common for all
@@ -876,7 +891,7 @@ def GetPerTargetSettings(self):
         result = dict(self.xcode_settings[configname])
         first_pass = False
       else:
-        for key, value in self.xcode_settings[configname].iteritems():
+        for key, value in self.xcode_settings[configname].items():
           if key not in result:
             continue
           elif result[key] != value:
@@ -984,8 +999,8 @@ def _GetIOSPostbuilds(self, configname, output_binary):
     unimpl = ['OTHER_CODE_SIGN_FLAGS']
     unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
     if unimpl:
-      print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
-          ', '.join(sorted(unimpl)))
+      print('Warning: Some codesign keys not implemented, ignoring: %s' % (
+          ', '.join(sorted(unimpl))))
 
     return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % (
         os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
@@ -1251,7 +1266,7 @@ def XcodeVersion():
   if XCODE_VERSION_CACHE:
     return XCODE_VERSION_CACHE
   try:
-    version_list = GetStdout(['xcodebuild', '-version']).splitlines()
+    version_list = GetStdoutQuiet(['xcodebuild', '-version']).splitlines()
     # In some circumstances xcodebuild exits 0 but doesn't return
     # the right results; for example, a user on 10.7 or 10.8 with
     # a bogus path set via xcode-select
@@ -1262,7 +1277,7 @@ def XcodeVersion():
   except:
     version = CLTVersion()
     if version:
-      version = re.match(r'(\d\.\d\.?\d*)', version).groups()[0]
+      version = re.match(r'(\d+\.\d+\.?\d*)', version).groups()[0]
     else:
       raise GypError("No Xcode or CLT version detected!")
     # The CLT has no build information, so we return an empty string.
@@ -1301,6 +1316,17 @@ def CLTVersion():
       continue
 
 
+def GetStdoutQuiet(cmdlist):
+  """Returns the content of standard output returned by invoking |cmdlist|.
+  Ignores the stderr.
+  Raises |GypError| if the command return with a non-zero return code."""
+  job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  out = job.communicate()[0]
+  if job.returncode != 0:
+    raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
+  return out.rstrip('\n')
+
+
 def GetStdout(cmdlist):
   """Returns the content of standard output returned by invoking |cmdlist|.
   Raises |GypError| if the command return with a non-zero return code."""
@@ -1573,7 +1599,7 @@ def GetEdges(node):
     order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
     order.reverse()
     return order
-  except gyp.common.CycleError, e:
+  except gyp.common.CycleError as e:
     raise GypError(
         'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
 
@@ -1613,7 +1639,7 @@ def _AddIOSDeviceConfigurations(targets):
   for target_dict in targets.itervalues():
     toolset = target_dict['toolset']
     configs = target_dict['configurations']
-    for config_name, config_dict in dict(configs).iteritems():
+    for config_name, config_dict in dict(configs).items():
       iphoneos_config_dict = copy.deepcopy(config_dict)
       configs[config_name + '-iphoneos'] = iphoneos_config_dict
       configs[config_name + '-iphonesimulator'] = config_dict
diff --git a/gyp/pylib/gyp/xcode_ninja.py b/gyp/pylib/gyp/xcode_ninja.py
index 3820d6bf04..5acd82e004 100644
--- a/gyp/pylib/gyp/xcode_ninja.py
+++ b/gyp/pylib/gyp/xcode_ninja.py
@@ -28,7 +28,7 @@ def _WriteWorkspace(main_gyp, sources_gyp, params):
     workspace_path = os.path.join(options.generator_output, workspace_path)
   try:
     os.makedirs(workspace_path)
-  except OSError, e:
+  except OSError as e:
     if e.errno != errno.EEXIST:
       raise
   output_string = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
@@ -161,7 +161,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
     params: Dict of global options for gyp.
   """
   orig_gyp = params['build_files'][0]
-  for gyp_name, gyp_dict in data.iteritems():
+  for gyp_name, gyp_dict in data.items():
     if gyp_name == orig_gyp:
       depth = gyp_dict['_DEPTH']
 
@@ -228,7 +228,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
   sources_target['configurations'] = {'Default': { 'include_dirs': [ depth ] } }
 
   sources = []
-  for target, target_dict in target_dicts.iteritems():
+  for target, target_dict in target_dicts.items():
     base = os.path.dirname(target)
     files = target_dict.get('sources', []) + \
             target_dict.get('mac_bundle_resources', [])
diff --git a/gyp/pylib/gyp/xcodeproj_file.py b/gyp/pylib/gyp/xcodeproj_file.py
index d08b7f7770..9bd582e477 100644
--- a/gyp/pylib/gyp/xcodeproj_file.py
+++ b/gyp/pylib/gyp/xcodeproj_file.py
@@ -314,7 +314,7 @@ def Copy(self):
     """
 
     that = self.__class__(id=self.id, parent=self.parent)
-    for key, value in self._properties.iteritems():
+    for key, value in self._properties.items():
       is_strong = self._schema[key][2]
 
       if isinstance(value, XCObject):
@@ -452,7 +452,7 @@ def _HashUpdate(hash, data):
       digest_int_count = hash.digest_size / 4
       digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest())
       id_ints = [0, 0, 0]
-      for index in xrange(0, digest_int_count):
+      for index in range(0, digest_int_count):
         id_ints[index % 3] ^= digest_ints[index]
       self.id = '%08X%08X%08X' % tuple(id_ints)
 
@@ -475,7 +475,7 @@ def Children(self):
     """Returns a list of all of this object's owned (strong) children."""
 
     children = []
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong) = attributes[0:3]
       if is_strong and property in self._properties:
         if not is_list:
@@ -622,7 +622,7 @@ def _XCPrintableValue(self, tabs, value, flatten_list=False):
         printable += end_tabs + ')'
     elif isinstance(value, dict):
       printable = '{' + sep
-      for item_key, item_value in sorted(value.iteritems()):
+      for item_key, item_value in sorted(value.items()):
         printable += element_tabs + \
             self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \
             self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \
@@ -691,7 +691,7 @@ def _XCKVPrint(self, file, tabs, key, value):
           printable_value[0] == '"' and printable_value[-1] == '"':
         printable_value = printable_value[1:-1]
       printable += printable_key + ' = ' + printable_value + ';' + after_kv
-    except TypeError, e:
+    except TypeError as e:
       gyp.common.ExceptionAppend(e,
                                  'while printing key "%s"' % key)
       raise
@@ -730,7 +730,7 @@ def Print(self, file=sys.stdout):
     self._XCKVPrint(file, 3, 'isa', self.__class__.__name__)
 
     # The remaining elements of an object dictionary are sorted alphabetically.
-    for property, value in sorted(self._properties.iteritems()):
+    for property, value in sorted(self._properties.items()):
       self._XCKVPrint(file, 3, property, value)
 
     # End the object.
@@ -752,7 +752,7 @@ def UpdateProperties(self, properties, do_copy=False):
     if properties is None:
       return
 
-    for property, value in properties.iteritems():
+    for property, value in properties.items():
       # Make sure the property is in the schema.
       if not property in self._schema:
         raise KeyError(property + ' not in ' + self.__class__.__name__)
@@ -865,7 +865,7 @@ def VerifyHasRequiredProperties(self):
 
     # TODO(mark): A stronger verification mechanism is needed.  Some
     # subclasses need to perform validation beyond what the schema can enforce.
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong, is_required) = attributes[0:4]
       if is_required and not property in self._properties:
         raise KeyError(self.__class__.__name__ + ' requires ' + property)
@@ -875,7 +875,7 @@ def _SetDefaultsFromSchema(self):
     overwrite properties that have already been set."""
 
     defaults = {}
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong, is_required) = attributes[0:4]
       if is_required and len(attributes) >= 5 and \
           not property in self._properties:
@@ -1426,7 +1426,7 @@ def PathHashables(self):
     xche = self
     while xche != None and isinstance(xche, XCHierarchicalElement):
       xche_hashables = xche.Hashables()
-      for index in xrange(0, len(xche_hashables)):
+      for index in range(0, len(xche_hashables)):
         hashables.insert(index, xche_hashables[index])
       xche = xche.parent
     return hashables
@@ -2401,7 +2401,7 @@ def HeadersPhase(self):
       # The headers phase should come before the resources, sources, and
       # frameworks phases, if any.
       insert_at = len(self._properties['buildPhases'])
-      for index in xrange(0, len(self._properties['buildPhases'])):
+      for index in range(0, len(self._properties['buildPhases'])):
         phase = self._properties['buildPhases'][index]
         if isinstance(phase, PBXResourcesBuildPhase) or \
            isinstance(phase, PBXSourcesBuildPhase) or \
@@ -2422,7 +2422,7 @@ def ResourcesPhase(self):
       # The resources phase should come before the sources and frameworks
       # phases, if any.
       insert_at = len(self._properties['buildPhases'])
-      for index in xrange(0, len(self._properties['buildPhases'])):
+      for index in range(0, len(self._properties['buildPhases'])):
         phase = self._properties['buildPhases'][index]
         if isinstance(phase, PBXSourcesBuildPhase) or \
            isinstance(phase, PBXFrameworksBuildPhase):
@@ -2844,7 +2844,7 @@ def CompareProducts(x, y, remote_products):
       # determine the sort order.
       return cmp(x_index, y_index)
 
-    for other_pbxproject, ref_dict in self._other_pbxprojects.iteritems():
+    for other_pbxproject, ref_dict in self._other_pbxprojects.items():
       # Build up a list of products in the remote project file, ordered the
       # same as the targets that produce them.
       remote_products = []
@@ -2889,7 +2889,7 @@ def Print(self, file=sys.stdout):
       self._XCPrint(file, 0, '{ ')
     else:
       self._XCPrint(file, 0, '{\n')
-    for property, value in sorted(self._properties.iteritems(),
+    for property, value in sorted(self._properties.items(),
                                   cmp=lambda x, y: cmp(x, y)):
       if property == 'objects':
         self._PrintObjects(file)
diff --git a/gyp/tools/graphviz.py b/gyp/tools/graphviz.py
index 326ae221cf..538b059da4 100755
--- a/gyp/tools/graphviz.py
+++ b/gyp/tools/graphviz.py
@@ -8,6 +8,8 @@
 generate input suitable for graphviz to render a dependency graph of
 targets."""
 
+from __future__ import print_function
+
 import collections
 import json
 import sys
@@ -50,9 +52,9 @@ def WriteGraph(edges):
     build_file, target_name, toolset = ParseTarget(src)
     files[build_file].append(src)
 
-  print 'digraph D {'
-  print '  fontsize=8'  # Used by subgraphs.
-  print '  node [fontsize=8]'
+  print('digraph D {')
+  print('  fontsize=8')  # Used by subgraphs.
+  print('  node [fontsize=8]')
 
   # Output nodes by file.  We must first write out each node within
   # its file grouping before writing out any edges that may refer
@@ -63,31 +65,31 @@ def WriteGraph(edges):
       # the display by making it a box without an internal node.
       target = targets[0]
       build_file, target_name, toolset = ParseTarget(target)
-      print '  "%s" [shape=box, label="%s\\n%s"]' % (target, filename,
-                                                     target_name)
+      print('  "%s" [shape=box, label="%s\\n%s"]' % (target, filename,
+                                                     target_name))
     else:
       # Group multiple nodes together in a subgraph.
-      print '  subgraph "cluster_%s" {' % filename
-      print '    label = "%s"' % filename
+      print('  subgraph "cluster_%s" {' % filename)
+      print('    label = "%s"' % filename)
       for target in targets:
         build_file, target_name, toolset = ParseTarget(target)
-        print '    "%s" [label="%s"]' % (target, target_name)
-      print '  }'
+        print('    "%s" [label="%s"]' % (target, target_name))
+      print('  }')
 
   # Now that we've placed all the nodes within subgraphs, output all
   # the edges between nodes.
   for src, dsts in edges.items():
     for dst in dsts:
-      print '  "%s" -> "%s"' % (src, dst)
+      print('  "%s" -> "%s"' % (src, dst))
 
-  print '}'
+  print('}')
 
 
 def main():
   if len(sys.argv) < 2:
-    print >>sys.stderr, __doc__
-    print >>sys.stderr
-    print >>sys.stderr, 'usage: %s target1 target2...' % (sys.argv[0])
+    print(__doc__, file=sys.stderr)
+    print(file=sys.stderr)
+    print('usage: %s target1 target2...' % (sys.argv[0]), file=sys.stderr)
     return 1
 
   edges = LoadEdges('dump.json', sys.argv[1:])
diff --git a/gyp/tools/pretty_gyp.py b/gyp/tools/pretty_gyp.py
index c51d35872c..d01c692edc 100755
--- a/gyp/tools/pretty_gyp.py
+++ b/gyp/tools/pretty_gyp.py
@@ -6,6 +6,8 @@
 
 """Pretty-prints the contents of a GYP file."""
 
+from __future__ import print_function
+
 import sys
 import re
 
@@ -119,22 +121,22 @@ def prettyprint_input(lines):
   last_line = ""
   for line in lines:
     if COMMENT_RE.match(line):
-      print line
+      print(line)
     else:
       line = line.strip('\r\n\t ')  # Otherwise doesn't strip \r on Unix.
       if len(line) > 0:
         (brace_diff, after) = count_braces(line)
         if brace_diff != 0:
           if after:
-            print " " * (basic_offset * indent) + line
+            print(" " * (basic_offset * indent) + line)
             indent += brace_diff
           else:
             indent += brace_diff
-            print " " * (basic_offset * indent) + line
+            print(" " * (basic_offset * indent) + line)
         else:
-          print " " * (basic_offset * indent) + line
+          print(" " * (basic_offset * indent) + line)
       else:
-        print ""
+        print("")
       last_line = line
 
 
diff --git a/gyp/tools/pretty_sln.py b/gyp/tools/pretty_sln.py
index ca8cf4ad3f..731844caf7 100755
--- a/gyp/tools/pretty_sln.py
+++ b/gyp/tools/pretty_sln.py
@@ -14,6 +14,8 @@
 
 __author__ = 'nsylvain (Nicolas Sylvain)'
 
+from __future__ import print_function
+
 import os
 import re
 import sys
@@ -26,7 +28,7 @@ def BuildProject(project, built, projects, deps):
   for dep in deps[project]:
     if dep not in built:
       BuildProject(dep, built, projects, deps)
-  print project
+  print(project)
   built.append(project)
 
 def ParseSolution(solution_file):
@@ -100,44 +102,44 @@ def ParseSolution(solution_file):
   return (projects, dependencies)
 
 def PrintDependencies(projects, deps):
-  print "---------------------------------------"
-  print "Dependencies for all projects"
-  print "---------------------------------------"
-  print "--                                   --"
+  print("---------------------------------------")
+  print("Dependencies for all projects")
+  print("---------------------------------------")
+  print("--                                   --")
 
   for (project, dep_list) in sorted(deps.items()):
-    print "Project : %s" % project
-    print "Path : %s" % projects[project][0]
+    print("Project : %s" % project)
+    print("Path : %s" % projects[project][0])
     if dep_list:
       for dep in dep_list:
-        print "  - %s" % dep
-    print ""
+        print("  - %s" % dep)
+    print("")
 
-  print "--                                   --"
+  print("--                                   --")
 
 def PrintBuildOrder(projects, deps):
-  print "---------------------------------------"
-  print "Build order                            "
-  print "---------------------------------------"
-  print "--                                   --"
+  print("---------------------------------------")
+  print("Build order                            ")
+  print("---------------------------------------")
+  print("--                                   --")
 
   built = []
   for (project, _) in sorted(deps.items()):
     if project not in built:
       BuildProject(project, built, projects, deps)
 
-  print "--                                   --"
+  print("--                                   --")
 
 def PrintVCProj(projects):
 
   for project in projects:
-    print "-------------------------------------"
-    print "-------------------------------------"
-    print project
-    print project
-    print project
-    print "-------------------------------------"
-    print "-------------------------------------"
+    print("-------------------------------------")
+    print("-------------------------------------")
+    print(project)
+    print(project)
+    print(project)
+    print("-------------------------------------")
+    print("-------------------------------------")
 
     project_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[1]),
                                                 projects[project][2]))
@@ -153,7 +155,7 @@ def PrintVCProj(projects):
 def main():
   # check if we have exactly 1 parameter.
   if len(sys.argv) < 2:
-    print 'Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0]
+    print('Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0])
     return 1
 
   (projects, deps) = ParseSolution(sys.argv[1])
diff --git a/gyp/tools/pretty_vcproj.py b/gyp/tools/pretty_vcproj.py
deleted file mode 100755
index 6099bd7cc4..0000000000
--- a/gyp/tools/pretty_vcproj.py
+++ /dev/null
@@ -1,329 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2012 Google Inc. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Make the format of a vcproj really pretty.
-
-   This script normalize and sort an xml. It also fetches all the properties
-   inside linked vsprops and include them explicitly in the vcproj.
-
-   It outputs the resulting xml to stdout.
-"""
-
-__author__ = 'nsylvain (Nicolas Sylvain)'
-
-import os
-import sys
-
-from xml.dom.minidom import parse
-from xml.dom.minidom import Node
-
-REPLACEMENTS = dict()
-ARGUMENTS = None
-
-
-class CmpTuple(object):
-  """Compare function between 2 tuple."""
-  def __call__(self, x, y):
-    return cmp(x[0], y[0])
-
-
-class CmpNode(object):
-  """Compare function between 2 xml nodes."""
-
-  def __call__(self, x, y):
-    def get_string(node):
-      node_string = "node"
-      node_string += node.nodeName
-      if node.nodeValue:
-        node_string += node.nodeValue
-
-      if node.attributes:
-        # We first sort by name, if present.
-        node_string += node.getAttribute("Name")
-
-        all_nodes = []
-        for (name, value) in node.attributes.items():
-          all_nodes.append((name, value))
-
-        all_nodes.sort(CmpTuple())
-        for (name, value) in all_nodes:
-          node_string += name
-          node_string += value
-
-      return node_string
-
-    return cmp(get_string(x), get_string(y))
-
-
-def PrettyPrintNode(node, indent=0):
-  if node.nodeType == Node.TEXT_NODE:
-    if node.data.strip():
-      print '%s%s' % (' '*indent, node.data.strip())
-    return
-
-  if node.childNodes:
-    node.normalize()
-  # Get the number of attributes
-  attr_count = 0
-  if node.attributes:
-    attr_count = node.attributes.length
-
-  # Print the main tag
-  if attr_count == 0:
-    print '%s<%s>' % (' '*indent, node.nodeName)
-  else:
-    print '%s<%s' % (' '*indent, node.nodeName)
-
-    all_attributes = []
-    for (name, value) in node.attributes.items():
-      all_attributes.append((name, value))
-      all_attributes.sort(CmpTuple())
-    for (name, value) in all_attributes:
-      print '%s  %s="%s"' % (' '*indent, name, value)
-    print '%s>' % (' '*indent)
-  if node.nodeValue:
-    print '%s  %s' % (' '*indent, node.nodeValue)
-
-  for sub_node in node.childNodes:
-    PrettyPrintNode(sub_node, indent=indent+2)
-  print '%s</%s>' % (' '*indent, node.nodeName)
-
-
-def FlattenFilter(node):
-  """Returns a list of all the node and sub nodes."""
-  node_list = []
-
-  if (node.attributes and
-      node.getAttribute('Name') == '_excluded_files'):
-      # We don't add the "_excluded_files" filter.
-    return []
-
-  for current in node.childNodes:
-    if current.nodeName == 'Filter':
-      node_list.extend(FlattenFilter(current))
-    else:
-      node_list.append(current)
-
-  return node_list
-
-
-def FixFilenames(filenames, current_directory):
-  new_list = []
-  for filename in filenames:
-    if filename:
-      for key in REPLACEMENTS:
-        filename = filename.replace(key, REPLACEMENTS[key])
-      os.chdir(current_directory)
-      filename = filename.strip('"\' ')
-      if filename.startswith('$'):
-        new_list.append(filename)
-      else:
-        new_list.append(os.path.abspath(filename))
-  return new_list
-
-
-def AbsoluteNode(node):
-  """Makes all the properties we know about in this node absolute."""
-  if node.attributes:
-    for (name, value) in node.attributes.items():
-      if name in ['InheritedPropertySheets', 'RelativePath',
-                  'AdditionalIncludeDirectories',
-                  'IntermediateDirectory', 'OutputDirectory',
-                  'AdditionalLibraryDirectories']:
-        # We want to fix up these paths
-        path_list = value.split(';')
-        new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
-        node.setAttribute(name, ';'.join(new_list))
-      if not value:
-        node.removeAttribute(name)
-
-
-def CleanupVcproj(node):
-  """For each sub node, we call recursively this function."""
-  for sub_node in node.childNodes:
-    AbsoluteNode(sub_node)
-    CleanupVcproj(sub_node)
-
-  # Normalize the node, and remove all extranous whitespaces.
-  for sub_node in node.childNodes:
-    if sub_node.nodeType == Node.TEXT_NODE:
-      sub_node.data = sub_node.data.replace("\r", "")
-      sub_node.data = sub_node.data.replace("\n", "")
-      sub_node.data = sub_node.data.rstrip()
-
-  # Fix all the semicolon separated attributes to be sorted, and we also
-  # remove the dups.
-  if node.attributes:
-    for (name, value) in node.attributes.items():
-      sorted_list = sorted(value.split(';'))
-      unique_list = []
-      for i in sorted_list:
-        if not unique_list.count(i):
-          unique_list.append(i)
-      node.setAttribute(name, ';'.join(unique_list))
-      if not value:
-        node.removeAttribute(name)
-
-  if node.childNodes:
-    node.normalize()
-
-  # For each node, take a copy, and remove it from the list.
-  node_array = []
-  while node.childNodes and node.childNodes[0]:
-    # Take a copy of the node and remove it from the list.
-    current = node.childNodes[0]
-    node.removeChild(current)
-
-    # If the child is a filter, we want to append all its children
-    # to this same list.
-    if current.nodeName == 'Filter':
-      node_array.extend(FlattenFilter(current))
-    else:
-      node_array.append(current)
-
-
-  # Sort the list.
-  node_array.sort(CmpNode())
-
-  # Insert the nodes in the correct order.
-  for new_node in node_array:
-    # But don't append empty tool node.
-    if new_node.nodeName == 'Tool':
-      if new_node.attributes and new_node.attributes.length == 1:
-        # This one was empty.
-        continue
-    if new_node.nodeName == 'UserMacro':
-      continue
-    node.appendChild(new_node)
-
-
-def GetConfiguationNodes(vcproj):
-  #TODO(nsylvain): Find a better way to navigate the xml.
-  nodes = []
-  for node in vcproj.childNodes:
-    if node.nodeName == "Configurations":
-      for sub_node in node.childNodes:
-        if sub_node.nodeName == "Configuration":
-          nodes.append(sub_node)
-
-  return nodes
-
-
-def GetChildrenVsprops(filename):
-  dom = parse(filename)
-  if dom.documentElement.attributes:
-    vsprops = dom.documentElement.getAttribute('InheritedPropertySheets')
-    return FixFilenames(vsprops.split(';'), os.path.dirname(filename))
-  return []
-
-def SeekToNode(node1, child2):
-  # A text node does not have properties.
-  if child2.nodeType == Node.TEXT_NODE:
-    return None
-
-  # Get the name of the current node.
-  current_name = child2.getAttribute("Name")
-  if not current_name:
-    # There is no name. We don't know how to merge.
-    return None
-
-  # Look through all the nodes to find a match.
-  for sub_node in node1.childNodes:
-    if sub_node.nodeName == child2.nodeName:
-      name = sub_node.getAttribute("Name")
-      if name == current_name:
-        return sub_node
-
-  # No match. We give up.
-  return None
-
-
-def MergeAttributes(node1, node2):
-  # No attributes to merge?
-  if not node2.attributes:
-    return
-
-  for (name, value2) in node2.attributes.items():
-    # Don't merge the 'Name' attribute.
-    if name == 'Name':
-      continue
-    value1 = node1.getAttribute(name)
-    if value1:
-      # The attribute exist in the main node. If it's equal, we leave it
-      # untouched, otherwise we concatenate it.
-      if value1 != value2:
-        node1.setAttribute(name, ';'.join([value1, value2]))
-    else:
-      # The attribute does nto exist in the main node. We append this one.
-      node1.setAttribute(name, value2)
-
-    # If the attribute was a property sheet attributes, we remove it, since
-    # they are useless.
-    if name == 'InheritedPropertySheets':
-      node1.removeAttribute(name)
-
-
-def MergeProperties(node1, node2):
-  MergeAttributes(node1, node2)
-  for child2 in node2.childNodes:
-    child1 = SeekToNode(node1, child2)
-    if child1:
-      MergeProperties(child1, child2)
-    else:
-      node1.appendChild(child2.cloneNode(True))
-
-
-def main(argv):
-  """Main function of this vcproj prettifier."""
-  global ARGUMENTS
-  ARGUMENTS = argv
-
-  # check if we have exactly 1 parameter.
-  if len(argv) < 2:
-    print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
-           '[key2=value2]' % argv[0])
-    return 1
-
-  # Parse the keys
-  for i in range(2, len(argv)):
-    (key, value) = argv[i].split('=')
-    REPLACEMENTS[key] = value
-
-  # Open the vcproj and parse the xml.
-  dom = parse(argv[1])
-
-  # First thing we need to do is find the Configuration Node and merge them
-  # with the vsprops they include.
-  for configuration_node in GetConfiguationNodes(dom.documentElement):
-    # Get the property sheets associated with this configuration.
-    vsprops = configuration_node.getAttribute('InheritedPropertySheets')
-
-    # Fix the filenames to be absolute.
-    vsprops_list = FixFilenames(vsprops.strip().split(';'),
-                                os.path.dirname(argv[1]))
-
-    # Extend the list of vsprops with all vsprops contained in the current
-    # vsprops.
-    for current_vsprops in vsprops_list:
-      vsprops_list.extend(GetChildrenVsprops(current_vsprops))
-
-    # Now that we have all the vsprops, we need to merge them.
-    for current_vsprops in vsprops_list:
-      MergeProperties(configuration_node,
-                      parse(current_vsprops).documentElement)
-
-  # Now that everything is merged, we need to cleanup the xml.
-  CleanupVcproj(dom.documentElement)
-
-  # Finally, we use the prett xml function to print the vcproj back to the
-  # user.
-  #print dom.toprettyxml(newl="\n")
-  PrettyPrintNode(dom.documentElement)
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main(sys.argv))
diff --git a/lib/Find-VS2017.cs b/lib/Find-VS2017.cs
index 87e0a9c9bb..6e7429b771 100644
--- a/lib/Find-VS2017.cs
+++ b/lib/Find-VS2017.cs
@@ -232,7 +232,9 @@ private static bool CheckInstance(ISetupInstance2 setupInstance2, ref StringBuil
                     string[] parts = id.Substring(Win10SDKPrefix.Length).Split('.');
                     if (parts.Length > 1 && parts[1] != "Desktop")
                         continue;
-                    Win10SDKVer = Math.Max(Win10SDKVer, UInt32.Parse(parts[0]));
+                    uint foundSdkVer;
+                    if (UInt32.TryParse(parts[0], out foundSdkVer))
+                        Win10SDKVer = Math.Max(Win10SDKVer, foundSdkVer);
                 } else if (id == "Microsoft.VisualStudio.Component.Windows81SDK")
                     hasWin8SDK = true;
                 else
diff --git a/lib/build.js b/lib/build.js
index 0445fb6452..b8389bcd7b 100644
--- a/lib/build.js
+++ b/lib/build.js
@@ -1,18 +1,12 @@
 
 module.exports = exports = build
 
-/**
- * Module dependencies.
- */
-
 var fs = require('graceful-fs')
-  , rm = require('rimraf')
   , path = require('path')
   , glob = require('glob')
   , log = require('npmlog')
   , which = require('which')
   , exec = require('child_process').exec
-  , processRelease = require('./process-release')
   , win = process.platform === 'win32'
 
 exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
@@ -23,13 +17,14 @@ function build (gyp, argv, callback) {
     platformMake = 'gmake'
   } else if (process.platform.indexOf('bsd') !== -1) {
     platformMake = 'gmake'
+  } else if (win && argv.length > 0) {
+    argv = argv.map(function(target) {
+      return '/t:' + target
+    })
   }
 
-  var release = processRelease(argv, gyp, process.version, process.release)
-    , makeCommand = gyp.opts.make || process.env.MAKE || platformMake
+  var makeCommand = gyp.opts.make || process.env.MAKE || platformMake
     , command = win ? 'msbuild' : makeCommand
-    , buildDir = path.resolve('build')
-    , configPath = path.resolve(buildDir, 'config.gypi')
     , jobs = gyp.opts.jobs || process.env.JOBS
     , buildType
     , config
@@ -43,6 +38,7 @@ function build (gyp, argv, callback) {
    */
 
   function loadConfigGypi () {
+    var configPath = path.resolve('build', 'config.gypi')
     fs.readFile(configPath, 'utf8', function (err, data) {
       if (err) {
         if (err.code == 'ENOENT') {
@@ -133,7 +129,7 @@ function build (gyp, argv, callback) {
     var cmd = 'reg query "HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions" /s'
     if (process.arch !== 'ia32')
       cmd += ' /reg:32'
-    exec(cmd, function (err, stdout, stderr) {
+    exec(cmd, function (err, stdout) {
       if (err) {
         return callback(new Error(err.message + '\n' + notfoundErr))
       }
@@ -163,7 +159,7 @@ function build (gyp, argv, callback) {
       ;(function verifyMsbuild () {
         if (!msbuilds.length) return callback(new Error(notfoundErr))
         msbuildPath = path.resolve(msbuilds.pop().path, 'msbuild.exe')
-        fs.stat(msbuildPath, function (err, stat) {
+        fs.stat(msbuildPath, function (err) {
           if (err) {
             if (err.code == 'ENOENT') {
               if (msbuilds.length) {
@@ -183,13 +179,11 @@ function build (gyp, argv, callback) {
     })
   }
 
-
   /**
    * Actually spawn the process and compile the module.
    */
 
   function doBuild () {
-
     // Enable Verbose build
     var verbose = log.levels[log.level] <= log.levels.verbose
     if (!win && verbose) {
@@ -249,10 +243,6 @@ function build (gyp, argv, callback) {
     proc.on('exit', onExit)
   }
 
-  /**
-   * Invoked after the make/msbuild command exits.
-   */
-
   function onExit (code, signal) {
     if (code !== 0) {
       return callback(new Error('`' + command + '` failed with exit code: ' + code))
@@ -262,5 +252,4 @@ function build (gyp, argv, callback) {
     }
     callback()
   }
-
 }
diff --git a/lib/clean.js b/lib/clean.js
index e69164d45a..8172e1c3d3 100644
--- a/lib/clean.js
+++ b/lib/clean.js
@@ -3,20 +3,13 @@ module.exports = exports = clean
 
 exports.usage = 'Removes any generated build files and the "out" dir'
 
-/**
- * Module dependencies.
- */
-
 var rm = require('rimraf')
 var log = require('npmlog')
 
-
 function clean (gyp, argv, callback) {
-
   // Remove the 'build' dir
   var buildDir = 'build'
 
   log.verbose('clean', 'removing "%s" directory', buildDir)
   rm(buildDir, callback)
-
 }
diff --git a/lib/configure.js b/lib/configure.js
index 1351576d12..32d77523ca 100644
--- a/lib/configure.js
+++ b/lib/configure.js
@@ -5,15 +5,10 @@ module.exports.test = {
   findPython: findPython,
 }
 
-/**
- * Module dependencies.
- */
-
 var fs = require('graceful-fs')
   , path = require('path')
   , log = require('npmlog')
-  , osenv = require('osenv')
-  , which = require('which')
+  , os = require('os')
   , semver = require('semver')
   , mkdirp = require('mkdirp')
   , cp = require('child_process')
@@ -28,15 +23,14 @@ if (win)
 exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
 
 function configure (gyp, argv, callback) {
-
-  var python = gyp.opts.python || process.env.PYTHON || 'python2'
+  var python
     , buildDir = path.resolve('build')
     , configNames = [ 'config.gypi', 'common.gypi' ]
     , configs = []
     , nodeDir
     , release = processRelease(argv, gyp, process.version, process.release)
 
-  findPython(python, function (err, found) {
+  findPython(gyp.opts.python, function (err, found) {
     if (err) {
       callback(err)
     } else {
@@ -46,17 +40,15 @@ function configure (gyp, argv, callback) {
   })
 
   function getNodeDir () {
-
     // 'python' should be set by now
     process.env.PYTHON = python
 
     if (gyp.opts.nodedir) {
       // --nodedir was specified. use that for the dev files
-      nodeDir = gyp.opts.nodedir.replace(/^~/, osenv.home())
+      nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir())
 
       log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir)
       createBuildDir()
-
     } else {
       // if no --nodedir specified, ensure node dependencies are installed
       if ('v' + release.version !== process.version) {
@@ -72,9 +64,11 @@ function configure (gyp, argv, callback) {
         return callback(new Error('Invalid version number: ' + release.version))
       }
 
-      // ensure that the target node version's dev files are installed
-      gyp.opts.ensure = true
-      gyp.commands.install([ release.version ], function (err, version) {
+      // If the tarball option is set, always remove and reinstall the headers
+      // into devdir. Otherwise only install if they're not already there.
+      gyp.opts.ensure = gyp.opts.tarball ? false : true
+
+      gyp.commands.install([ release.version ], function (err) {
         if (err) return callback(err)
         log.verbose('get node dir', 'target node version installed:', release.versionDir)
         nodeDir = path.resolve(gyp.devDir, release.versionDir)
@@ -193,7 +187,7 @@ function configure (gyp, argv, callback) {
     if (!name) return runGyp()
     var fullPath = path.resolve(name)
     log.verbose(name, 'checking for gypi file: %s', fullPath)
-    fs.stat(fullPath, function (err, stat) {
+    fs.stat(fullPath, function (err) {
       if (err) {
         if (err.code == 'ENOENT') {
           findConfigs() // check next gypi filename
@@ -242,28 +236,35 @@ function configure (gyp, argv, callback) {
       argv.push('-I', config)
     })
 
-    // for AIX we need to set up the path to the exp file
+    // For AIX and z/OS we need to set up the path to the exports file
     // which contains the symbols needed for linking.
-    // The file will either be in one of the following
-    // depending on whether it is an installed or
-    // development environment:
-    //  - the include/node directory
-    //  - the out/Release directory
-    //  - the out/Debug directory
-    //  - the root directory
     var node_exp_file = undefined
-    if (process.platform === 'aix') {
+    if (process.platform === 'aix' || process.platform === 'os390') {
+      var ext = process.platform === 'aix' ? 'exp' : 'x'
       var node_root_dir = findNodeDirectory()
-      var candidates = ['include/node/node.exp',
-                        'out/Release/node.exp',
-                        'out/Debug/node.exp',
-                        'node.exp']
+      var candidates = undefined
+      if (process.platform === 'aix') {
+        candidates = ['include/node/node',
+                      'out/Release/node',
+                      'out/Debug/node',
+                      'node'
+                     ].map(function(file) {
+                       return file + '.' + ext
+                     })
+      } else {
+        candidates = ['out/Release/obj.target/libnode',
+                      'out/Debug/obj.target/libnode',
+                      'lib/libnode'
+                     ].map(function(file) {
+                       return file + '.' + ext
+                     })
+      }
       var logprefix = 'find exports file'
       node_exp_file = findAccessibleSync(logprefix, node_root_dir, candidates)
       if (node_exp_file !== undefined) {
         log.verbose(logprefix, 'Found exports file: %s', node_exp_file)
       } else {
-        var msg = msgFormat('Could not find node.exp file in %s', node_root_dir)
+        var msg = msgFormat('Could not find node.%s file in %s', ext, node_root_dir)
         log.error(logprefix, 'Could not find exports file')
         return callback(new Error(msg))
       }
@@ -273,7 +274,7 @@ function configure (gyp, argv, callback) {
     var gyp_script = path.resolve(__dirname, '..', 'gyp', 'gyp_main.py')
     var addon_gypi = path.resolve(__dirname, '..', 'addon.gypi')
     var common_gypi = path.resolve(nodeDir, 'include/node/common.gypi')
-    fs.stat(common_gypi, function (err, stat) {
+    fs.stat(common_gypi, function (err) {
       if (err)
         common_gypi = path.resolve(nodeDir, 'common.gypi')
 
@@ -292,7 +293,7 @@ function configure (gyp, argv, callback) {
       argv.push('-Dlibrary=shared_library')
       argv.push('-Dvisibility=default')
       argv.push('-Dnode_root_dir=' + nodeDir)
-      if (process.platform === 'aix') {
+      if (process.platform === 'aix' || process.platform === 'os390') {
         argv.push('-Dnode_exp_file=' + node_exp_file)
       }
       argv.push('-Dnode_gyp_dir=' + nodeGypDir)
@@ -327,11 +328,7 @@ function configure (gyp, argv, callback) {
     })
   }
 
-  /**
-   * Called when the `gyp` child process exits.
-   */
-
-  function onCpExit (code, signal) {
+  function onCpExit (code) {
     if (code !== 0) {
       callback(new Error('`gyp` failed with exit code: ' + code))
     } else {
@@ -365,48 +362,156 @@ function findAccessibleSync (logprefix, dir, candidates) {
   return undefined
 }
 
-function PythonFinder(python, callback) {
+function PythonFinder(configPython, callback) {
   this.callback = callback
-  this.python = python
+  this.configPython = configPython
+  this.errorLog = []
 }
 
 PythonFinder.prototype = {
-  checkPythonLauncherDepth: 0,
-  env: process.env,
+  log: logWithPrefix(log, 'find Python'),
+  argsExecutable: ['-c', 'import sys; print(sys.executable);'],
+  argsVersion: ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);'],
+  semverRange: '>=2.6.0 <3.0.0',
+
+  // These can be overridden for testing:
   execFile: cp.execFile,
-  log: log,
-  resolve: path.win32 && path.win32.resolve || path.resolve,
-  stat: fs.stat,
-  which: which,
+  env: process.env,
   win: win,
+  pyLauncher: 'py.exe',
+  defaultLocation: path.join(process.env.SystemDrive || 'C:', 'Python27',
+                             'python.exe'),
+
+  // Logs a message at verbose level, but also saves it to be displayed later
+  // at error level if an error occurs. This should help diagnose the problem.
+  addLog: function addLog(message) {
+    this.log.verbose(message)
+    this.errorLog.push(message)
+  },
 
-  checkPython: function checkPython () {
-    this.log.verbose('check python',
-                     'checking for Python executable "%s" in the PATH',
-                     this.python)
-    this.which(this.python, function (err, execPath) {
+
+  // Find Python by trying a sequence of possibilities.
+  // Ignore errors, keep trying until Python is found.
+  findPython: function findPython() {
+    const SKIP=0, FAIL=1
+    const toCheck = [
+      {
+        before: () => {
+          if (!this.configPython) {
+            this.addLog(
+              'Python is not set from command line or npm configuration')
+            return SKIP
+          }
+          this.addLog('checking Python explicitly set from command line or ' +
+            'npm configuration')
+          this.addLog('- "--python=" or "npm config get python" is ' +
+            `"${this.configPython}"`)
+        },
+        check: this.checkCommand,
+        arg: this.configPython,
+      },
+      {
+        before: () => {
+          if (!this.env.PYTHON) {
+            this.addLog('Python is not set from environment variable PYTHON')
+            return SKIP
+          }
+          this.addLog(
+            'checking Python explicitly set from environment variable PYTHON')
+          this.addLog(`- process.env.PYTHON is "${this.env.PYTHON}"`)
+        },
+        check: this.checkCommand,
+        arg: this.env.PYTHON,
+      },
+      {
+        before: () => { this.addLog('checking if "python2" can be used') },
+        check: this.checkCommand,
+        arg: 'python2',
+      },
+      {
+        before: () => { this.addLog('checking if "python" can be used') },
+        check: this.checkCommand,
+        arg: 'python',
+      },
+      {
+        before: () => {
+          if (!this.win) {
+            // Everything after this is Windows specific
+            return FAIL
+          }
+          this.addLog(
+            'checking if the py launcher can be used to find Python 2')
+        },
+        check: this.checkPyLauncher,
+      },
+      {
+        before: () => {
+          this.addLog(
+            'checking if Python 2 is installed in the default location')
+        },
+        check: this.checkExecPath,
+        arg: this.defaultLocation,
+      },
+    ]
+
+    function runChecks(err) {
+      this.log.silly('runChecks: err = %j', err && err.stack || err)
+
+      const check = toCheck.shift()
+      if (!check) {
+        return this.fail()
+      }
+
+      const before = check.before.apply(this)
+      if (before === SKIP) {
+        return runChecks.apply(this)
+      }
+      if (before === FAIL) {
+        return this.fail()
+      }
+
+      const args = [ runChecks.bind(this) ]
+      if (check.arg) {
+        args.unshift(check.arg)
+      }
+      check.check.apply(this, args)
+    }
+
+    runChecks.apply(this)
+  },
+
+
+  // Check if command is a valid Python to use.
+  // Will exit the Python finder on success.
+  // If on Windows, run in a CMD shell to support BAT/CMD launchers.
+  checkCommand: function checkCommand (command, errorCallback) {
+    var exec = command
+    var args = this.argsExecutable
+    var shell = false
+    if (this.win) {
+      // Arguments have to be manually quoted
+      exec = `"${exec}"`
+      args = args.map(a => `"${a}"`)
+      shell = true
+    }
+
+    this.log.verbose(`- executing "${command}" to get executable path`)
+    this.run(exec, args, shell, function (err, execPath) {
+      // Possible outcomes:
+      // - Error: not in PATH, not executable or execution fails
+      // - Gibberish: the next command to check version will fail
+      // - Absolute path to executable
       if (err) {
-        this.log.verbose('`which` failed', this.python, err)
-        if (this.python === 'python2') {
-          this.python = 'python'
-          return this.checkPython()
-        }
-        if (this.win) {
-          this.checkPythonLauncher()
-        } else {
-          this.failNoPython()
-        }
-      } else {
-        this.log.verbose('`which` succeeded', this.python, execPath)
-        // Found the `python` executable, and from now on we use it explicitly.
-        // This solves #667 and #750 (`execFile` won't run batch files
-        // (*.cmd, and *.bat))
-        this.python = execPath
-        this.checkPythonVersion()
+        this.addLog(`- "${command}" is not in PATH or produced an error`)
+        return errorCallback(err)
       }
+      this.addLog(`- executable path is "${execPath}"`)
+      this.checkExecPath(execPath, errorCallback)
     }.bind(this))
   },
 
+  // Check if the py launcher can find a valid Python to use.
+  // Will exit the Python finder on success.
   // Distributions of Python on Windows by default install with the "py.exe"
   // Python launcher which is more likely to exist than the Python executable
   // being in the $PATH.
@@ -415,109 +520,137 @@ PythonFinder.prototype = {
   // the first command line argument. Since "py.exe -2" would be an invalid
   // executable for "execFile", we have to use the launcher to figure out
   // where the actual "python.exe" executable is located.
-  checkPythonLauncher: function checkPythonLauncher () {
-    this.checkPythonLauncherDepth += 1
-
+  checkPyLauncher: function checkPyLauncher (errorCallback) {
     this.log.verbose(
-        'could not find "' + this.python + '". checking python launcher')
-    var env = extend({}, this.env)
-    env.TERM = 'dumb'
-
-    var launcherArgs = ['-2', '-c', 'import sys; print sys.executable']
-    this.execFile('py.exe', launcherArgs, { env: env }, function (err, stdout) {
+      `- executing "${this.pyLauncher}" to get Python 2 executable path`)
+    this.run(this.pyLauncher, ['-2', ...this.argsExecutable], false,
+             function (err, execPath) {
+      // Possible outcomes: same as checkCommand
       if (err) {
-        this.guessPython()
-      } else {
-        this.python = stdout.trim()
-        this.log.verbose('check python launcher',
-                         'python executable found: %j',
-                         this.python)
-        this.checkPythonVersion()
+        this.addLog(
+          `- "${this.pyLauncher}" is not in PATH or produced an error`)
+        return errorCallback(err)
       }
-      this.checkPythonLauncherDepth -= 1
+      this.addLog(`- executable path is "${execPath}"`)
+      this.checkExecPath(execPath, errorCallback)
     }.bind(this))
   },
 
-  checkPythonVersion: function checkPythonVersion () {
-    var args = ['-c', 'import platform; print(platform.python_version());']
-    var env = extend({}, this.env)
-    env.TERM = 'dumb'
-
-    this.execFile(this.python, args, { env: env }, function (err, stdout) {
+  // Check if a Python executable is the correct version to use.
+  // Will exit the Python finder on success.
+  checkExecPath: function checkExecPath (execPath, errorCallback) {
+    this.log.verbose(`- executing "${execPath}" to get version`)
+    this.run(execPath, this.argsVersion, false, function (err, version) {
+      // Possible outcomes:
+      // - Error: executable can not be run (likely meaning the command wasn't
+      //   a Python executable and the previous command produced gibberish)
+      // - Gibberish: somehow the last command produced an executable path,
+      //   this will fail when verifying the version
+      // - Version of the Python executable
       if (err) {
-        return this.callback(err)
-      }
-      this.log.verbose('check python version',
-                       '`%s -c "' + args[1] + '"` returned: %j',
-                       this.python, stdout)
-      var version = stdout.trim()
-      if (~version.indexOf('+')) {
-        this.log.silly('stripping "+" sign(s) from version')
-        version = version.replace(/\+/g, '')
+        this.addLog(`- "${execPath}" could not be run`)
+        return errorCallback(err)
       }
-      if (~version.indexOf('rc')) {
-        this.log.silly('stripping "rc" identifier from version')
-        version = version.replace(/rc(.*)$/ig, '')
-      }
-      var range = semver.Range('>=2.5.0 <3.0.0')
+      this.addLog(`- version is "${version}"`)
+
+      const range = semver.Range(this.semverRange)
       var valid = false
       try {
         valid = range.test(version)
-      } catch (e) {
-        this.log.silly('range.test() error', e)
+      } catch (err) {
+        this.log.silly('range.test() threw:\n%s', err.stack)
+        this.addLog(`- "${execPath}" does not have a valid version`)
+        this.addLog('- is it a Python executable?')
+        return errorCallback(err)
       }
-      if (valid) {
-        this.callback(null, this.python)
-      } else if (this.win && this.checkPythonLauncherDepth === 0) {
-        this.checkPythonLauncher()
-      } else {
-        this.failPythonVersion(version)
+
+      if (!valid) {
+        this.addLog(`- version is ${version} - should be ${this.semverRange}`)
+        this.addLog('- THIS VERSION OF PYTHON IS NOT SUPPORTED')
+        return errorCallback(new Error(
+          `Found unsupported Python version ${version}`))
       }
+      this.succeed(execPath, version)
     }.bind(this))
   },
 
-  failNoPython: function failNoPython () {
-    var errmsg =
-        'Can\'t find Python executable "' + this.python +
-        '", you can set the PYTHON env variable.'
-    this.callback(new Error(errmsg))
+  // Run an executable or shell command, trimming the output.
+  run: function run(exec, args, shell, callback) {
+    var env = extend({}, this.env)
+    env.TERM = 'dumb'
+    const opts = { env: env, shell: shell }
+
+    this.log.silly('execFile: exec = %j', exec)
+    this.log.silly('execFile: args = %j', args)
+    this.log.silly('execFile: opts = %j', opts)
+    try {
+      this.execFile(exec, args, opts, execFileCallback.bind(this))
+    } catch (err) {
+      this.log.silly('execFile: threw:\n%s', err.stack)
+      return callback(err)
+    }
+
+    function execFileCallback(err, stdout, stderr) {
+      this.log.silly('execFile result: err = %j', err && err.stack || err)
+      this.log.silly('execFile result: stdout = %j', stdout)
+      this.log.silly('execFile result: stderr = %j', stderr)
+      if (err) {
+        return callback(err)
+      }
+      const execPath = stdout.trim()
+      callback(null, execPath)
+    }
   },
 
-  failPythonVersion: function failPythonVersion (badVersion) {
-    var errmsg =
-        'Python executable "' + this.python +
-        '" is v' + badVersion + ', which is not supported by gyp.\n' +
-        'You can pass the --python switch to point to ' +
-        'Python >= v2.5.0 & < 3.0.0.'
-    this.callback(new Error(errmsg))
+
+  succeed: function succeed(execPath, version) {
+    this.log.info(`using Python version ${version} found at "${execPath}"`)
+    process.nextTick(this.callback.bind(null, null, execPath))
   },
 
-  // Called on Windows when "python" isn't available in the current $PATH.
-  // We are going to check if "%SystemDrive%\python27\python.exe" exists.
-  guessPython: function guessPython () {
-    this.log.verbose('could not find "' + this.python + '". guessing location')
-    var rootDir = this.env.SystemDrive || 'C:\\'
-    if (rootDir[rootDir.length - 1] !== '\\') {
-      rootDir += '\\'
-    }
-    var pythonPath = this.resolve(rootDir, 'Python27', 'python.exe')
-    this.log.verbose('ensuring that file exists:', pythonPath)
-    this.stat(pythonPath, function (err, stat) {
-      if (err) {
-        if (err.code == 'ENOENT') {
-          this.failNoPython()
-        } else {
-          this.callback(err)
-        }
-        return
-      }
-      this.python = pythonPath
-      this.checkPythonVersion()
-    }.bind(this))
+  fail: function fail() {
+    const errorLog = this.errorLog.join('\n')
+
+    const pathExample = this.win ? 'C:\\Path\\To\\python.exe' :
+                                   '/path/to/pythonexecutable'
+    // For Windows 80 col console, use up to the column before the one marked
+    // with X (total 79 chars including logger prefix, 58 chars usable here):
+    //                                                           X
+    const info = [
+      '**********************************************************',
+      'You need to install the latest version of Python 2.7.',
+      'Node-gyp should be able to find and use Python. If not,',
+      'you can try one of the following options:',
+      `- Use the switch --python="${pathExample}"`,
+      '  (accepted by both node-gyp and npm)',
+      '- Set the environment variable PYTHON',
+      '- Set the npm configuration variable python:',
+      `  npm config set python "${pathExample}"`,
+      'For more information consult the documentation at:',
+      'https://github.com/nodejs/node-gyp#installation',
+      '**********************************************************',
+    ].join('\n')
+
+    this.log.error(`\n${errorLog}\n\n${info}\n`)
+    process.nextTick(this.callback.bind(null, new Error (
+      'Could not find any Python 2 installation to use')))
   },
 }
 
-function findPython (python, callback) {
-  var finder = new PythonFinder(python, callback)
-  finder.checkPython()
+function findPython (configPython, callback) {
+  var finder = new PythonFinder(configPython, callback)
+  finder.findPython()
+}
+
+function logWithPrefix (log, prefix) {
+  function setPrefix(logFunction) {
+    return (...args) => logFunction.apply(null, [prefix, ...args])
+  }
+  return {
+    silly: setPrefix(log.silly),
+    verbose: setPrefix(log.verbose),
+    info: setPrefix(log.info),
+    warn: setPrefix(log.warn),
+    error: setPrefix(log.error),
+  }
 }
diff --git a/lib/find-node-directory.js b/lib/find-node-directory.js
index 3aee8a109a..524909581f 100644
--- a/lib/find-node-directory.js
+++ b/lib/find-node-directory.js
@@ -1,7 +1,7 @@
 var path = require('path')
   , log = require('npmlog')
 
-function findNodeDirectory(scriptLocation, processObj) {
+module.exports = function findNodeDirectory(scriptLocation, processObj) {
   // set dirname and process if not passed in
   // this facilitates regression tests
   if (scriptLocation === undefined) {
@@ -57,5 +57,3 @@ function findNodeDirectory(scriptLocation, processObj) {
   }
   return node_root_dir
 }
-
-module.exports = findNodeDirectory
diff --git a/lib/find-vs2017.js b/lib/find-vs2017.js
index 8c79e9ec9b..8655d7c931 100644
--- a/lib/find-vs2017.js
+++ b/lib/find-vs2017.js
@@ -2,13 +2,13 @@ var log = require('npmlog')
   , execFile = require('child_process').execFile
   , path = require('path')
 
-function findVS2017(callback) {
+module.exports = function findVS2017(callback) {
   var ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell',
                      'v1.0', 'powershell.exe')
   var csFile = path.join(__dirname, 'Find-VS2017.cs')
-  var psArgs = ['-ExecutionPolicy', 'Unrestricted', '-Command',
-                '&{Add-Type -Path \'' + csFile +
-                '\'; [VisualStudioConfiguration.Main]::Query()}']
+  var psArgs = ['-ExecutionPolicy', 'Unrestricted', '-NoProfile',
+                '-Command', '&{Add-Type -Path \'' + csFile + '\';' +
+                '[VisualStudioConfiguration.Main]::Query()}']
 
   log.silly('find vs2017', 'Running', ps, psArgs)
   var child = execFile(ps, psArgs, { encoding: 'utf8' },
@@ -42,5 +42,3 @@ function findVS2017(callback) {
 
   child.stdin.end()
 }
-
-module.exports = findVS2017
diff --git a/lib/install.js b/lib/install.js
index fa2e1c5430..735c31c0d0 100644
--- a/lib/install.js
+++ b/lib/install.js
@@ -1,32 +1,28 @@
+module.exports = exports = function (gyp, argv, callback) {
+  return install(fs, gyp, argv, callback)
+}
 
-module.exports = exports = install
-
-module.exports.test = { download: download, readCAFile: readCAFile }
+module.exports.test = {
+  download: download,
+  install: install,
+  readCAFile: readCAFile,
+}
 
 exports.usage = 'Install node development files for the specified node version.'
 
-/**
- * Module dependencies.
- */
-
 var fs = require('graceful-fs')
-  , osenv = require('osenv')
+  , os = require('os')
   , tar = require('tar')
-  , rm = require('rimraf')
   , path = require('path')
   , crypto = require('crypto')
-  , zlib = require('zlib')
   , log = require('npmlog')
   , semver = require('semver')
-  , fstream = require('fstream')
   , request = require('request')
-  , minimatch = require('minimatch')
   , mkdir = require('mkdirp')
   , processRelease = require('./process-release')
   , win = process.platform == 'win32'
 
-function install (gyp, argv, callback) {
-
+function install (fs, gyp, argv, callback) {
   var release = processRelease(argv, gyp, process.version, process.release)
 
   // ensure no double-callbacks happen
@@ -36,7 +32,7 @@ function install (gyp, argv, callback) {
     if (err) {
       log.warn('install', 'got an error, rolling back install')
       // roll-back the install if anything went wrong
-      gyp.commands.remove([ release.versionDir ], function (err2) {
+      gyp.commands.remove([ release.versionDir ], function () {
         callback(err)
       })
     } else {
@@ -78,13 +74,13 @@ function install (gyp, argv, callback) {
   // check if it is already installed, and only install when needed
   if (gyp.opts.ensure) {
     log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
-    fs.stat(devDir, function (err, stat) {
+    fs.stat(devDir, function (err) {
       if (err) {
         if (err.code == 'ENOENT') {
           log.verbose('install', 'version not already installed, continuing with install', release.version)
           go()
         } else if (err.code == 'EACCES') {
-          eaccesFallback()
+          eaccesFallback(err)
         } else {
           cb(err)
         }
@@ -122,14 +118,13 @@ function install (gyp, argv, callback) {
   }
 
   function go () {
-
     log.verbose('ensuring nodedir is created', devDir)
 
     // first create the dir for the node dev files
     mkdir(devDir, function (err, created) {
       if (err) {
         if (err.code == 'EACCES') {
-          eaccesFallback()
+          eaccesFallback(err)
         } else {
           cb(err)
         }
@@ -144,41 +139,32 @@ function install (gyp, argv, callback) {
       var tarPath = gyp.opts.tarball
       var badDownload = false
         , extractCount = 0
-        , gunzip = zlib.createGunzip()
-        , extracter = tar.Extract({ path: devDir, strip: 1, filter: isValid })
 
       var contentShasums = {}
       var expectShasums = {}
 
       // checks if a file to be extracted from the tarball is valid.
       // only .h header files and the gyp files get extracted
-      function isValid () {
-        var name = this.path.substring(devDir.length + 1)
-        var isValid = valid(name)
-        if (name === '' && this.type === 'Directory') {
-          // the first directory entry is ok
-          return true
-        }
+      function isValid (path) {
+        var isValid = valid(path)
         if (isValid) {
-          log.verbose('extracted file from tarball', name)
+          log.verbose('extracted file from tarball', path)
           extractCount++
         } else {
           // invalid
-          log.silly('ignoring from tarball', name)
+          log.silly('ignoring from tarball', path)
         }
         return isValid
       }
 
-      gunzip.on('error', cb)
-      extracter.on('error', cb)
-      extracter.on('end', afterTarball)
-
-      // download the tarball, gunzip and extract!
-
+      // download the tarball and extract!
       if (tarPath) {
-        var input = fs.createReadStream(tarPath)
-        input.pipe(gunzip).pipe(extracter)
-        return
+        return tar.extract({
+          file: tarPath,
+          strip: 1,
+          filter: isValid,
+          cwd: devDir
+        }).then(afterTarball, cb)
       }
 
       try {
@@ -218,7 +204,11 @@ function install (gyp, argv, callback) {
         })
 
         // start unzipping and untaring
-        req.pipe(gunzip).pipe(extracter)
+        res.pipe(tar.extract({
+          strip: 1,
+          cwd: devDir,
+          filter: isValid
+        }).on('close', afterTarball).on('error', cb))
       })
 
       // invoked after the tarball has finished being extracted
@@ -274,8 +264,6 @@ function install (gyp, argv, callback) {
 
       function downloadShasums(done) {
         log.verbose('check download content checksum, need to download `SHASUMS256.txt`...')
-        var shasumsPath = path.resolve(devDir, 'SHASUMS256.txt')
-
         log.verbose('checksum url', release.shasumsUrl)
         try {
           var req = download(gyp, process.env, release.shasumsUrl)
@@ -396,8 +384,8 @@ function install (gyp, argv, callback) {
 
   function valid (file) {
     // header files
-    return minimatch(file, '*.h', { matchBase: true }) ||
-           minimatch(file, '*.gypi', { matchBase: true })
+    var extname = path.extname(file);
+    return extname === '.h' || extname === '.gypi';
   }
 
   /**
@@ -409,16 +397,18 @@ function install (gyp, argv, callback) {
    * the compilation will succeed...
    */
 
-  function eaccesFallback () {
-    var tmpdir = osenv.tmpdir()
+  function eaccesFallback (err) {
+    var noretry = '--node_gyp_internal_noretry'
+    if (-1 !== argv.indexOf(noretry)) return cb(err)
+    var tmpdir = os.tmpdir()
     gyp.devDir = path.resolve(tmpdir, '.node-gyp')
-    log.warn('EACCES', 'user "%s" does not have permission to access the dev dir "%s"', osenv.user(), devDir)
+    log.warn('EACCES', 'user "%s" does not have permission to access the dev dir "%s"', os.userInfo().username, devDir)
     log.warn('EACCES', 'attempting to reinstall using temporary dev dir "%s"', gyp.devDir)
     if (process.cwd() == tmpdir) {
       log.verbose('tmpdir == cwd', 'automatically will remove dev files after to save disk space')
       gyp.todo.push({ name: 'remove', args: argv })
     }
-    gyp.commands.install(argv, cb)
+    gyp.commands.install([noretry].concat(argv), cb)
   }
 
 }
diff --git a/lib/list.js b/lib/list.js
index 9d680a56a4..90f6447180 100644
--- a/lib/list.js
+++ b/lib/list.js
@@ -3,20 +3,13 @@ module.exports = exports = list
 
 exports.usage = 'Prints a listing of the currently installed node development files'
 
-/**
- * Module dependencies.
- */
-
 var fs = require('graceful-fs')
-  , path = require('path')
   , log = require('npmlog')
 
 function list (gyp, args, callback) {
-
   var devDir = gyp.devDir
   log.verbose('list', 'using node-gyp dir:', devDir)
 
-  // readdir() the node-gyp dir
   fs.readdir(devDir, onreaddir)
 
   function onreaddir (err, versions) {
diff --git a/lib/node-gyp.js b/lib/node-gyp.js
index a841161e32..8dd551bf3d 100644
--- a/lib/node-gyp.js
+++ b/lib/node-gyp.js
@@ -1,16 +1,7 @@
 
-/**
- * Module exports.
- */
-
 module.exports = exports = gyp
 
-/**
- * Module dependencies.
- */
-
-var fs = require('graceful-fs')
-  , path = require('path')
+var path = require('path')
   , nopt = require('nopt')
   , log = require('npmlog')
   , child_process = require('child_process')
@@ -35,10 +26,6 @@ var fs = require('graceful-fs')
 // differentiate node-gyp's logs from npm's
 log.heading = 'gyp'
 
-/**
- * The `gyp` function.
- */
-
 function gyp () {
   return new Gyp()
 }
@@ -213,4 +200,3 @@ Object.defineProperty(proto, 'version', {
     }
   , enumerable: true
 })
-
diff --git a/lib/process-release.js b/lib/process-release.js
index 0d177f1c93..4805fcc7d1 100644
--- a/lib/process-release.js
+++ b/lib/process-release.js
@@ -9,7 +9,7 @@ var semver = require('semver')
   , bitsreV3 = /\/win-(x86|ia32|x64)\// // io.js v3.x.x shipped with "ia32" but should
                                         // have been "x86"
 
-// Captures all the logic required to determine download URLs, local directory and 
+// Captures all the logic required to determine download URLs, local directory and
 // file names. Inputs come from command-line switches (--target, --dist-url),
 // `process.version` and `process.release` where it exists.
 function processRelease (argv, gyp, defaultVersion, defaultRelease) {
@@ -88,35 +88,22 @@ function processRelease (argv, gyp, defaultVersion, defaultRelease) {
     baseUrl = url.resolve(defaultRelease.headersUrl, './')
     libUrl32 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x86', versionSemver.major)
     libUrl64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x64', versionSemver.major)
-
-    return {
-      version: version,
-      semver: versionSemver,
-      name: name,
-      baseUrl: baseUrl,
-      tarballUrl: defaultRelease.headersUrl,
-      shasumsUrl: url.resolve(baseUrl, 'SHASUMS256.txt'),
-      versionDir: (name !== 'node' ? name + '-' : '') + version,
-      libUrl32: libUrl32,
-      libUrl64: libUrl64,
-      libPath32: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl32).path)),
-      libPath64: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl64).path))
-    }
+    tarballUrl = defaultRelease.headersUrl
+  } else {
+    // older versions without process.release are captured here and we have to make
+    // a lot of assumptions, additionally if you --target=x.y.z then we can't use the
+    // current process.release
+    baseUrl = distBaseUrl
+    libUrl32 = resolveLibUrl(name, baseUrl, 'x86', versionSemver.major)
+    libUrl64 = resolveLibUrl(name, baseUrl, 'x64', versionSemver.major)
+
+    // making the bold assumption that anything with a version number >3.0.0 will
+    // have a *-headers.tar.gz file in its dist location, even some frankenstein
+    // custom version
+    canGetHeaders = semver.satisfies(versionSemver, headersTarballRange)
+    tarballUrl = url.resolve(baseUrl, name + '-v' + version + (canGetHeaders ? '-headers' : '') + '.tar.gz')
   }
 
-  // older versions without process.release are captured here and we have to make
-  // a lot of assumptions, additionally if you --target=x.y.z then we can't use the
-  // current process.release
-
-  baseUrl = distBaseUrl
-  libUrl32 = resolveLibUrl(name, baseUrl, 'x86', versionSemver.major)
-  libUrl64 = resolveLibUrl(name, baseUrl, 'x64', versionSemver.major)
-  // making the bold assumption that anything with a version number >3.0.0 will
-  // have a *-headers.tar.gz file in its dist location, even some frankenstein
-  // custom version
-  canGetHeaders = semver.satisfies(versionSemver, headersTarballRange)
-  tarballUrl = url.resolve(baseUrl, name + '-v' + version + (canGetHeaders ? '-headers' : '') + '.tar.gz')
-
   return {
     version: version,
     semver: versionSemver,
diff --git a/lib/rebuild.js b/lib/rebuild.js
index 4c6f472aa7..dc8025a7b0 100644
--- a/lib/rebuild.js
+++ b/lib/rebuild.js
@@ -4,7 +4,6 @@ module.exports = exports = rebuild
 exports.usage = 'Runs "clean", "configure" and "build" all at once'
 
 function rebuild (gyp, argv, callback) {
-
   gyp.todo.push(
       { name: 'clean', args: [] }
     , { name: 'configure', args: argv }
diff --git a/lib/remove.js b/lib/remove.js
index eb80981b88..46a1a3d4c2 100644
--- a/lib/remove.js
+++ b/lib/remove.js
@@ -3,10 +3,6 @@ module.exports = exports = remove
 
 exports.usage = 'Removes the node development files for the specified version'
 
-/**
- * Module dependencies.
- */
-
 var fs = require('fs')
   , rm = require('rimraf')
   , path = require('path')
@@ -14,7 +10,6 @@ var fs = require('fs')
   , semver = require('semver')
 
 function remove (gyp, argv, callback) {
-
   var devDir = gyp.devDir
   log.verbose('remove', 'using node-gyp dir:', devDir)
 
@@ -36,7 +31,7 @@ function remove (gyp, argv, callback) {
   log.verbose('remove', 'removing development files for version:', version)
 
   // first check if its even installed
-  fs.stat(versionPath, function (err, stat) {
+  fs.stat(versionPath, function (err) {
     if (err) {
       if (err.code == 'ENOENT') {
         callback(null, 'version was already uninstalled: ' + version)
@@ -48,5 +43,4 @@ function remove (gyp, argv, callback) {
     // Go ahead and delete the dir
     rm(versionPath, callback)
   })
-
 }
diff --git a/package.json b/package.json
index a66a546889..883a774086 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
     "bindings",
     "gyp"
   ],
-  "version": "3.6.2",
+  "version": "4.0.0",
   "installVersion": 9,
   "author": "Nathan Rajlich <nathan@tootallnate.net> (http://tootallnate.net)",
   "repository": {
@@ -22,30 +22,31 @@
   "bin": "./bin/node-gyp.js",
   "main": "./lib/node-gyp.js",
   "dependencies": {
-    "fstream": "^1.0.0",
+    "env-paths": "^1.0.0",
     "glob": "^7.0.3",
     "graceful-fs": "^4.1.2",
-    "minimatch": "^3.0.2",
     "mkdirp": "^0.5.0",
     "nopt": "2 || 3",
     "npmlog": "0 || 1 || 2 || 3 || 4",
-    "osenv": "0",
-    "request": "2",
+    "request": "^2.87.0",
     "rimraf": "2",
     "semver": "~5.3.0",
-    "tar": "^2.0.0",
+    "tar": "^3.1.3",
     "which": "1"
   },
   "engines": {
-    "node": ">= 0.8.0"
+    "node": ">= 6.0.0"
   },
   "devDependencies": {
-    "tape": "~4.2.0",
+    "babel-eslint": "^8.2.5",
     "bindings": "~1.2.1",
+    "eslint": "^5.0.1",
     "nan": "^2.0.0",
-    "require-inject": "~1.3.0"
+    "require-inject": "~1.3.0",
+    "tape": "~4.2.0"
   },
   "scripts": {
-    "test": "tape test/test-*"
+    "lint": "eslint bin lib test",
+    "test": "npm run lint && tape test/test-*"
   }
 }
diff --git a/src/win_delay_load_hook.cc b/src/win_delay_load_hook.cc
index e75954b605..5e7f14b2b2 100644
--- a/src/win_delay_load_hook.cc
+++ b/src/win_delay_load_hook.cc
@@ -1,10 +1,10 @@
 /*
  * When this file is linked to a DLL, it sets up a delay-load hook that
- * intervenes when the DLL is trying to load 'node.exe' or 'iojs.exe'
- * dynamically. Instead of trying to locate the .exe file it'll just return
- * a handle to the process image.
+ * intervenes when the DLL is trying to load the host executable
+ * dynamically. Instead of trying to locate the .exe file it'll just
+ * return a handle to the process image.
  *
- * This allows compiled addons to work when node.exe or iojs.exe is renamed.
+ * This allows compiled addons to work when the host executable is renamed.
  */
 
 #ifdef _MSC_VER
@@ -23,8 +23,7 @@ static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {
   if (event != dliNotePreLoadLibrary)
     return NULL;
 
-  if (_stricmp(info->szDll, "iojs.exe") != 0 &&
-      _stricmp(info->szDll, "node.exe") != 0)
+  if (_stricmp(info->szDll, HOST_BINARY) != 0)
     return NULL;
 
   m = GetModuleHandle(NULL);
diff --git a/test/fixtures/test-charmap.py b/test/fixtures/test-charmap.py
new file mode 100644
index 0000000000..b752f0bbbf
--- /dev/null
+++ b/test/fixtures/test-charmap.py
@@ -0,0 +1,23 @@
+from __future__ import print_function
+import sys
+import locale
+
+reload(sys)
+
+def main():
+  encoding = locale.getdefaultlocale()[1]
+  if not encoding:
+    return False
+
+  sys.setdefaultencoding(encoding)
+  textmap = {
+    'cp936': u'\u4e2d\u6587',
+    'cp1252': u'Lat\u012Bna',
+    'cp932': u'\u306b\u307b\u3093\u3054'
+  }
+  if encoding in textmap:
+    print(textmap[encoding])
+  return True
+
+if __name__ == '__main__':
+  print(main())
diff --git a/test/process-exec-sync.js b/test/process-exec-sync.js
new file mode 100644
index 0000000000..13daf308a3
--- /dev/null
+++ b/test/process-exec-sync.js
@@ -0,0 +1,138 @@
+'use strict'
+
+var fs = require('graceful-fs')
+var child_process = require('child_process')
+
+if (!String.prototype.startsWith) {
+  String.prototype.startsWith = function(search, pos) {
+    return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search
+  }
+}
+
+function processExecSync(file, args, options) {
+  var child, error, timeout, tmpdir, command
+  command = makeCommand(file, args)
+
+  /*
+    this function emulates child_process.execSync for legacy node <= 0.10.x
+    derived from https://github.com/gvarsanyi/sync-exec/blob/master/js/sync-exec.js
+  */
+
+  options = options || {}
+  // init timeout
+  timeout = Date.now() + options.timeout
+  // init tmpdir
+  var os_temp_base = '/tmp'
+  var os = determine_os()
+  os_temp_base = '/tmp'
+
+  if (process.env.TMP) {
+    os_temp_base = process.env.TMP
+  }
+
+  if (os_temp_base[os_temp_base.length - 1] !== '/') {
+    os_temp_base += '/'
+  }
+
+  tmpdir = os_temp_base + 'processExecSync.' + Date.now() + Math.random()
+  fs.mkdirSync(tmpdir)
+
+  // init command
+  if (os === 'linux') {
+    command = '(' + command + ' > ' + tmpdir + '/stdout 2> ' + tmpdir +
+      '/stderr); echo $? > ' + tmpdir + '/status'
+  } else {
+    command = '(' + command + ' > ' + tmpdir + '/stdout 2> ' + tmpdir +
+      '/stderr) | echo %errorlevel% > ' + tmpdir + '/status | exit'
+  }
+
+  // init child
+  child = child_process.exec(command, options)
+
+  var maxTry = 100000 // increases the test time by 6 seconds on win-2016-node-0.10
+  var tryCount = 0
+  while (tryCount < maxTry) {
+    try {
+      var x = fs.readFileSync(tmpdir + '/status')
+      if (x.toString() === '0') {
+        break
+      }
+    } catch (ignore) {}
+    tryCount++
+    if (Date.now() > timeout) {
+      error = child
+      break
+    }
+  }
+
+  ['stdout', 'stderr', 'status'].forEach(function (file) {
+    child[file] = fs.readFileSync(tmpdir + '/' + file, options.encoding)
+    setTimeout(unlinkFile, 500, tmpdir + '/' + file)
+  })
+
+  child.status = Number(child.status)
+  if (child.status !== 0) {
+    error = child
+  }
+
+  try {
+    fs.rmdirSync(tmpdir)
+  } catch (ignore) {}
+  if (error) {
+    throw error
+  }
+  return child.stdout
+}
+
+function makeCommand(file, args) {
+  var command, quote
+  command = file
+  if (args.length > 0) {
+    for(var i in args) {
+      command = command + ' '
+      if (args[i][0] === '-') {
+        command = command + args[i]
+      } else {
+        if (!quote) {
+          command = command + '\"'
+          quote = true
+        }
+        command = command + args[i]
+        if (quote) {
+          if (args.length === (parseInt(i) + 1)) {
+            command = command + '\"'
+          }
+        }
+      }
+    }
+  }
+  return command
+}
+
+function determine_os() {
+  var os = ''
+  var tmpVar = ''
+  if (process.env.OSTYPE) {
+    tmpVar = process.env.OSTYPE
+  } else  if (process.env.OS) {
+    tmpVar = process.env.OS
+  } else {
+    //default is linux
+    tmpVar = 'linux'
+  }
+
+  if (tmpVar.startsWith('linux')) {
+    os = 'linux'
+  }
+  if (tmpVar.startsWith('win')) {
+    os = 'win'
+  }
+
+  return os
+}
+
+function unlinkFile(file) {
+  fs.unlinkSync(file)
+}
+
+module.exports = processExecSync
diff --git a/test/test-addon.js b/test/test-addon.js
index c2a71f4498..900b0b049d 100644
--- a/test/test-addon.js
+++ b/test/test-addon.js
@@ -1,10 +1,40 @@
 'use strict'
 
 var test = require('tape')
-var execFile = require('child_process').execFile
 var path = require('path')
+var fs = require('graceful-fs')
+var child_process = require('child_process')
+var os = require('os')
 var addonPath = path.resolve(__dirname, 'node_modules', 'hello_world')
 var nodeGyp = path.resolve(__dirname, '..', 'bin', 'node-gyp.js')
+var execFileSync = child_process.execFileSync || require('./process-exec-sync')
+var execFile = child_process.execFile
+
+function runHello(hostProcess) {
+  if (!hostProcess) {
+    hostProcess = process.execPath
+  }
+  var testCode = "console.log(require('hello_world').hello())"
+  console.log('running ', hostProcess);
+  return execFileSync(hostProcess, ['-e', testCode], { cwd: __dirname }).toString()
+}
+
+function getEncoding() {
+  var code = 'import locale;print locale.getdefaultlocale()[1]'
+  return execFileSync('python', ['-c', code]).toString().trim()
+}
+
+function checkCharmapValid() {
+  var data
+  try {
+    data = execFileSync('python', ['fixtures/test-charmap.py'],
+                        { cwd: __dirname })
+  } catch (err) {
+    return false
+  }
+  var lines = data.toString().trim().split('\n')
+  return lines.pop() === 'True'
+}
 
 test('build simple addon', function (t) {
   t.plan(3)
@@ -16,12 +46,98 @@ test('build simple addon', function (t) {
     var lastLine = logLines[logLines.length-1]
     t.strictEqual(err, null)
     t.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
+    t.strictEqual(runHello().trim(), 'world')
+  })
+  proc.stdout.setEncoding('utf-8')
+  proc.stderr.setEncoding('utf-8')
+})
+
+test('build simple addon in path with non-ascii characters', function (t) {
+  t.plan(1)
+
+  if (!checkCharmapValid()) {
+    return t.skip('python console app can\'t encode non-ascii character.')
+  }
+
+  var testDirNames = {
+    'cp936': '文件夹',
+    'cp1252': 'Latīna',
+    'cp932': 'フォルダ'
+  }
+  // Select non-ascii characters by current encoding
+  var testDirName = testDirNames[getEncoding()]
+  // If encoding is UTF-8 or other then no need to test
+  if (!testDirName) {
+    return t.skip('no need to test')
+  }
+
+  t.plan(3)
+
+  var data, configPath = path.join(addonPath, 'build', 'config.gypi')
+  try {
+    data = fs.readFileSync(configPath, 'utf8')
+  } catch (err) {
+    t.error(err)
+    return
+  }
+  var config = JSON.parse(data.replace(/\#.+\n/, ''))
+  var nodeDir = config.variables.nodedir
+  var testNodeDir = path.join(addonPath, testDirName)
+  // Create symbol link to path with non-ascii characters
+  try {
+    fs.symlinkSync(nodeDir, testNodeDir, 'dir')
+  } catch (err) {
+    switch (err.code) {
+      case 'EEXIST': break
+      case 'EPERM':
+        t.error(err, 'Please try to running console as an administrator')
+        return
+      default:
+        t.error(err)
+        return
+    }
+  }
+
+  var cmd = [nodeGyp, 'rebuild', '-C', addonPath,
+             '--loglevel=verbose', '-nodedir=' + testNodeDir]
+  var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) {
     try {
-      var binding = require('hello_world')
-      t.strictEqual(binding.hello(), 'world')
-    } catch (error) {
-      t.error(error, 'load module')
+      fs.unlink(testNodeDir)
+    } catch (err) {
+      t.error(err)
     }
+
+    var logLines = stderr.toString().trim().split(/\r?\n/)
+    var lastLine = logLines[logLines.length-1]
+    t.strictEqual(err, null)
+    t.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
+    t.strictEqual(runHello().trim(), 'world')
+  })
+  proc.stdout.setEncoding('utf-8')
+  proc.stderr.setEncoding('utf-8')
+})
+
+test('addon works with renamed host executable', function (t) {
+  // No `fs.copyFileSync` before node8.
+  if (process.version.substr(1).split('.')[0] < 8) {
+    t.skip("skipping test for old node version");
+    t.end();
+    return;
+  }
+
+  t.plan(3)
+
+  var notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath))
+  fs.copyFileSync(process.execPath, notNodePath)
+
+  var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose']
+  var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) {
+    var logLines = stderr.toString().trim().split(/\r?\n/)
+    var lastLine = logLines[logLines.length-1]
+    t.strictEqual(err, null)
+    t.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
+    t.strictEqual(runHello(notNodePath).trim(), 'world')
+    fs.unlinkSync(notNodePath)
   })
   proc.stdout.setEncoding('utf-8')
   proc.stderr.setEncoding('utf-8')
diff --git a/test/test-configure-python.js b/test/test-configure-python.js
index f235bdbba1..07cdce2b17 100644
--- a/test/test-configure-python.js
+++ b/test/test-configure-python.js
@@ -6,8 +6,8 @@ var gyp = require('../lib/node-gyp')
 var requireInject = require('require-inject')
 var configure = requireInject('../lib/configure', {
   'graceful-fs': {
-    'openSync': function (file, mode) { return 0; },
-    'closeSync': function (fd) { },
+    'openSync': function () { return 0; },
+    'closeSync': function () { },
     'writeFile': function (file, data, cb) { cb() },
     'stat': function (file, cb) { cb(null, {}) }
   }
diff --git a/test/test-find-accessible-sync.js b/test/test-find-accessible-sync.js
index d336243dd0..114403e278 100644
--- a/test/test-find-accessible-sync.js
+++ b/test/test-find-accessible-sync.js
@@ -5,7 +5,7 @@ var path = require('path')
 var requireInject = require('require-inject')
 var configure = requireInject('../lib/configure', {
   'graceful-fs': {
-    'closeSync': function (fd) { return undefined },
+    'closeSync': function () { return undefined },
     'openSync': function (path) {
       if (readableFiles.some(function (f) { return f === path} )) {
         return 0
diff --git a/test/test-find-python.js b/test/test-find-python.js
index 2d9f171c57..f3c14ce659 100644
--- a/test/test-find-python.js
+++ b/test/test-find-python.js
@@ -1,7 +1,6 @@
 'use strict'
 
 var test = require('tape')
-var path = require('path')
 var configure = require('../lib/configure')
 var execFile = require('child_process').execFile
 var PythonFinder = configure.test.PythonFinder
@@ -9,7 +8,7 @@ var PythonFinder = configure.test.PythonFinder
 test('find python', function (t) {
   t.plan(4)
 
-  configure.test.findPython('python', function (err, found) {
+  configure.test.findPython(null, function (err, found) {
     t.strictEqual(err, null)
     var proc = execFile(found, ['-V'], function (err, stdout, stderr) {
       t.strictEqual(err, null)
@@ -23,181 +22,188 @@ test('find python', function (t) {
 
 function poison(object, property) {
   function fail() {
-    throw new Error('Property ' + property + ' should not have been accessed.')
+    console.error(Error(`Property ${property} should not have been accessed.`))
+    process.abort()
   }
   var descriptor = {
-    configurable: true,
+    configurable: false,
     enumerable: false,
-    writable: true,
-    getter: fail,
-    setter: fail,
+    get: fail,
+    set: fail,
   }
   Object.defineProperty(object, property, descriptor)
 }
 
-// Work around a v0.10.x CI issue where path.resolve() on UNIX systems prefixes
-// Windows paths with the current working directory.  v0.12 and up are free of
-// this issue because they use path.win32.resolve() which does the right thing.
-var resolve = path.win32 && path.win32.resolve || function() {
-  function rstrip(s) { return s.replace(/\\+$/, '') }
-  return [].slice.call(arguments).map(rstrip).join('\\')
-}
-
 function TestPythonFinder() { PythonFinder.apply(this, arguments) }
 TestPythonFinder.prototype = Object.create(PythonFinder.prototype)
-poison(TestPythonFinder.prototype, 'env')
-poison(TestPythonFinder.prototype, 'execFile')
-poison(TestPythonFinder.prototype, 'resolve')
-poison(TestPythonFinder.prototype, 'stat')
-poison(TestPythonFinder.prototype, 'which')
-poison(TestPythonFinder.prototype, 'win')
+// Silence npmlog - remove for debugging
+TestPythonFinder.prototype.log = {
+  silly: () => {},
+  verbose: () => {},
+  info: () => {},
+  warn: () => {},
+  error: () => {},
+}
 
 test('find python - python', function (t) {
-  t.plan(5)
+  t.plan(6)
 
   var f = new TestPythonFinder('python', done)
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(null, program)
-  }
   f.execFile = function(program, args, opts, cb) {
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '2.7.0')
+    f.execFile = function(program, args, opts, cb) {
+      poison(f, 'execFile')
+      t.strictEqual(program, '/path/python')
+      t.ok(/sys\.version_info/.test(args[1]))
+      cb(null, '2.7.15')
+    }
+    t.strictEqual(program,
+                  process.platform === 'win32' ? '"python"' : 'python')
+    t.ok(/sys\.executable/.test(args[1]))
+    cb(null, '/path/python')
   }
-  f.checkPython()
+  f.findPython()
 
   function done(err, python) {
     t.strictEqual(err, null)
-    t.strictEqual(python, 'python')
+    t.strictEqual(python, '/path/python')
   }
 })
 
 test('find python - python too old', function (t) {
-  t.plan(4)
+  t.plan(2)
 
-  var f = new TestPythonFinder('python', done)
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(null, program)
-  }
+  var f = new TestPythonFinder(null, done)
   f.execFile = function(program, args, opts, cb) {
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '2.3.4')
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(null, '/path/python')
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(null, '2.3.4')
+    } else {
+      t.fail()
+    }
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/is not supported by gyp/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not supported/i.test(f.errorLog))
   }
 })
 
 test('find python - python too new', function (t) {
-  t.plan(4)
+  t.plan(2)
 
-  var f = new TestPythonFinder('python', done)
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(null, program)
-  }
+  var f = new TestPythonFinder(null, done)
   f.execFile = function(program, args, opts, cb) {
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '3.0.0')
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(null, '/path/python')
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(null, '3.0.0')
+    } else {
+      t.fail()
+    }
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/is not supported by gyp/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not supported/i.test(f.errorLog))
   }
 })
 
 test('find python - no python', function (t) {
   t.plan(2)
 
-  var f = new TestPythonFinder('python', done)
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(new Error('not found'))
+  var f = new TestPythonFinder(null, done)
+  f.execFile = function(program, args, opts, cb) {
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(new Error('not found'))
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(new Error('not a Python executable'))
+    } else {
+      t.fail()
+    }
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/Can't find Python executable/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not in PATH/.test(f.errorLog))
   }
 })
 
 test('find python - no python2', function (t) {
-  t.plan(6)
+  t.plan(2)
 
-  var f = new TestPythonFinder('python2', done)
-  f.which = function(program, cb) {
-    f.which = function(program, cb) {
-      t.strictEqual(program, 'python')
-      cb(null, program)
-    }
-    t.strictEqual(program, 'python2')
-    cb(new Error('not found'))
-  }
+  var f = new TestPythonFinder(null, done)
   f.execFile = function(program, args, opts, cb) {
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '2.7.0')
+    if (/sys\.executable/.test(args[args.length-1])) {
+      if (program == 'python2') {
+        cb(new Error('not found'))
+      } else {
+        cb(null, '/path/python')
+      }
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(null, '2.7.14')
+    } else {
+      t.fail()
+    }
   }
-  f.checkPython()
+  f.findPython()
 
   function done(err, python) {
     t.strictEqual(err, null)
-    t.strictEqual(python, 'python')
+    t.strictEqual(python, '/path/python')
   }
 })
 
 test('find python - no python2, no python, unix', function (t) {
-  t.plan(3)
+  t.plan(2)
 
-  var f = new TestPythonFinder('python2', done)
-  poison(f, 'checkPythonLauncher')
+  var f = new TestPythonFinder(null, done)
+  f.checkPyLauncher = t.fail
   f.win = false
 
-  f.which = function(program, cb) {
-    f.which = function(program, cb) {
-      t.strictEqual(program, 'python')
+  f.execFile = function(program, args, opts, cb) {
+    if (/sys\.executable/.test(args[args.length-1])) {
       cb(new Error('not found'))
+    } else {
+      t.fail()
     }
-    t.strictEqual(program, 'python2')
-    cb(new Error('not found'))
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/Can't find Python executable/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not in PATH/.test(f.errorLog))
   }
 })
 
 test('find python - no python, use python launcher', function (t) {
-  t.plan(8)
+  t.plan(4)
 
-  var f = new TestPythonFinder('python', done)
-  f.env = {}
+  var f = new TestPythonFinder(null, done)
   f.win = true
 
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(new Error('not found'))
-  }
   f.execFile = function(program, args, opts, cb) {
-    f.execFile = function(program, args, opts, cb) {
-      t.strictEqual(program, 'Z:\\snake.exe')
-      t.ok(/import platform/.test(args[1]))
-      cb(null, '2.7.0')
+    if (program === 'py.exe') {
+      t.notEqual(args.indexOf('-2'), -1)
+      t.notEqual(args.indexOf('-c'), -1)
+      return cb(null, 'Z:\\snake.exe')
+    }
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(new Error('not found'))
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      if (program === 'Z:\\snake.exe') {
+        cb(null, '2.7.14')
+      } else {
+        t.fail()
+      }
+    } else {
+      t.fail()
     }
-    t.strictEqual(program, 'py.exe')
-    t.notEqual(args.indexOf('-2'), -1)
-    t.notEqual(args.indexOf('-c'), -1)
-    cb(null, 'Z:\\snake.exe')
   }
-  f.checkPython()
+  f.findPython()
 
   function done(err, python) {
     t.strictEqual(err, null)
@@ -206,33 +212,34 @@ test('find python - no python, use python launcher', function (t) {
 })
 
 test('find python - python 3, use python launcher', function (t) {
-  t.plan(10)
+  t.plan(4)
 
-  var f = new TestPythonFinder('python', done)
-  f.env = {}
+  var f = new TestPythonFinder(null, done)
   f.win = true
 
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(null, program)
-  }
   f.execFile = function(program, args, opts, cb) {
-    f.execFile = function(program, args, opts, cb) {
+    if (program === 'py.exe') {
       f.execFile = function(program, args, opts, cb) {
-        t.strictEqual(program, 'Z:\\snake.exe')
-        t.ok(/import platform/.test(args[1]))
-        cb(null, '2.7.0')
+        poison(f, 'execFile')
+        if (/sys\.version_info/.test(args[args.length-1])) {
+          cb(null, '2.7.14')
+        } else {
+          t.fail()
+        }
       }
-      t.strictEqual(program, 'py.exe')
       t.notEqual(args.indexOf('-2'), -1)
       t.notEqual(args.indexOf('-c'), -1)
-      cb(null, 'Z:\\snake.exe')
+      return cb(null, 'Z:\\snake.exe')
+    }
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(null, '/path/python')
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(null, '3.0.0')
+    } else {
+      t.fail()
     }
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '3.0.0')
   }
-  f.checkPython()
+  f.findPython()
 
   function done(err, python) {
     t.strictEqual(err, null)
@@ -242,98 +249,100 @@ test('find python - python 3, use python launcher', function (t) {
 
 test('find python - python 3, use python launcher, python 2 too old',
      function (t) {
-  t.plan(9)
+  t.plan(6)
 
-  var f = new TestPythonFinder('python', done)
-  f.checkedPythonLauncher = false
-  f.env = {}
+  var f = new TestPythonFinder(null, done)
   f.win = true
 
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(null, program)
-  }
   f.execFile = function(program, args, opts, cb) {
-    f.execFile = function(program, args, opts, cb) {
+    if (program === 'py.exe') {
       f.execFile = function(program, args, opts, cb) {
-        t.strictEqual(program, 'Z:\\snake.exe')
-        t.ok(/import platform/.test(args[1]))
-        cb(null, '2.3.4')
+        if (/sys\.version_info/.test(args[args.length-1])) {
+          f.execFile = function(program, args, opts, cb) {
+            if (/sys\.version_info/.test(args[args.length-1])) {
+              poison(f, 'execFile')
+              t.strictEqual(program, f.defaultLocation)
+              cb(new Error('not found'))
+            } else {
+              t.fail()
+            }
+          }
+          t.strictEqual(program, 'Z:\\snake.exe')
+          cb(null, '2.3.4')
+        } else {
+          t.fail()
+        }
       }
-      t.strictEqual(program, 'py.exe')
       t.notEqual(args.indexOf('-2'), -1)
       t.notEqual(args.indexOf('-c'), -1)
-      cb(null, 'Z:\\snake.exe')
+      return cb(null, 'Z:\\snake.exe')
+    }
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(null, '/path/python')
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(null, '3.0.0')
+    } else {
+      t.fail()
     }
-    t.strictEqual(program, 'python')
-    t.ok(/import platform/.test(args[1]))
-    cb(null, '3.0.0')
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/is not supported by gyp/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not supported/i.test(f.errorLog))
   }
 })
 
 test('find python - no python, no python launcher, good guess', function (t) {
-  t.plan(6)
+  t.plan(4)
 
   var re = /C:[\\\/]Python27[\\\/]python[.]exe/
-  var f = new TestPythonFinder('python', done)
-  f.env = {}
+  var f = new TestPythonFinder(null, done)
   f.win = true
 
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(new Error('not found'))
-  }
   f.execFile = function(program, args, opts, cb) {
-    f.execFile = function(program, args, opts, cb) {
-      t.ok(re.test(program))
-      t.ok(/import platform/.test(args[1]))
-      cb(null, '2.7.0')
+    if (program === 'py.exe') {
+      f.execFile = function(program, args, opts, cb) {
+        poison(f, 'execFile')
+        t.ok(re.test(program))
+        t.ok(/sys\.version_info/.test(args[args.length-1]))
+        cb(null, '2.7.14')
+      }
+      return cb(new Error('not found'))
+    }
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(new Error('not found'))
+    } else {
+      t.fail()
     }
-    t.strictEqual(program, 'py.exe')
-    cb(new Error('not found'))
-  }
-  f.resolve = resolve
-  f.stat = function(path, cb) {
-    t.ok(re.test(path))
-    cb(null, {})
   }
-  f.checkPython()
+  f.findPython()
 
   function done(err, python) {
+    t.strictEqual(err, null)
     t.ok(re.test(python))
   }
 })
 
 test('find python - no python, no python launcher, bad guess', function (t) {
-  t.plan(4)
+  t.plan(2)
 
-  var f = new TestPythonFinder('python', done)
-  f.env = { SystemDrive: 'Z:\\' }
+  var f = new TestPythonFinder(null, done)
   f.win = true
 
-  f.which = function(program, cb) {
-    t.strictEqual(program, 'python')
-    cb(new Error('not found'))
-  }
   f.execFile = function(program, args, opts, cb) {
-    t.strictEqual(program, 'py.exe')
-    cb(new Error('not found'))
-  }
-  f.resolve = resolve
-  f.stat = function(path, cb) {
-    t.ok(/Z:[\\\/]Python27[\\\/]python.exe/.test(path))
-    var err = new Error('not found')
-    err.code = 'ENOENT'
-    cb(err)
+    if (/sys\.executable/.test(args[args.length-1])) {
+      cb(new Error('not found'))
+    } else if (/sys\.version_info/.test(args[args.length-1])) {
+      cb(new Error('not a Python executable'))
+    } else {
+      t.fail()
+    }
   }
-  f.checkPython()
+  f.findPython()
 
-  function done(err, python) {
-    t.ok(/Can't find Python executable/.test(err))
+  function done(err) {
+    t.ok(/Could not find any Python/.test(err))
+    t.ok(/not in PATH/.test(f.errorLog))
   }
 })
diff --git a/test/test-install.js b/test/test-install.js
new file mode 100644
index 0000000000..f647326a7f
--- /dev/null
+++ b/test/test-install.js
@@ -0,0 +1,37 @@
+'use strict'
+
+var test = require('tape')
+var install = require('../lib/install').test.install
+
+test('EACCES retry once', function (t) {
+  t.plan(3)
+
+  var fs = {}
+  fs.stat = function (path, cb) {
+    var err = new Error()
+    err.code = 'EACCES'
+    cb(err)
+    t.ok(true);
+  }
+
+
+  var gyp = {}
+  gyp.devDir = __dirname
+  gyp.opts = {}
+  gyp.opts.ensure = true
+  gyp.commands = {}
+  gyp.commands.install = function (argv, cb) {
+    install(fs, gyp, argv, cb)
+  }
+  gyp.commands.remove = function (argv, cb) {
+    cb()
+  }
+
+  gyp.commands.install([], function (err) {
+    t.ok(true)
+    if (/"pre" versions of node cannot be installed/.test(err.message)) {
+      t.ok(true)
+      t.ok(true)
+    }
+  })
+})
diff --git a/tools/gyp/pylib/gyp/generator/compile_commands_json.py b/tools/gyp/pylib/gyp/generator/compile_commands_json.py
new file mode 100644
index 0000000000..575db63c4e
--- /dev/null
+++ b/tools/gyp/pylib/gyp/generator/compile_commands_json.py
@@ -0,0 +1,115 @@
+# Copyright (c) 2016 Ben Noordhuis <info@bnoordhuis.nl>. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import gyp.common
+import gyp.xcode_emulation
+import json
+import os
+
+generator_additional_non_configuration_keys = []
+generator_additional_path_sections = []
+generator_extra_sources_for_rules = []
+generator_filelist_paths = None
+generator_supports_multiple_toolsets = True
+generator_wants_sorted_dependencies = False
+
+# Lifted from make.py.  The actual values don't matter much.
+generator_default_variables = {
+  'CONFIGURATION_NAME': '$(BUILDTYPE)',
+  'EXECUTABLE_PREFIX': '',
+  'EXECUTABLE_SUFFIX': '',
+  'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni',
+  'PRODUCT_DIR': '$(builddir)',
+  'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s',
+  'RULE_INPUT_EXT': '$(suffix $<)',
+  'RULE_INPUT_NAME': '$(notdir $<)',
+  'RULE_INPUT_PATH': '$(abspath $<)',
+  'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',
+  'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
+  'SHARED_LIB_PREFIX': 'lib',
+  'STATIC_LIB_PREFIX': 'lib',
+  'STATIC_LIB_SUFFIX': '.a',
+}
+
+
+def IsMac(params):
+  return 'mac' == gyp.common.GetFlavor(params)
+
+
+def CalculateVariables(default_variables, params):
+  default_variables.setdefault('OS', gyp.common.GetFlavor(params))
+
+
+def AddCommandsForTarget(cwd, target, params, per_config_commands):
+  output_dir = params['generator_flags']['output_dir']
+  for configuration_name, configuration in target['configurations'].iteritems():
+    builddir_name = os.path.join(output_dir, configuration_name)
+
+    if IsMac(params):
+      xcode_settings = gyp.xcode_emulation.XcodeSettings(target)
+      cflags = xcode_settings.GetCflags(configuration_name)
+      cflags_c = xcode_settings.GetCflagsC(configuration_name)
+      cflags_cc = xcode_settings.GetCflagsCC(configuration_name)
+    else:
+      cflags = configuration.get('cflags', [])
+      cflags_c = configuration.get('cflags_c', [])
+      cflags_cc = configuration.get('cflags_cc', [])
+
+    cflags_c = cflags + cflags_c
+    cflags_cc = cflags + cflags_cc
+
+    defines = configuration.get('defines', [])
+    defines = ['-D' + s for s in defines]
+
+    # TODO(bnoordhuis) Handle generated source files.
+    sources = target.get('sources', [])
+    sources = [s for s in sources if s.endswith('.c') or s.endswith('.cc')]
+
+    def resolve(filename):
+      return os.path.abspath(os.path.join(cwd, filename))
+
+    # TODO(bnoordhuis) Handle generated header files.
+    include_dirs = configuration.get('include_dirs', [])
+    include_dirs = [s for s in include_dirs if not s.startswith('$(obj)')]
+    includes = ['-I' + resolve(s) for s in include_dirs]
+
+    defines = gyp.common.EncodePOSIXShellList(defines)
+    includes = gyp.common.EncodePOSIXShellList(includes)
+    cflags_c = gyp.common.EncodePOSIXShellList(cflags_c)
+    cflags_cc = gyp.common.EncodePOSIXShellList(cflags_cc)
+
+    commands = per_config_commands.setdefault(configuration_name, [])
+    for source in sources:
+      file = resolve(source)
+      isc = source.endswith('.c')
+      cc = 'cc' if isc else 'c++'
+      cflags = cflags_c if isc else cflags_cc
+      command = ' '.join((cc, defines, includes, cflags,
+                          '-c', gyp.common.EncodePOSIXShellArgument(file)))
+      commands.append(dict(command=command, directory=output_dir, file=file))
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+  per_config_commands = {}
+  for qualified_target, target in target_dicts.iteritems():
+    build_file, target_name, toolset = (
+        gyp.common.ParseQualifiedTarget(qualified_target))
+    if IsMac(params):
+      settings = data[build_file]
+      gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(settings, target)
+    cwd = os.path.dirname(build_file)
+    AddCommandsForTarget(cwd, target, params, per_config_commands)
+
+  output_dir = params['generator_flags']['output_dir']
+  for configuration_name, commands in per_config_commands.iteritems():
+    filename = os.path.join(output_dir,
+                            configuration_name,
+                            'compile_commands.json')
+    gyp.common.EnsureDirExists(filename)
+    fp = open(filename, 'w')
+    json.dump(commands, fp=fp, indent=0, check_circular=False)
+
+
+def PerformBuild(data, configurations, params):
+  pass
