Import Cobalt 21.lts.1.276914
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 0b3308c..7f8b3ba 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-276711
\ No newline at end of file
+276914
\ No newline at end of file
diff --git a/src/starboard/evergreen/shared/gyp_configuration.py b/src/starboard/evergreen/shared/gyp_configuration.py
index d11e04c..ead5082 100644
--- a/src/starboard/evergreen/shared/gyp_configuration.py
+++ b/src/starboard/evergreen/shared/gyp_configuration.py
@@ -102,9 +102,9 @@
 
   def GetTestTargets(self):
     tests = super(EvergreenConfiguration, self).GetTestTargets()
-    return [test for test in tests if test not in self.__BLACKLISTED_TESTS]
+    return [test for test in tests if test not in self.__FORBIDDEN_TESTS]
 
-  __BLACKLISTED_TESTS = [  # pylint: disable=invalid-name
+  __FORBIDDEN_TESTS = [  # pylint: disable=invalid-name
       # elf_loader_test and installation_manager_test are explicitly tests that
       # validate the correctness of the underlying platform. We should not be
       # running these tests in Evergreen mode, and instead will rely on the
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index 556dc46..81dc81a 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -26,6 +26,7 @@
 import gyp.MSVSUtil as MSVSUtil
 import gyp.xcode_emulation
 
+from gyp.common import GetEnvironFallback
 import gyp.ninja_syntax as ninja_syntax
 
 if sys.platform == 'cygwin':
@@ -236,9 +237,28 @@
     """Return true if this is a target that can be linked against."""
     return self.type in ('static_library', 'shared_library')
 
+  def UsesToc(self, flavor):
+    """Return true if the target should produce a restat rule based on a TOC
+    file."""
+    try:
+      # Do not use TOC files for abstract toolchain.
+      toolchain = GetTargetToolchain(flavor)
+      return False
+    except NotImplementedError:
+      # Follow the logic for the legacy toolchain.
+      pass
+    # For bundles, the .TOC should be produced for the binary, not for
+    # FinalOutput(). But the naive approach would put the TOC file into the
+    # bundle, so don't do this for bundles for now.
+    if flavor in windows_host_flavors or self.bundle:
+      return False
+    return self.type in ('shared_library', 'loadable_module')
+
   def PreActionInput(self, flavor):
     """Return the path, if any, that should be used as a dependency of
     any dependent action step."""
+    if self.UsesToc(flavor):
+      return self.FinalOutput() + '.TOC'
     return self.FinalOutput() or self.preaction_stamp
 
   def PreCompileInput(self):
@@ -446,8 +466,12 @@
     if len(targets) == 1:
       return targets[0]
 
-    assert FindFirstInstanceOf(abstract.Stamp, GetHostToolchain(
-        self.flavor)), 'Host toolchain must provide stamp tool.'
+    try:
+      assert FindFirstInstanceOf(abstract.Stamp, GetHostToolchain(
+          self.flavor)), 'Host toolchain must provide stamp tool.'
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
+      pass
 
     stamp_output = self.GypPathToUniqueOutput(name + '.stamp')
     self.ninja.build(stamp_output, 'stamp', targets)
@@ -791,8 +815,12 @@
     return all_outputs
 
   def WriteCopy(self, src, dst, prebuild, env, mac_bundle_depends):
-    assert FindFirstInstanceOf(abstract.Copy, GetHostToolchain(
-        self.flavor)), 'Host toolchain must provide copy tool.'
+    try:
+      assert FindFirstInstanceOf(abstract.Copy, GetHostToolchain(
+          self.flavor)), 'Host toolchain must provide copy tool.'
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
+      pass
 
     dst = self.GypPathToNinja(dst, env)
     # Renormalize with the separator character of the os on which ninja will run
@@ -890,245 +918,572 @@
   def WriteSources(self, config_name, config, sources, predepends,
                    precompiled_header, spec):
     """Write build rules to compile all of |sources|."""
-    shell = GetShell(self.flavor)
 
-    if self.toolset == 'target':
-      toolchain = GetTargetToolchain(self.flavor, spec=spec,
-                                     config_name=config_name)
-    else:
-      toolchain = GetHostToolchain(self.flavor, spec=spec,
-                                   config_name=config_name)
+    try:
+      shell = GetShell(self.flavor)
 
-    defines = config.get('defines', [])
-    include_dirs = [
-        self.GypPathToNinja(include_dir)
-        for include_dir in config.get('include_dirs', [])
-    ]
-
-    # TODO: This code emulates legacy toolchain behavior. We need to migrate
-    #       to single-responsibility, toolchain-independent GYP keywords as
-    #       per abstract toolchain design doc.
-    cflags = GetConfigFlags(config, self.toolset, 'cflags')
-    cflags_c = GetConfigFlags(config, self.toolset, 'cflags_c')
-    cflags_cc = GetConfigFlags(config, self.toolset, 'cflags_cc')
-    cflags_mm = GetConfigFlags(config, self.toolset, 'cflags_mm')
-    obj = 'obj'
-    if self.toolset != 'target':
-      obj += '.' + self.toolset
-    pdbpath = os.path.normpath(
-        os.path.join(obj, self.base_dir, self.name + '.pdb'))
-    self.WriteVariableList('pdbname', [pdbpath])
-
-    c_compiler = FindFirstInstanceOf(abstract.CCompiler, toolchain)
-    if c_compiler:
-      c_compiler_flags = c_compiler.GetFlags(defines, include_dirs,
-                                             cflags + cflags_c)
-      self.ninja.variable(
-          '{0}_flags'.format(GetNinjaRuleName(c_compiler, self.toolset)),
-          shell.Join(c_compiler_flags))
-
-    cxx_compiler = FindFirstInstanceOf(abstract.CxxCompiler, toolchain)
-    if cxx_compiler:
-      cxx_compiler_flags = cxx_compiler.GetFlags(defines, include_dirs,
-                                                 cflags + cflags_cc)
-      self.ninja.variable(
-          '{0}_flags'.format(GetNinjaRuleName(cxx_compiler, self.toolset)),
-          shell.Join(cxx_compiler_flags))
-
-    objcxx_compiler = FindFirstInstanceOf(abstract.ObjectiveCxxCompiler,
-                                          toolchain)
-    if objcxx_compiler:
-      objcxx_compiler_flags = objcxx_compiler.GetFlags(
-          defines, include_dirs, cflags + cflags_cc + cflags_mm)
-      self.ninja.variable(
-          '{0}_flags'.format(GetNinjaRuleName(objcxx_compiler, self.toolset)),
-          shell.Join(objcxx_compiler_flags))
-
-    assembler = FindFirstInstanceOf(abstract.AssemblerWithCPreprocessor,
-                                    toolchain)
-    if assembler:
-      assembler_flags = assembler.GetFlags(defines, include_dirs,
-                                           cflags + cflags_c)
-      self.ninja.variable(
-          '{0}_flags'.format(GetNinjaRuleName(assembler, self.toolset)),
-          shell.Join(assembler_flags))
-
-    self.ninja.newline()
-
-    outputs = []
-    for source in sources:
-      _, extension = os.path.splitext(source)
-      if extension in ['.c']:
-        assert c_compiler, ('Toolchain must provide C compiler in order to '
-                            'build {0} for {1} platform.').format(
-                                source, self.toolset)
-        rule_name = GetNinjaRuleName(c_compiler, self.toolset)
-      elif extension in ['.cc', '.cpp', '.cxx']:
-        assert cxx_compiler, ('Toolchain must provide C++ compiler in order '
-                              'to build {0} for {1} platform.').format(
-                                  source, self.toolset)
-        rule_name = GetNinjaRuleName(cxx_compiler, self.toolset)
-      elif extension in ['.mm']:
-        assert objcxx_compiler, ('Toolchain must provide Objective-C++ '
-                                 'compiler in order to build {0} for {1} '
-                                 'platform.').format(source, self.toolset)
-        rule_name = GetNinjaRuleName(objcxx_compiler, self.toolset)
-      elif extension in ['.S', '.s']:
-        assert assembler, ('Toolchain must provide assembler in order to '
-                           'build {0} for {1} platform.').format(
-                               source, self.toolset)
-        rule_name = GetNinjaRuleName(assembler, self.toolset)
+      if self.toolset == 'target':
+        toolchain = GetTargetToolchain(self.flavor, spec=spec,
+                                       config_name=config_name)
       else:
-        rule_name = None
+        toolchain = GetHostToolchain(self.flavor, spec=spec,
+                                     config_name=config_name)
 
-      if rule_name:
+      defines = config.get('defines', [])
+      include_dirs = [
+          self.GypPathToNinja(include_dir)
+          for include_dir in config.get('include_dirs', [])
+      ]
+
+      # TODO: This code emulates legacy toolchain behavior. We need to migrate
+      #       to single-responsibility, toolchain-independent GYP keywords as
+      #       per abstract toolchain design doc.
+      cflags = GetConfigFlags(config, self.toolset, 'cflags')
+      cflags_c = GetConfigFlags(config, self.toolset, 'cflags_c')
+      cflags_cc = GetConfigFlags(config, self.toolset, 'cflags_cc')
+      cflags_mm = GetConfigFlags(config, self.toolset, 'cflags_mm')
+      obj = 'obj'
+      if self.toolset != 'target':
+        obj += '.' + self.toolset
+      pdbpath = os.path.normpath(
+          os.path.join(obj, self.base_dir, self.name + '.pdb'))
+      self.WriteVariableList('pdbname', [pdbpath])
+
+      c_compiler = FindFirstInstanceOf(abstract.CCompiler, toolchain)
+      if c_compiler:
+        c_compiler_flags = c_compiler.GetFlags(defines, include_dirs,
+                                               cflags + cflags_c)
+        self.ninja.variable(
+            '{0}_flags'.format(GetNinjaRuleName(c_compiler, self.toolset)),
+            shell.Join(c_compiler_flags))
+
+      cxx_compiler = FindFirstInstanceOf(abstract.CxxCompiler, toolchain)
+      if cxx_compiler:
+        cxx_compiler_flags = cxx_compiler.GetFlags(defines, include_dirs,
+                                                   cflags + cflags_cc)
+        self.ninja.variable(
+            '{0}_flags'.format(GetNinjaRuleName(cxx_compiler, self.toolset)),
+            shell.Join(cxx_compiler_flags))
+
+      objcxx_compiler = FindFirstInstanceOf(abstract.ObjectiveCxxCompiler,
+                                            toolchain)
+      if objcxx_compiler:
+        objcxx_compiler_flags = objcxx_compiler.GetFlags(
+            defines, include_dirs, cflags + cflags_cc + cflags_mm)
+        self.ninja.variable(
+            '{0}_flags'.format(GetNinjaRuleName(objcxx_compiler, self.toolset)),
+            shell.Join(objcxx_compiler_flags))
+
+      assembler = FindFirstInstanceOf(abstract.AssemblerWithCPreprocessor,
+                                      toolchain)
+      if assembler:
+        assembler_flags = assembler.GetFlags(defines, include_dirs,
+                                             cflags + cflags_c)
+        self.ninja.variable(
+            '{0}_flags'.format(GetNinjaRuleName(assembler, self.toolset)),
+            shell.Join(assembler_flags))
+
+      self.ninja.newline()
+
+      outputs = []
+      for source in sources:
+        _, extension = os.path.splitext(source)
+        if extension in ['.c']:
+          assert c_compiler, ('Toolchain must provide C compiler in order to '
+                              'build {0} for {1} platform.').format(
+                                  source, self.toolset)
+          rule_name = GetNinjaRuleName(c_compiler, self.toolset)
+        elif extension in ['.cc', '.cpp', '.cxx']:
+          assert cxx_compiler, ('Toolchain must provide C++ compiler in order '
+                                'to build {0} for {1} platform.').format(
+                                    source, self.toolset)
+          rule_name = GetNinjaRuleName(cxx_compiler, self.toolset)
+        elif extension in ['.mm']:
+          assert objcxx_compiler, ('Toolchain must provide Objective-C++ '
+                                   'compiler in order to build {0} for {1} '
+                                   'platform.').format(source, self.toolset)
+          rule_name = GetNinjaRuleName(objcxx_compiler, self.toolset)
+        elif extension in ['.S', '.s']:
+          assert assembler, ('Toolchain must provide assembler in order to '
+                             'build {0} for {1} platform.').format(
+                                 source, self.toolset)
+          rule_name = GetNinjaRuleName(assembler, self.toolset)
+        else:
+          rule_name = None
+
+        if rule_name:
+          input = self.GypPathToNinja(source)
+          output = '{0}.o'.format(self.GypPathToUniqueOutput(source))
+          self.ninja.build(
+              output,
+              rule_name,
+              input,
+              implicit=None,  # TODO: Implemenet precompiled headers.
+              order_only=predepends)
+          outputs.append(output)
+
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
+
+      if self.toolset == 'host':
+        self.ninja.variable('ar', '$ar_host')
+        self.ninja.variable('cc', '$cc_host')
+        self.ninja.variable('cxx', '$cxx_host')
+        self.ninja.variable('ld', '$ld_host')
+
+      extra_defines = []
+      if self.flavor == 'mac':
+        cflags = self.xcode_settings.GetCflags(config_name)
+        cflags_c = self.xcode_settings.GetCflagsC(config_name)
+        cflags_cc = self.xcode_settings.GetCflagsCC(config_name)
+        cflags_objc = ['$cflags_c'] + \
+                      self.xcode_settings.GetCflagsObjC(config_name)
+        cflags_objcc = ['$cflags_cc'] + \
+                       self.xcode_settings.GetCflagsObjCC(config_name)
+      elif GetToolchainOrNone(self.flavor):
+        cflags = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflags(config_name)
+        cflags_c = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflagsC(config_name)
+        cflags_cc = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflagsCC(config_name)
+        extra_defines = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetDefines(config_name)
+        obj = 'obj'
+        if self.toolset != 'target':
+          obj += '.' + self.toolset
+        pdbpath = os.path.normpath(
+            os.path.join(obj, self.base_dir, self.name + '.pdb'))
+        self.WriteVariableList('pdbname', [pdbpath])
+        self.WriteVariableList('pchprefix', [self.name])
+      else:
+        cflags = config.get('cflags', [])
+        cflags_c = config.get('cflags_c', [])
+        cflags_cc = config.get('cflags_cc', [])
+
+      cflags_host = config.get('cflags_host', cflags)
+      cflags_c_host = config.get('cflags_c_host', cflags_c)
+      cflags_cc_host = config.get('cflags_cc_host', cflags_cc)
+
+      defines = config.get('defines', []) + extra_defines
+      if GetToolchainOrNone(self.flavor):
+        self.WriteVariableList(
+            'defines',
+            [GetToolchainOrNone(self.flavor).Define(d) for d in defines])
+      else:
+        self.WriteVariableList('defines',
+                               [Define(d, self.flavor) for d in defines])
+      if GetToolchainOrNone(self.flavor):
+        self.WriteVariableList('rcflags', [
+            QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
+            for f in GetToolchainOrNone(self.flavor).GetCompilerSettings()
+            .GetRcFlags(config_name, self.GypPathToNinja)
+        ])
+
+      include_dirs = config.get('include_dirs', [])
+      include_dirs += config.get('include_dirs_' + self.toolset, [])
+
+      if GetToolchainOrNone(self.flavor):
+        include_dirs = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().ProcessIncludeDirs(
+                include_dirs, config_name)
+        self.WriteVariableList('includes', [
+            '/I' + GetToolchainOrNone(self.flavor).QuoteForRspFile(
+                self.GypPathToNinja(i)) for i in include_dirs
+        ])
+      else:
+        self.WriteVariableList('includes', [
+            QuoteShellArgument('-I' + self.GypPathToNinja(i), self.flavor)
+            for i in include_dirs
+        ])
+
+      pch_commands = precompiled_header.GetPchBuildCommands()
+      if self.flavor == 'mac':
+        self.WriteVariableList('cflags_pch_c',
+                               [precompiled_header.GetInclude('c')])
+        self.WriteVariableList('cflags_pch_cc',
+                               [precompiled_header.GetInclude('cc')])
+        self.WriteVariableList('cflags_pch_objc',
+                               [precompiled_header.GetInclude('m')])
+        self.WriteVariableList('cflags_pch_objcc',
+                               [precompiled_header.GetInclude('mm')])
+
+      self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags))
+      self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c))
+      self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc))
+
+      self.WriteVariableList('cflags_host', map(self.ExpandSpecial,
+                                                cflags_host))
+      self.WriteVariableList('cflags_c_host',
+                             map(self.ExpandSpecial, cflags_c_host))
+      self.WriteVariableList('cflags_cc_host',
+                             map(self.ExpandSpecial, cflags_cc_host))
+
+      if self.flavor == 'mac':
+        self.WriteVariableList('cflags_objc',
+                               map(self.ExpandSpecial, cflags_objc))
+        self.WriteVariableList('cflags_objcc',
+                               map(self.ExpandSpecial, cflags_objcc))
+      self.ninja.newline()
+
+      outputs = []
+      for source in sources:
+        filename, ext = os.path.splitext(source)
+        ext = ext[1:]
+        obj_ext = self.obj_ext
+        if ext in ('cc', 'cpp', 'cxx'):
+          command = 'cxx'
+        elif ext == 'c' or (ext == 'S' and self.flavor != 'win'):
+          command = 'cc'
+        elif ext == 's' and self.flavor != 'win':  # Doesn't generate .o.d files.
+          command = 'cc_s'
+        elif (self.flavor == 'win' and ext == 'asm' and GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetArch(config_name) == 'x86' and
+              not GetToolchainOrNone(
+                  self.flavor).GetCompilerSettings().HasExplicitAsmRules(spec)):
+          # Asm files only get auto assembled for x86 (not x64).
+          command = 'asm'
+          # Add the _asm suffix as msvs is capable of handling .cc and
+          # .asm files of the same name without collision.
+          obj_ext = '_asm.obj'
+        elif self.flavor == 'mac' and ext == 'm':
+          command = 'objc'
+        elif self.flavor == 'mac' and ext == 'mm':
+          command = 'objcxx'
+        elif self.flavor in microsoft_flavors and ext == 'rc':
+          # TODO: Starboardize this.
+          command = 'rc'
+          obj_ext = '.res'
+        else:
+          # Ignore unhandled extensions.
+          continue
+        if self.toolset != 'target':
+          command += '_' + self.toolset
+
         input = self.GypPathToNinja(source)
-        output = '{0}.o'.format(self.GypPathToUniqueOutput(source))
+        output = self.GypPathToUniqueOutput(filename + obj_ext)
+        implicit = precompiled_header.GetObjDependencies([input], [output])
+        variables = []
+        if GetToolchainOrNone(self.flavor):
+          (variables, output,
+           implicit) = precompiled_header.GetFlagsModifications(
+               input, output, implicit, command, cflags_c, cflags_cc,
+               self.ExpandSpecial)
         self.ninja.build(
             output,
-            rule_name,
+            command,
             input,
-            implicit=None,  # TODO: Implemenet precompiled headers.
-            order_only=predepends)
+            implicit=[gch for _, _, gch in implicit],
+            order_only=predepends,
+            variables=variables)
         outputs.append(output)
 
+      self.WritePchTargets(pch_commands)
+
     self.ninja.newline()
     return outputs
 
+  def WritePchTargets(self, pch_commands):
+    """Writes ninja rules to compile prefix headers."""
+    if not pch_commands:
+      return
+
+    for gch, lang_flag, lang, input in pch_commands:
+      var_name = {
+          'c': 'cflags_pch_c',
+          'cc': 'cflags_pch_cc',
+          'm': 'cflags_pch_objc',
+          'mm': 'cflags_pch_objcc',
+      }[lang]
+
+      map = {
+          'c': 'cc',
+          'cc': 'cxx',
+          'm': 'objc',
+          'mm': 'objcxx',
+      }
+      cmd = map.get(lang)
+      self.ninja.build(gch, cmd, input, variables=[(var_name, lang_flag)])
+
   def WriteLink(self, spec, config_name, config, link_deps):
     """Write out a link step. Fills out target.binary. """
-    if self.toolset == 'target':
-      toolchain = GetTargetToolchain(
-          self.flavor,
-          spec=spec,
-          config_name=config_name,
-          gyp_path_to_ninja=self.GypPathToNinja,
-          expand_special=self.ExpandSpecial,
-          gyp_path_to_unique_output=self.GypPathToUniqueOutput,
-          compute_output_file_name=self.ComputeOutputFileName
-      )
-    else:
-      toolchain = GetHostToolchain(
-          self.flavor,
-          spec=spec,
-          config_name=config_name,
-          gyp_path_to_ninja=self.GypPathToNinja,
-          expand_special=self.ExpandSpecial,
-          gyp_path_to_unique_output=self.GypPathToUniqueOutput,
-          compute_output_file_name=self.ComputeOutputFileName
-      )
 
-    shell = GetShell(self.flavor)
-    extra_bindings = []
-    target_type = spec['type']
-    if target_type == 'executable':
-      executable_linker = FindFirstInstanceOf(abstract.ExecutableLinker,
-                                              toolchain)
-      assert executable_linker, ('Toolchain must provide executable linker '
-                                 'for {0} platform.').format(self.toolset)
+    try:
+      if self.toolset == 'target':
+        toolchain = GetTargetToolchain(
+            self.flavor,
+            spec=spec,
+            config_name=config_name,
+            gyp_path_to_ninja=self.GypPathToNinja,
+            expand_special=self.ExpandSpecial,
+            gyp_path_to_unique_output=self.GypPathToUniqueOutput,
+            compute_output_file_name=self.ComputeOutputFileName
+        )
+      else:
+        toolchain = GetHostToolchain(
+            self.flavor,
+            spec=spec,
+            config_name=config_name,
+            gyp_path_to_ninja=self.GypPathToNinja,
+            expand_special=self.ExpandSpecial,
+            gyp_path_to_unique_output=self.GypPathToUniqueOutput,
+            compute_output_file_name=self.ComputeOutputFileName
+        )
 
-      rule_name = GetNinjaRuleName(executable_linker, self.toolset)
+      shell = GetShell(self.flavor)
+      extra_bindings = []
+      target_type = spec['type']
+      if target_type == 'executable':
+        executable_linker = FindFirstInstanceOf(abstract.ExecutableLinker,
+                                                toolchain)
+        assert executable_linker, ('Toolchain must provide executable linker '
+                                   'for {0} platform.').format(self.toolset)
 
-      # TODO: This code emulates legacy toolchain behavior. We need to migrate
-      #       to single-responsibility, toolchain-independent GYP keywords as
-      #       per abstract toolchain design doc.
-      libraries_keyword = 'libraries{0}'.format('_host' if self.toolset ==
-                                                'host' else '')
-      libraries = spec.get(libraries_keyword, []) + config.get(
-          libraries_keyword, [])
+        rule_name = GetNinjaRuleName(executable_linker, self.toolset)
 
-      ldflags_executable = GetConfigFlags(
-          config, self.toolset, 'ldflags_executable')
-      if not ldflags_executable:
-        ldflags_executable = GetConfigFlags(config, self.toolset, 'ldflags')
+        # TODO: This code emulates legacy toolchain behavior. We need to migrate
+        #       to single-responsibility, toolchain-independent GYP keywords as
+        #       per abstract toolchain design doc.
+        libraries_keyword = 'libraries{0}'.format('_host' if self.toolset ==
+                                                  'host' else '')
+        libraries = spec.get(libraries_keyword, []) + config.get(
+            libraries_keyword, [])
 
-      ldflags = gyp.common.uniquer(
-          map(self.ExpandSpecial, ldflags_executable + libraries))
+        ldflags_executable = GetConfigFlags(
+            config, self.toolset, 'ldflags_executable')
+        if not ldflags_executable:
+          ldflags_executable = GetConfigFlags(config, self.toolset, 'ldflags')
 
-      executable_linker_flags = executable_linker.GetFlags(ldflags)
-      self.ninja.variable('{0}_flags'.format(rule_name),
-                          shell.Join(executable_linker_flags))
-    elif target_type == 'shared_library':
-      shared_library_linker = FindFirstInstanceOf(
-          abstract.SharedLibraryLinker, toolchain)
-      assert shared_library_linker, (
-          'Toolchain must provide shared library linker '
-          'for {0} platform.').format(self.toolset)
+        ldflags = gyp.common.uniquer(
+            map(self.ExpandSpecial, ldflags_executable + libraries))
 
-      rule_name = GetNinjaRuleName(shared_library_linker, self.toolset)
+        executable_linker_flags = executable_linker.GetFlags(ldflags)
+        self.ninja.variable('{0}_flags'.format(rule_name),
+                            shell.Join(executable_linker_flags))
+      elif target_type == 'shared_library':
+        shared_library_linker = FindFirstInstanceOf(
+            abstract.SharedLibraryLinker, toolchain)
+        assert shared_library_linker, (
+            'Toolchain must provide shared library linker '
+            'for {0} platform.').format(self.toolset)
 
-      # TODO: This code emulates legacy toolchain behavior. We need to migrate
-      #       to single-responsibility, toolchain-independent GYP keywords as
-      #       per abstract toolchain design doc.
-      libraries_keyword = 'libraries{0}'.format('_host' if self.toolset ==
-                                                'host' else '')
-      libraries = spec.get(libraries_keyword, []) + config.get(
-          libraries_keyword, [])
+        rule_name = GetNinjaRuleName(shared_library_linker, self.toolset)
 
-      ldflags_shared = GetConfigFlags(config, self.toolset, 'ldflags_shared')
-      if not ldflags_shared:
-        ldflags_shared = GetConfigFlags(config, self.toolset, 'ldflags')
+        # TODO: This code emulates legacy toolchain behavior. We need to migrate
+        #       to single-responsibility, toolchain-independent GYP keywords as
+        #       per abstract toolchain design doc.
+        libraries_keyword = 'libraries{0}'.format('_host' if self.toolset ==
+                                                  'host' else '')
+        libraries = spec.get(libraries_keyword, []) + config.get(
+            libraries_keyword, [])
 
-      ldflags = gyp.common.uniquer(
-          map(self.ExpandSpecial, ldflags_shared + libraries))
+        ldflags_shared = GetConfigFlags(config, self.toolset, 'ldflags_shared')
+        if not ldflags_shared:
+          ldflags_shared = GetConfigFlags(config, self.toolset, 'ldflags')
 
-      shared_library_linker_flags = shared_library_linker.GetFlags(ldflags)
-      self.ninja.variable('{0}_flags'.format(rule_name),
-                          shell.Join(shared_library_linker_flags))
+        ldflags = gyp.common.uniquer(
+            map(self.ExpandSpecial, ldflags_shared + libraries))
+
+        shared_library_linker_flags = shared_library_linker.GetFlags(ldflags)
+        self.ninja.variable('{0}_flags'.format(rule_name),
+                            shell.Join(shared_library_linker_flags))
+        output = self.ComputeOutput(spec)
+        extra_bindings.append(('soname', os.path.split(output)[1]))
+        extra_bindings.append(('dll', output))
+        if '/NOENTRY' not in shared_library_linker_flags:
+          extra_bindings.append(('implibflag',
+                                 '/IMPLIB:%s' % output + '.lib'))
+
+      else:
+        raise Exception('Target type {0} is not supported for target {1}.'
+                        .format(target_type, spec['target_name']))
+
+      order_only_deps = set()
+
+      if 'dependencies' in spec:
+        # Two kinds of dependencies:
+        # - Linkable dependencies (like a .a or a .so): add them to the link
+        #   line.
+        # - Non-linkable dependencies (like a rule that generates a file
+        #   and writes a stamp file): add them to implicit_deps or
+        #   order_only_deps
+        extra_link_deps = []
+        for dep in spec['dependencies']:
+          target = self.target_outputs.get(dep)
+          if not target:
+            continue
+          linkable = target.Linkable()
+          if linkable:
+            extra_link_deps.append(target.binary)
+
+          final_output = target.FinalOutput()
+          if not linkable or final_output != target.binary:
+            order_only_deps.add(final_output)
+
+        # dedup the extra link deps while preserving order
+        seen = set()
+        extra_link_deps = [
+            x for x in extra_link_deps if x not in seen and not seen.add(x)
+        ]
+
+        link_deps.extend(extra_link_deps)
+
+      tail_deps = GetConfigFlags(config, self.toolset, 'TailDependencies')
+      if tail_deps:
+        link_deps.extend(map(self.ExpandSpecial, tail_deps))
+
       output = self.ComputeOutput(spec)
-      extra_bindings.append(('soname', os.path.split(output)[1]))
-      extra_bindings.append(('dll', output))
-      if '/NOENTRY' not in shared_library_linker_flags:
-        extra_bindings.append(('implibflag',
-                               '/IMPLIB:%s' % output + '.lib'))
+      self.target.binary = output
 
-    else:
-      raise Exception('Target type {0} is not supported for target {1}.'
-                      .format(target_type, spec['target_name']))
+      self.ninja.build(
+          output,
+          rule_name,
+          link_deps,
+          order_only=list(order_only_deps),
+          variables=extra_bindings)
 
-    order_only_deps = set()
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
 
-    if 'dependencies' in spec:
-      # Two kinds of dependencies:
-      # - Linkable dependencies (like a .a or a .so): add them to the link
-      #   line.
-      # - Non-linkable dependencies (like a rule that generates a file
-      #   and writes a stamp file): add them to implicit_deps or
-      #   order_only_deps
-      extra_link_deps = []
-      for dep in spec['dependencies']:
-        target = self.target_outputs.get(dep)
-        if not target:
-          continue
-        linkable = target.Linkable()
-        if linkable:
-          extra_link_deps.append(target.binary)
+      command = {
+          'executable': 'link',
+          'loadable_module': 'solink_module',
+          'shared_library': 'solink',
+      }[spec['type']]
 
-        final_output = target.FinalOutput()
-        if not linkable or final_output != target.binary:
-          order_only_deps.add(final_output)
+      implicit_deps = set()
+      order_only_deps = set()
+      solibs = set()
 
-      # dedup the extra link deps while preserving order
-      seen = set()
-      extra_link_deps = [
-          x for x in extra_link_deps if x not in seen and not seen.add(x)
-      ]
+      if 'dependencies' in spec:
+        # Two kinds of dependencies:
+        # - Linkable dependencies (like a .a or a .so): add them to the link
+        #   line.
+        # - Non-linkable dependencies (like a rule that generates a file
+        #   and writes a stamp file): add them to implicit_deps or
+        #   order_only_deps
+        extra_link_deps = []
+        for dep in spec['dependencies']:
+          target = self.target_outputs.get(dep)
+          if not target:
+            continue
+          linkable = target.Linkable()
+          # TODO: Starboardize.
+          if linkable:
+            if (self.flavor in microsoft_flavors and target.component_objs and
+                GetToolchainOrNone(self.flavor).GetCompilerSettings()
+                .IsUseLibraryDependencyInputs(config_name)):
+              extra_link_deps.extend(target.component_objs)
+            elif (self.flavor in microsoft_flavors and
+                  target.import_lib):
+              extra_link_deps.append(target.import_lib)
+            elif target.UsesToc(self.flavor):
+              solibs.add(target.binary)
+              implicit_deps.add(target.binary + '.TOC')
+            else:
+              extra_link_deps.append(target.binary)
 
-      link_deps.extend(extra_link_deps)
+          final_output = target.FinalOutput()
+          if not linkable or final_output != target.binary:
+            order_only_deps.add(final_output)
 
-    tail_deps = GetConfigFlags(config, self.toolset, 'TailDependencies')
-    if tail_deps:
-      link_deps.extend(map(self.ExpandSpecial, tail_deps))
+        # dedup the extra link deps while preserving order
+        seen = set()
+        extra_link_deps = [
+            x for x in extra_link_deps if x not in seen and not seen.add(x)
+        ]
 
-    output = self.ComputeOutput(spec)
-    self.target.binary = output
+        link_deps.extend(extra_link_deps)
 
-    self.ninja.build(
-        output,
-        rule_name,
-        link_deps,
-        order_only=list(order_only_deps),
-        variables=extra_bindings)
+      extra_bindings = []
+      if self.is_mac_bundle:
+        output = self.ComputeMacBundleBinaryOutput()
+      else:
+        output = self.ComputeOutput(spec)
+        extra_bindings.append(('postbuilds',
+                               self.GetPostbuildCommand(spec, output, output)))
+
+      if self.flavor == 'mac':
+        ldflags = self.xcode_settings.GetLdflags(
+            config_name,
+            self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+            self.GypPathToNinja)
+      elif GetToolchainOrNone(self.flavor):
+        libflags = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetLibFlags(
+                config_name, self.GypPathToNinja)
+        self.WriteVariableList(
+            'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags)))
+        is_executable = spec['type'] == 'executable'
+        manifest_name = self.GypPathToUniqueOutput(
+            self.ComputeOutputFileName(spec))
+        ldflags, manifest_files = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetLdFlags(
+                config_name, **{
+                    'gyp_path_to_ninja': self.GypPathToNinja,
+                    'expand_special': self.ExpandSpecial,
+                    'manifest_name': manifest_name,
+                    'is_executable': is_executable
+                })
+        self.WriteVariableList('manifests', manifest_files)
+      else:
+        ldflags = config.get('ldflags', [])
+        ldflags_host = config.get('ldflags_host', ldflags)
+
+      self.WriteVariableList(
+          'ldflags', gyp.common.uniquer(map(self.ExpandSpecial, ldflags)))
+      if ('ldflags_host' in locals()):
+        self.WriteVariableList(
+            'ldflags_host',
+            gyp.common.uniquer(map(self.ExpandSpecial, ldflags_host)))
+
+      if self.toolset == 'host':
+        libs = spec.get('libraries_host', [])
+        libs.extend(config.get('libraries_host', []))
+      else:
+        libs = spec.get('libraries', [])
+        libs.extend(config.get('libraries', []))
+
+      libraries = gyp.common.uniquer(map(self.ExpandSpecial, libs))
+
+      if self.flavor == 'mac':
+        libraries = self.xcode_settings.AdjustLibraries(libraries)
+      elif GetToolchainOrNone(self.flavor):
+        libraries = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().ProcessLibraries(libraries)
+      self.WriteVariableList('libs', libraries)
+
+      self.target.binary = output
+
+      if command in ('solink', 'solink_module'):
+        extra_bindings.append(('soname', os.path.split(output)[1]))
+        extra_bindings.append(('lib',
+                               gyp.common.EncodePOSIXShellArgument(output)))
+        # TODO: Starboardize.
+        if self.flavor in microsoft_flavors:
+          extra_bindings.append(('dll', output))
+          if '/NOENTRY' not in ldflags:
+            self.target.import_lib = output + '.lib'
+            extra_bindings.append(('implibflag',
+                                   '/IMPLIB:%s' % self.target.import_lib))
+            output = [output, self.target.import_lib]
+        else:
+          output = [output, output + '.TOC']
+
+      if len(solibs):
+        extra_bindings.append(('solibs',
+                               gyp.common.EncodePOSIXShellList(solibs)))
+
+      if self.toolset != 'target':
+        command += '_' + self.toolset
+
+      self.ninja.build(
+          output,
+          command,
+          link_deps,
+          implicit=list(implicit_deps),
+          order_only=list(order_only_deps),
+          variables=extra_bindings)
 
   def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
     if spec['type'] == 'none':
@@ -1139,37 +1494,62 @@
       self.target.binary = self.ComputeOutput(spec)
       variables = []
 
-      if self.toolset == 'target':
-        toolchain = GetTargetToolchain(
-            self.flavor,
-            spec=spec,
-            config_name=config_name,
-            gyp_path_to_ninja=self.GypPathToNinja
-        )
-      else:
-        toolchain = GetHostToolchain(
-            self.flavor,
-            spec=spec,
-            config_name=config_name,
-            gyp_path_to_ninja=self.GypPathToNinja
-        )
+      try:
+        if self.toolset == 'target':
+          toolchain = GetTargetToolchain(
+              self.flavor,
+              spec=spec,
+              config_name=config_name,
+              gyp_path_to_ninja=self.GypPathToNinja
+          )
+        else:
+          toolchain = GetHostToolchain(
+              self.flavor,
+              spec=spec,
+              config_name=config_name,
+              gyp_path_to_ninja=self.GypPathToNinja
+          )
 
-      shell = GetShell(self.flavor)
-      static_linker = FindFirstInstanceOf(abstract.StaticLinker, toolchain)
-      if not self.is_standalone_static_library:
-        static_thin_linker = FindFirstInstanceOf(abstract.StaticThinLinker,
-                                                 toolchain)
-        if static_thin_linker:
-          static_linker = static_thin_linker
-      assert static_linker, ('Toolchain must provide static linker in order '
-                             'to build {0} for {1} platform.').format(
-                                 self.target.binary, self.toolset)
+        shell = GetShell(self.flavor)
+        static_linker = FindFirstInstanceOf(abstract.StaticLinker, toolchain)
+        if not self.is_standalone_static_library:
+          static_thin_linker = FindFirstInstanceOf(abstract.StaticThinLinker,
+                                                   toolchain)
+          if static_thin_linker:
+            static_linker = static_thin_linker
+        assert static_linker, ('Toolchain must provide static linker in order '
+                               'to build {0} for {1} platform.').format(
+                                   self.target.binary, self.toolset)
 
-      rule_name = GetNinjaRuleName(static_linker, self.toolset)
+        rule_name = GetNinjaRuleName(static_linker, self.toolset)
 
-      static_linker_flags = static_linker.GetFlags()
-      self.ninja.variable('{0}_flags'.format(rule_name),
-                          shell.Join(static_linker_flags))
+        static_linker_flags = static_linker.GetFlags()
+        self.ninja.variable('{0}_flags'.format(rule_name),
+                            shell.Join(static_linker_flags))
+      except NotImplementedError:
+        # Fall back to the legacy toolchain.
+
+        if GetToolchainOrNone(self.flavor):
+          libflags = GetToolchainOrNone(
+              self.flavor).GetCompilerSettings().GetLibFlags(
+                  config_name, self.GypPathToNinja)
+          # TODO: Starboardize libflags vs libtool_flags.
+          variables.append(('libflags', ' '.join(libflags)))
+        postbuild = self.GetPostbuildCommand(spec, self.target.binary,
+                                             self.target.binary)
+        if postbuild:
+          variables.append(('postbuilds', postbuild))
+        if self.xcode_settings:
+          variables.append(('libtool_flags',
+                            self.xcode_settings.GetLibtoolflags(config_name)))
+        # TODO: Starboardize.
+        if (self.flavor not in (['mac'] + microsoft_flavors) and
+            not self.is_standalone_static_library):
+          rule_name = 'alink_thin'
+        else:
+          rule_name = 'alink'
+        if self.toolset != 'target':
+          rule_name += '_' + self.toolset
 
       self.ninja.build(
           self.target.binary,
@@ -1280,6 +1660,12 @@
     path = self.ExpandSpecial(generator_default_variables['PRODUCT_DIR'])
     return os.path.join(path, self.xcode_settings.GetWrapperName())
 
+  def ComputeMacBundleBinaryOutput(self):
+    """Return the 'output' (full output path) to the binary in a bundle."""
+    assert self.is_mac_bundle
+    path = self.ExpandSpecial(generator_default_variables['PRODUCT_DIR'])
+    return os.path.join(path, self.xcode_settings.GetExecutablePath())
+
   def ComputeOutputFileName(self, spec, type=None):
     """Compute the filename of the final output for the current target."""
     if not type:
@@ -1550,6 +1936,62 @@
     pass
   return open(path, mode)
 
+
+def GetDefaultConcurrentLinks():
+  """Returns a best-guess for a number of concurrent links."""
+  pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0))
+  if pool_size:
+    return pool_size
+
+  if sys.platform in ('win32', 'cygwin'):
+    import ctypes
+
+    class MEMORYSTATUSEX(ctypes.Structure):
+      _fields_ = [
+          ('dwLength', ctypes.c_ulong),
+          ('dwMemoryLoad', ctypes.c_ulong),
+          ('ullTotalPhys', ctypes.c_ulonglong),
+          ('ullAvailPhys', ctypes.c_ulonglong),
+          ('ullTotalPageFile', ctypes.c_ulonglong),
+          ('ullAvailPageFile', ctypes.c_ulonglong),
+          ('ullTotalVirtual', ctypes.c_ulonglong),
+          ('ullAvailVirtual', ctypes.c_ulonglong),
+          ('sullAvailExtendedVirtual', ctypes.c_ulonglong),
+      ]
+
+    stat = MEMORYSTATUSEX()
+    stat.dwLength = ctypes.sizeof(stat)
+    ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
+
+    # VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
+    # on a 64 GB machine.
+    mem_limit = max(1, stat.ullTotalPhys / (5 * (2**30)))  # total / 5GB
+    hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
+    return min(mem_limit, hard_cap)
+  elif sys.platform.startswith('linux'):
+    if os.path.exists('/proc/meminfo'):
+      with open('/proc/meminfo') as meminfo:
+        memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
+        for line in meminfo:
+          match = memtotal_re.match(line)
+          if not match:
+            continue
+          # Allow 6Gb per link on Linux because Gold is quite memory hungry
+          return max(1, int(match.group(1)) / (6 * (2**20)))
+    return 1
+  elif sys.platform == 'darwin':
+    try:
+      avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
+      # A static library debug build of Chromium's unit_tests takes ~2.7GB, so
+      # 4GB per ld process allows for some more bloat.
+      return max(1, avail_bytes / (4 * (2**30)))  # total / 4GB
+    except:
+      return 1
+  else:
+    # TODO(scottmg): Implement this for other platforms.
+    return 1
+
+
 def MaybeWritePathVariable(ninja, tool, toolset):
   if tool.GetPath():
     ninja.variable('{0}_path'.format(GetNinjaRuleName(tool, toolset)),
@@ -1611,53 +2053,609 @@
   build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
   make_global_settings = data[build_file].get('make_global_settings', [])
 
-  # To avoid duplication, platform-agnostic tools (such as stamp and copy)
-  # will be processed only in the host toolchain.
-  target_toolchain = [
-      target_tool for target_tool in GetTargetToolchain(flavor)
-      if not target_tool.IsPlatformAgnostic()
-  ]
-  host_toolchain = GetHostToolchain(flavor)
+  try:
+    # To avoid duplication, platform-agnostic tools (such as stamp and copy)
+    # will be processed only in the host toolchain.
+    target_toolchain = [
+        target_tool for target_tool in GetTargetToolchain(flavor)
+        if not target_tool.IsPlatformAgnostic()
+    ]
+    host_toolchain = GetHostToolchain(flavor)
 
-  shell = GetShell(flavor)
+    shell = GetShell(flavor)
 
-  for target_tool in target_toolchain:
-    MaybeWritePathVariable(master_ninja, target_tool, 'target')
-  for host_tool in host_toolchain:
-    MaybeWritePathVariable(master_ninja, host_tool, 'host')
-  master_ninja.newline()
+    for target_tool in target_toolchain:
+      MaybeWritePathVariable(master_ninja, target_tool, 'target')
+    for host_tool in host_toolchain:
+      MaybeWritePathVariable(master_ninja, host_tool, 'host')
+    master_ninja.newline()
 
-  for target_tool in target_toolchain:
-    MaybeWriteExtraFlagsVariable(master_ninja, target_tool, 'target', shell)
-  for host_tool in host_toolchain:
-    MaybeWriteExtraFlagsVariable(master_ninja, host_tool, 'host', shell)
-  master_ninja.newline()
+    for target_tool in target_toolchain:
+      MaybeWriteExtraFlagsVariable(master_ninja, target_tool, 'target', shell)
+    for host_tool in host_toolchain:
+      MaybeWriteExtraFlagsVariable(master_ninja, host_tool, 'host', shell)
+    master_ninja.newline()
 
-  for target_tool in target_toolchain:
-    MaybeWritePool(master_ninja, target_tool, 'target')
-  for host_tool in host_toolchain:
-    MaybeWritePool(master_ninja, host_tool, 'host')
-  master_ninja.newline()
+    for target_tool in target_toolchain:
+      MaybeWritePool(master_ninja, target_tool, 'target')
+    for host_tool in host_toolchain:
+      MaybeWritePool(master_ninja, host_tool, 'host')
+    master_ninja.newline()
 
-  for target_tool in target_toolchain:
-    MaybeWriteRule(master_ninja, target_tool, 'target', shell)
-  for host_tool in host_toolchain:
-    MaybeWriteRule(master_ninja, host_tool, 'host', shell)
-  master_ninja.newline()
+    for target_tool in target_toolchain:
+      MaybeWriteRule(master_ninja, target_tool, 'target', shell)
+    for host_tool in host_toolchain:
+      MaybeWriteRule(master_ninja, host_tool, 'host', shell)
+    master_ninja.newline()
 
-  # Copy the gyp-win-tool to the toplevel_build.
-  # Also write python to the master_ninja.
-  if is_windows:
+    # Copy the gyp-win-tool to the toplevel_build.
+    # Also write python to the master_ninja.
+    if is_windows:
+      gyp.common.CopyTool(flavor, toplevel_build)
+      if GetToolchainOrNone(flavor):
+        GetToolchainOrNone(flavor).GenerateEnvironmentFiles(
+            toplevel_build, generator_flags, OpenOutput)
+      else:
+        gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build,
+            generator_flags, OpenOutput)
+      master_ninja.variable('python', sys.executable)
+      master_ninja.newline()
+
+  except NotImplementedError:
+    # Fall back to the legacy toolchain.
+
+    # Put build-time support tools in out/{config_name}.
     gyp.common.CopyTool(flavor, toplevel_build)
-    if GetToolchainOrNone(flavor):
+
+    # Grab make settings for CC/CXX.
+    # The rules are
+    # - The priority from low to high is gcc/g++, the 'make_global_settings' in
+    #   gyp, the environment variable.
+    # - If there is no 'make_global_settings' for CC.host/CXX.host or
+    #   'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
+    #   to cc/cxx.
+    if (flavor in sony_flavors and is_windows):
+      cc = 'cl.exe'
+      cxx = 'cl.exe'
+      ld = 'link.exe'
+      gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build,
+                                                  generator_flags, OpenOutput)
+      ld_host = '$ld'
+    elif GetToolchainOrNone(flavor):
+      # TODO: starboardize.
+      cc = 'cl.exe'
+      cxx = 'cl.exe'
+      ld = 'link.exe'
       GetToolchainOrNone(flavor).GenerateEnvironmentFiles(
           toplevel_build, generator_flags, OpenOutput)
+      ld_host = '$ld'
     else:
-      gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build,
-          generator_flags, OpenOutput)
-    master_ninja.variable('python', sys.executable)
+      cc = 'gcc'
+      cxx = 'g++'
+      ld = '$cxx'
+      ld_host = '$cxx_host'
+
+    cc_host = None
+    cxx_host = None
+    cc_host_global_setting = None
+    cxx_host_global_setting = None
+
+    build_to_root = InvertRelativePath(build_dir)
+    for key, value in make_global_settings:
+      if key == 'CC':
+        cc = os.path.join(build_to_root, value)
+      if key == 'CXX':
+        cxx = os.path.join(build_to_root, value)
+      if key == 'LD':
+        ld = os.path.join(build_to_root, value)
+      if key == 'CC.host':
+        cc_host = os.path.join(build_to_root, value)
+        cc_host_global_setting = value
+      if key == 'CXX.host':
+        cxx_host = os.path.join(build_to_root, value)
+        cxx_host_global_setting = value
+      if key == 'LD.host':
+        ld_host = os.path.join(build_to_root, value)
+
+    flock = 'flock'
+    if flavor == 'mac':
+      flock = './gyp-mac-tool flock'
+    cc = GetEnvironFallback(['CC_target', 'CC'], cc)
+    master_ninja.variable('cc', cc)
+    cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
+    master_ninja.variable('cxx', cxx)
+    ld = GetEnvironFallback(['LD_target', 'LD'], ld)
+    rc = GetEnvironFallback(['RC'], 'rc.exe')
+
+    if not cc_host:
+      cc_host = cc
+    if not cxx_host:
+      cxx_host = cxx
+
+    # gyp-win-tool wrappers have a winpython only flock implementation.
+    if sys.platform == 'cygwin':
+      python_exec = '$python'
+    else:
+      python_exec = sys.executable
+
+    ar_flags = ''
+    if flavor in microsoft_flavors:
+      master_ninja.variable('ld', ld)
+      master_ninja.variable('ar', os.environ.get('AR', 'ar'))
+      master_ninja.variable('rc', rc)
+      master_ninja.variable('asm', 'ml.exe')
+      master_ninja.variable('mt', 'mt.exe')
+      master_ninja.variable('use_dep_database', '1')
+    elif flavor in sony_flavors:
+      # Require LD to be set.
+      master_ninja.variable('ld', os.environ.get('LD'))
+      master_ninja.variable('ar', os.environ.get('AR', 'ar'))
+      ar_flags = os.environ.get('ARFLAGS', 'rcs')
+      master_ninja.variable('arFlags', ar_flags)
+      # On Sony, when we use orbis-snarl.exe with a response file, we cannot
+      # pass it flags (like 'rcs'), so ARFLAGS is likely set to '' for this
+      # platform.  In that case, do not append the thin archive 'T' flag
+      # to the flags string.
+      thin_flag_to_add = ''
+      if len(ar_flags) >= 1 and ar_flags.find('T') == -1:
+        thin_flag_to_add = 'T'
+      master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
+
+    else:
+      master_ninja.variable('ld', ld)
+      master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
+      ar_flags = os.environ.get('ARFLAGS', 'rcs')
+      master_ninja.variable('arFlags', ar_flags)
+      thin_flag_to_add = ''
+      if ar_flags.find('T') == -1:
+        thin_flag_to_add = 'T'
+      master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
+    master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
+    cc_host = GetEnvironFallback(['CC_host'], cc_host)
+    cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
+    ld_host = GetEnvironFallback(['LD_host'], ld_host)
+    arflags_host = GetEnvironFallback(['ARFLAGS_host'], ar_flags)
+    arthinflags_host = GetEnvironFallback(['ARTHINFLAGS_host'], arflags_host)
+
+    # The environment variable could be used in 'make_global_settings', like
+    # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
+    if '$(CC)' in cc_host and cc_host_global_setting:
+      cc_host = cc_host_global_setting.replace('$(CC)', cc)
+    if '$(CXX)' in cxx_host and cxx_host_global_setting:
+      cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
+    master_ninja.variable('cc_host', cc_host)
+    master_ninja.variable('cxx_host', cxx_host)
+    master_ninja.variable('arFlags_host', arflags_host)
+    master_ninja.variable('arThinFlags_host', arthinflags_host)
+    master_ninja.variable('ld_host', ld_host)
+
+    if sys.platform == 'cygwin':
+      python_path = cygpath.to_nt(
+          '/cygdrive/c/python_27_amd64/files/python.exe')
+    else:
+      python_path = 'python'
+    master_ninja.variable('python', python_path)
     master_ninja.newline()
 
+    master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
+    master_ninja.newline()
+
+    if flavor not in microsoft_flavors:
+      if flavor in sony_flavors:
+        # uca := Unnamed Console A
+        dep_format = 'uca'
+        master_ninja.rule(
+            'cc',
+            description='CC $out',
+            command=('$cc @$out.rsp'),
+            rspfile='$out.rsp',
+            rspfile_content=('-c $in -o $out '
+                             '-MMD $defines $includes $cflags $cflags_c '
+                             '$cflags_pch_c'),
+            depfile='$out_no_ext.d',
+            deps='gcc',
+            depformat=dep_format)
+        master_ninja.rule(
+            'cxx',
+            description='CXX $out',
+            command=('$cxx @$out.rsp'),
+            rspfile='$out.rsp',
+            rspfile_content=('-c $in -o $out '
+                             '-MMD $defines $includes $cflags $cflags_cc '
+                             '$cflags_pch_cc'),
+            depfile='$out_no_ext.d',
+            deps='gcc',
+            depformat=dep_format)
+      else:
+        master_ninja.rule(
+            'cc',
+            description='CC $out',
+            command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
+                     '$cflags_pch_c -c $in -o $out'),
+            deps='gcc',
+            depfile='$out.d')
+        master_ninja.rule(
+            'cc_s',
+            description='CC $out',
+            command=('$cc $defines $includes $cflags $cflags_c '
+                     '$cflags_pch_c -c $in -o $out'))
+        master_ninja.rule(
+            'cxx',
+            description='CXX $out',
+            command=(
+                '$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
+                '$cflags_pch_cc -c $in -o $out'),
+            deps='gcc',
+            depfile='$out.d')
+
+    else:
+      cc_command = ('$cc /nologo /showIncludes /FC '
+                    '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      cxx_command = ('$cxx /nologo /showIncludes /FC '
+                     '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      master_ninja.rule(
+          'cc',
+          description='CC $out',
+          command=cc_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags $cflags_c')
+      master_ninja.rule(
+          'cxx',
+          description='CXX $out',
+          command=cxx_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags $cflags_cc')
+
+      master_ninja.rule(
+          'rc',
+          description='RC $in',
+          # Note: $in must be last otherwise rc.exe complains.
+          command=('%s gyp-win-tool rc-wrapper '
+                   '$arch $rc $defines $includes $rcflags /fo$out $in' %
+                   python_exec))
+      master_ninja.rule(
+          'asm',
+          description='ASM $in',
+          command=(
+              '%s gyp-win-tool asm-wrapper '
+              '$arch $asm $defines $includes /c /Fo $out $in' % python_exec))
+
+    if flavor not in (['mac'] + microsoft_flavors):
+      alink_command = 'rm -f $out && $ar $arFlags $out @$out.rsp'
+      # TODO: Use rcsT on Linux only.
+      alink_thin_command = 'rm -f $out && $ar $arThinFlags $out @$out.rsp'
+
+      ld_cmd = '$ld'
+
+      if flavor in sony_flavors and is_windows:
+        alink_command = 'cmd.exe /c ' + alink_command
+        alink_thin_command = 'cmd.exe /c ' + alink_thin_command
+        ld_cmd = '%s gyp-win-tool link-wrapper $arch $ld' % python_exec
+
+      master_ninja.rule(
+          'alink',
+          description='AR $out',
+          command=alink_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      master_ninja.rule(
+          'alink_thin',
+          description='AR $out',
+          command=alink_thin_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+
+      # This allows targets that only need to depend on $lib's API to declare
+      # an order-only dependency on $lib.TOC and avoid relinking such
+      # downstream dependencies when $lib changes only in non-public ways.
+      # The resulting string leaves an uninterpolated %{suffix} which
+      # is used in the final substitution below.
+      mtime_preserving_solink_base = (
+          'if [ ! -e $lib -o ! -e ${lib}.TOC ]; then %(solink)s && '
+          '%(extract_toc)s > ${lib}.TOC; else %(solink)s && %(extract_toc)s '
+          '> ${lib}.tmp && if ! cmp -s ${lib}.tmp ${lib}.TOC; then mv '
+          '${lib}.tmp ${lib}.TOC ; fi; fi' % {
+              'solink': (
+                  ld_cmd +
+                  ' -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s'),
+              'extract_toc': ('{ readelf -d ${lib} | grep SONAME ; '
+                              'nm -gD -f p ${lib} | cut -f1-2 -d\' \'; }')
+          })
+
+      master_ninja.rule(
+          'solink',
+          description='SOLINK $lib',
+          restat=True,
+          command=(mtime_preserving_solink_base % {
+              'suffix':
+                  '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive '
+                  '$libs'
+          }))
+      master_ninja.rule(
+          'solink_module',
+          description='SOLINK(module) $lib',
+          restat=True,
+          command=(mtime_preserving_solink_base % {
+              'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'
+          }))
+
+      if flavor in sony_flavors:
+        # Sony linkers don't know about rpath.
+        rpath = ''
+      else:
+        rpath = r'-Wl,-rpath=\$$ORIGIN/lib'
+
+      master_ninja.rule(
+          'link',
+          description='LINK $out',
+          command=(ld_cmd + ' @$out.rsp'),
+          rspfile='$out.rsp',
+          rspfile_content=('$ldflags -o $out %s -Wl,--start-group $in $solibs '
+                           '-Wl,--end-group $libs' % rpath),
+          pool='link_pool')
+    elif flavor in microsoft_flavors:
+      master_ninja.rule(
+          'alink',
+          description='LIB $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags')
+      dlldesc = 'LINK(DLL) $dll'
+      dllcmd = ('%s gyp-win-tool link-wrapper $arch '
+                '$ld /nologo $implibflag /DLL /OUT:$dll '
+                '/PDB:$dll.pdb @$dll.rsp' % python_exec)
+      if not flavor in microsoft_flavors:
+        # XB1 doesn't need a manifest.
+        dllcmd += (
+            ' && %s gyp-win-tool manifest-wrapper $arch '
+            '$mt -nologo -manifest $manifests -out:$dll.manifest' % python_exec)
+      master_ninja.rule(
+          'solink',
+          description=dlldesc,
+          command=dllcmd,
+          rspfile='$dll.rsp',
+          rspfile_content='$libs $in_newline $ldflags',
+          restat=True)
+      master_ninja.rule(
+          'solink_module',
+          description=dlldesc,
+          command=dllcmd,
+          rspfile='$dll.rsp',
+          rspfile_content='$libs $in_newline $ldflags',
+          restat=True)
+      # Note that ldflags goes at the end so that it has the option of
+      # overriding default settings earlier in the command line.
+      if flavor == 'win':
+        link_command = ('%s gyp-win-tool link-wrapper $arch '
+                        '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
+                        '%s gyp-win-tool manifest-wrapper $arch '
+                        '$mt -nologo -manifest $manifests -out:$out.manifest' %
+                        (python_exec, python_exec))
+      else:
+        assert flavor in microsoft_flavors
+        # XB1 doesn't need a manifest.
+        link_command = (
+            '%s gyp-win-tool link-wrapper $arch '
+            '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' % (python_exec))
+
+      master_ninja.rule(
+          'link',
+          description='LINK $out',
+          command=link_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libs $ldflags',
+          pool='link_pool')
+    else:
+      master_ninja.rule(
+          'objc',
+          description='OBJC $out',
+          command=(
+              '$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc '
+              '$cflags_pch_objc -c $in -o $out'),
+          depfile='$out.d')
+      master_ninja.rule(
+          'objcxx',
+          description='OBJCXX $out',
+          command=(
+              '$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc '
+              '$cflags_pch_objcc -c $in -o $out'),
+          depfile='$out.d')
+      master_ninja.rule(
+          'alink',
+          description='LIBTOOL-STATIC $out, POSTBUILDS',
+          command='rm -f $out && '
+          './gyp-mac-tool filter-libtool libtool $libtool_flags '
+          '-static -o $out $in'
+          '$postbuilds')
+
+      # Record the public interface of $lib in $lib.TOC. See the corresponding
+      # comment in the posix section above for details.
+      mtime_preserving_solink_base = (
+          'if [ ! -e $lib -o ! -e ${lib}.TOC ] || '
+          # Always force dependent targets to relink if this library
+          # reexports something. Handling this correctly would require
+          # recursive TOC dumping but this is rare in practice, so punt.
+          'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then '
+          '%(solink)s && %(extract_toc)s > ${lib}.TOC; '
+          'else '
+          '%(solink)s && %(extract_toc)s > ${lib}.tmp && '
+          'if ! cmp -s ${lib}.tmp ${lib}.TOC; then '
+          'mv ${lib}.tmp ${lib}.TOC ; '
+          'fi; '
+          'fi' % {
+              'solink': '$ld -shared $ldflags -o $lib %(suffix)s',
+              'extract_toc':
+                  '{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
+                  'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'
+          })
+
+      # TODO(thakis): The solink_module rule is likely wrong. Xcode seems to
+      # pass -bundle -single_module here (for osmesa.so).
+      master_ninja.rule(
+          'solink',
+          description='SOLINK $lib, POSTBUILDS',
+          restat=True,
+          command=(mtime_preserving_solink_base % {
+              'suffix': '$in $solibs $libs$postbuilds'
+          }))
+      master_ninja.rule(
+          'solink_module',
+          description='SOLINK(module) $lib, POSTBUILDS',
+          restat=True,
+          command=(mtime_preserving_solink_base % {
+              'suffix': '$in $solibs $libs$postbuilds'
+          }))
+
+      master_ninja.rule(
+          'link',
+          description='LINK $out, POSTBUILDS',
+          command=('$ld $ldflags -o $out '
+                   '$in $solibs $libs$postbuilds'),
+          pool='link_pool')
+      master_ninja.rule(
+          'infoplist',
+          description='INFOPLIST $out',
+          command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && '
+                   'plutil -convert xml1 $out $out'))
+      master_ninja.rule(
+          'mac_tool',
+          description='MACTOOL $mactool_cmd $in',
+          command='$env ./gyp-mac-tool $mactool_cmd $in $out')
+      master_ninja.rule(
+          'package_framework',
+          description='PACKAGE FRAMEWORK $out, POSTBUILDS',
+          command='./gyp-mac-tool package-framework $out $version$postbuilds '
+          '&& touch $out')
+    if flavor in microsoft_flavors:
+      master_ninja.rule(
+          'stamp',
+          description='STAMP $out',
+          command='%s gyp-win-tool stamp $out' % python_exec)
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='%s gyp-win-tool recursive-mirror $in $out' % python_exec)
+    elif sys.platform in ['cygwin', 'win32']:
+      master_ninja.rule(
+          'stamp',
+          description='STAMP $out',
+          command='$python gyp-win-tool stamp $out')
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='$python gyp-win-tool recursive-mirror $in $out')
+    else:
+      master_ninja.rule(
+          'stamp', description='STAMP $out', command='${postbuilds}touch $out')
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='rm -rf $out && cp -af $in $out')
+    master_ninja.newline()
+
+    # Output host building rules
+    if is_windows:
+      cc_command = ('$cc /nologo /showIncludes /FC '
+                    '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      cxx_command = ('$cxx /nologo /showIncludes /FC '
+                     '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      master_ninja.rule(
+          'cc_host',
+          description='CC_HOST $out',
+          command=cc_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags_host $cflags_c_host')
+      master_ninja.rule(
+          'cxx_host',
+          description='CXX_HOST $out',
+          command=cxx_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags_host $cflags_cc_host')
+
+      master_ninja.rule(
+          'alink_host',
+          description='LIB_HOST $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags_host')
+
+      master_ninja.rule(
+          'alink_thin_host',
+          description='LIB_HOST $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags_host')
+
+      link_command = (
+          '%s gyp-win-tool link-wrapper $arch '
+          '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' % (python_exec))
+
+      master_ninja.rule(
+          'link_host',
+          description='LINK_HOST $out',
+          command=link_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libs $ldflags',
+          pool='link_pool')
+    else:
+      cc_command = 'bash -c "$cc_host @$out.rsp"'
+      cxx_command = 'bash -c "$cxx_host @$out.rsp"'
+      master_ninja.rule(
+          'cc_host',
+          description='CC_HOST $out',
+          command=cc_command,
+          rspfile='$out.rsp',
+          rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
+                           '$cflags_c_host $cflags_pch_c -c $in -o $out'),
+          depfile='$out.d')
+      master_ninja.rule(
+          'cxx_host',
+          description='CXX_HOST $out',
+          command=cxx_command,
+          rspfile='$out.rsp',
+          rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
+                           '$cflags_cc_host $cflags_pch_cc -c $in -o $out'),
+          depfile='$out.d')
+
+      alink_command = 'rm -f $out && $ar_host $arFlags_host $out @$out.rsp'
+      alink_thin_command = ('rm -f $out && $ar_host $arThinFlags_host $out '
+                            '@$out.rsp')
+
+      master_ninja.rule(
+          'alink_host',
+          description='AR_HOST $out',
+          command='bash -c "' + alink_command + '"',
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      master_ninja.rule(
+          'alink_thin_host',
+          description='AR_HOST $out',
+          command='bash -c "' + alink_thin_command + '"',
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      beginlinkinlibs = ''
+      endlinkinlibs = ''
+      if is_linux:
+        beginlinkinlibs = '-Wl,--start-group'
+        endlinkinlibs = '-Wl,--end-group'
+      rpath = '-Wl,-rpath=\$$ORIGIN/lib'
+      master_ninja.rule(
+          'link_host',
+          description='LINK_HOST $out',
+          command=('bash -c "$ld_host $ldflags_host -o $out %s '
+                   '%s $in $solibs %s $libs"' % (rpath, beginlinkinlibs,
+                                                 endlinkinlibs)))
+
   all_targets = set()
   for build_file in params['build_files']:
     for target in gyp.common.AllTargets(target_list, target_dicts,