summaryrefslogtreecommitdiff
path: root/tools/gyp
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2013-03-24 14:29:17 +0100
committerBen Noordhuis <info@bnoordhuis.nl>2013-03-24 15:03:09 +0100
commit8632af381e7086823db764f815cbee53681d450b (patch)
tree84c752dbe7c2adb53a567087ac995383fb3e3935 /tools/gyp
parent329b5388ba5a74aa3c4a7e142ba33510e4282cc1 (diff)
downloadandroid-node-v8-8632af381e7086823db764f815cbee53681d450b.tar.gz
android-node-v8-8632af381e7086823db764f815cbee53681d450b.tar.bz2
android-node-v8-8632af381e7086823db764f815cbee53681d450b.zip
tools: update gyp to r1601
Among other things, this should make it easier for people to build node.js on openbsd.
Diffstat (limited to 'tools/gyp')
-rw-r--r--tools/gyp/AUTHORS2
-rw-r--r--tools/gyp/PRESUBMIT.py13
-rwxr-xr-xtools/gyp/buildbot/buildbot_run.py98
-rw-r--r--tools/gyp/data/win/large-pdb-shim.cc12
-rwxr-xr-xtools/gyp/gyptest.py1
-rw-r--r--tools/gyp/pylib/gyp/MSVSUtil.py212
-rw-r--r--tools/gyp/pylib/gyp/MSVSVersion.py9
-rwxr-xr-xtools/gyp/pylib/gyp/__init__.py21
-rw-r--r--tools/gyp/pylib/gyp/common.py26
-rwxr-xr-xtools/gyp/pylib/gyp/common_test.py14
-rw-r--r--tools/gyp/pylib/gyp/generator/android.py77
-rw-r--r--tools/gyp/pylib/gyp/generator/eclipse.py32
-rw-r--r--tools/gyp/pylib/gyp/generator/make.py52
-rw-r--r--tools/gyp/pylib/gyp/generator/msvs.py118
-rw-r--r--tools/gyp/pylib/gyp/generator/ninja.py166
-rw-r--r--tools/gyp/pylib/gyp/generator/xcode.py25
-rw-r--r--tools/gyp/pylib/gyp/input.py140
-rwxr-xr-xtools/gyp/pylib/gyp/mac_tool.py13
-rw-r--r--tools/gyp/pylib/gyp/msvs_emulation.py95
-rw-r--r--tools/gyp/pylib/gyp/xcode_emulation.py82
-rw-r--r--tools/gyp/pylib/gyp/xcodeproj_file.py1
-rw-r--r--tools/gyp/tools/emacs/gyp-tests.el11
-rw-r--r--tools/gyp/tools/emacs/gyp.el2
23 files changed, 722 insertions, 500 deletions
diff --git a/tools/gyp/AUTHORS b/tools/gyp/AUTHORS
index 6db82b9e4b..8977761960 100644
--- a/tools/gyp/AUTHORS
+++ b/tools/gyp/AUTHORS
@@ -2,5 +2,7 @@
# Name or Organization <email address>
Google Inc.
+Bloomberg Finance L.P.
+
Steven Knight <knight@baldmt.com>
Ryan Norton <rnorton10@gmail.com>
diff --git a/tools/gyp/PRESUBMIT.py b/tools/gyp/PRESUBMIT.py
index 0338fb4a96..65235661a4 100644
--- a/tools/gyp/PRESUBMIT.py
+++ b/tools/gyp/PRESUBMIT.py
@@ -75,13 +75,20 @@ def CheckChangeOnUpload(input_api, output_api):
def CheckChangeOnCommit(input_api, output_api):
report = []
+
+ # 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)))
+ years_re = '(' + '|'.join(allowed_years) + ')'
+
+ # The (c) is deprecated, but tolerate it until it's removed from all files.
license = (
- r'.*? Copyright \(c\) %(year)s Google Inc\. All rights reserved\.\n'
+ 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'
r'.*? found in the LICENSE file\.\n'
) % {
- 'year': input_api.time.strftime('%Y'),
+ 'year': years_re,
}
report.extend(input_api.canned_checks.PanProjectChecks(
@@ -106,4 +113,4 @@ def CheckChangeOnCommit(input_api, output_api):
def GetPreferredTrySlaves():
- return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac']
+ return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac', 'gyp-android']
diff --git a/tools/gyp/buildbot/buildbot_run.py b/tools/gyp/buildbot/buildbot_run.py
deleted file mode 100755
index 57fdb655ba..0000000000
--- a/tools/gyp/buildbot/buildbot_run.py
+++ /dev/null
@@ -1,98 +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
-
-
-if sys.platform in ['win32', 'cygwin']:
- EXE_SUFFIX = '.exe'
-else:
- EXE_SUFFIX = ''
-
-
-BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__))
-TRUNK_DIR = os.path.dirname(BUILDBOT_DIR)
-ROOT_DIR = os.path.dirname(TRUNK_DIR)
-OUT_DIR = os.path.join(TRUNK_DIR, 'out')
-
-
-def GypTestFormat(title, format=None, msvs_version=None):
- """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()
- # TODO(bradnelson): remove this when this issue is resolved:
- # http://code.google.com/p/chromium/issues/detail?id=108251
- if format == 'ninja':
- env['NOGOLD'] = '1'
- if msvs_version:
- env['GYP_MSVS_VERSION'] = msvs_version
- retcode = subprocess.call(' '.join(
- [sys.executable, 'trunk/gyptest.py',
- '--all',
- '--passed',
- '--format', format,
- '--chdir', 'trunk',
- '--path', '../scons']),
- 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('scons')
- retcode += GypTestFormat('make')
- elif sys.platform == 'darwin':
- retcode += GypTestFormat('ninja')
- retcode += GypTestFormat('xcode')
- retcode += GypTestFormat('make')
- elif sys.platform == 'win32':
- retcode += GypTestFormat('ninja')
- retcode += GypTestFormat('msvs-2008', format='msvs', msvs_version='2008')
- if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64':
- retcode += GypTestFormat('msvs-2010', format='msvs', msvs_version='2010')
- 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/tools/gyp/data/win/large-pdb-shim.cc b/tools/gyp/data/win/large-pdb-shim.cc
new file mode 100644
index 0000000000..8bca510815
--- /dev/null
+++ b/tools/gyp/data/win/large-pdb-shim.cc
@@ -0,0 +1,12 @@
+// 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.
+
+// This file is used to generate an empty .pdb -- with a 4KB pagesize -- that is
+// then used during the final link for modules that have large PDBs. Otherwise,
+// the linker will generate a pdb with a page size of 1KB, which imposes a limit
+// of 1GB on the .pdb. By generating an initial empty .pdb with the compiler
+// (rather than the linker), this limit is avoided. With this in place PDBs may
+// grow to 2GB.
+//
+// This file is referenced by the msvs_large_pdb mechanism in MSVSUtil.py.
diff --git a/tools/gyp/gyptest.py b/tools/gyp/gyptest.py
index 6c6b00944f..efa75a7aa8 100755
--- a/tools/gyp/gyptest.py
+++ b/tools/gyp/gyptest.py
@@ -212,6 +212,7 @@ def main(argv=None):
format_list = {
'freebsd7': ['make'],
'freebsd8': ['make'],
+ 'openbsd5': ['make'],
'cygwin': ['msvs'],
'win32': ['msvs', 'ninja'],
'linux2': ['make', 'ninja'],
diff --git a/tools/gyp/pylib/gyp/MSVSUtil.py b/tools/gyp/pylib/gyp/MSVSUtil.py
new file mode 100644
index 0000000000..5afcd1f2ab
--- /dev/null
+++ b/tools/gyp/pylib/gyp/MSVSUtil.py
@@ -0,0 +1,212 @@
+# 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.
+
+"""Utility functions shared amongst the Windows generators."""
+
+import copy
+import os
+
+
+_TARGET_TYPE_EXT = {
+ 'executable': '.exe',
+ 'shared_library': '.dll'
+}
+
+
+def _GetLargePdbShimCcPath():
+ """Returns the path of the large_pdb_shim.cc file."""
+ this_dir = os.path.abspath(os.path.dirname(__file__))
+ src_dir = os.path.abspath(os.path.join(this_dir, '..', '..'))
+ win_data_dir = os.path.join(src_dir, 'data', 'win')
+ large_pdb_shim_cc = os.path.join(win_data_dir, 'large-pdb-shim.cc')
+ return large_pdb_shim_cc
+
+
+def _DeepCopySomeKeys(in_dict, keys):
+ """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
+
+ Arguments:
+ in_dict: The dictionary to copy.
+ keys: The keys to be copied. If a key is in this list and doesn't exist in
+ |in_dict| this is not an error.
+ Returns:
+ The partially deep-copied dictionary.
+ """
+ d = {}
+ for key in keys:
+ if key not in in_dict:
+ continue
+ d[key] = copy.deepcopy(in_dict[key])
+ return d
+
+
+def _SuffixName(name, suffix):
+ """Add a suffix to the end of a target.
+
+ Arguments:
+ name: name of the target (foo#target)
+ suffix: the suffix to be added
+ Returns:
+ Target name with suffix added (foo_suffix#target)
+ """
+ parts = name.rsplit('#', 1)
+ parts[0] = '%s_%s' % (parts[0], suffix)
+ return '#'.join(parts)
+
+
+def _ShardName(name, number):
+ """Add a shard number to the end of a target.
+
+ Arguments:
+ name: name of the target (foo#target)
+ number: shard number
+ Returns:
+ Target name with shard added (foo_1#target)
+ """
+ return _SuffixName(name, str(number))
+
+
+def ShardTargets(target_list, target_dicts):
+ """Shard some targets apart to work around the linkers limits.
+
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ Returns:
+ Tuple of the new sharded versions of the inputs.
+ """
+ # Gather the targets to shard, and how many pieces.
+ targets_to_shard = {}
+ for t in target_dicts:
+ shards = int(target_dicts[t].get('msvs_shard', 0))
+ if shards:
+ targets_to_shard[t] = shards
+ # Shard target_list.
+ new_target_list = []
+ for t in target_list:
+ if t in targets_to_shard:
+ for i in range(targets_to_shard[t]):
+ new_target_list.append(_ShardName(t, i))
+ else:
+ new_target_list.append(t)
+ # Shard target_dict.
+ new_target_dicts = {}
+ for t in target_dicts:
+ if t in targets_to_shard:
+ for i in range(targets_to_shard[t]):
+ name = _ShardName(t, i)
+ new_target_dicts[name] = copy.copy(target_dicts[t])
+ new_target_dicts[name]['target_name'] = _ShardName(
+ new_target_dicts[name]['target_name'], i)
+ sources = new_target_dicts[name].get('sources', [])
+ new_sources = []
+ for pos in range(i, len(sources), targets_to_shard[t]):
+ new_sources.append(sources[pos])
+ new_target_dicts[name]['sources'] = new_sources
+ else:
+ new_target_dicts[t] = target_dicts[t]
+ # Shard dependencies.
+ for t in new_target_dicts:
+ dependencies = copy.copy(new_target_dicts[t].get('dependencies', []))
+ new_dependencies = []
+ for d in dependencies:
+ if d in targets_to_shard:
+ for i in range(targets_to_shard[d]):
+ new_dependencies.append(_ShardName(d, i))
+ else:
+ new_dependencies.append(d)
+ new_target_dicts[t]['dependencies'] = new_dependencies
+
+ return (new_target_list, new_target_dicts)
+
+
+def InsertLargePdbShims(target_list, target_dicts, vars):
+ """Insert a shim target that forces the linker to use 4KB pagesize PDBs.
+
+ This is a workaround for targets with PDBs greater than 1GB in size, the
+ limit for the 1KB pagesize PDBs created by the linker by default.
+
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ vars: A dictionary of common GYP variables with generator-specific values.
+ Returns:
+ Tuple of the shimmed version of the inputs.
+ """
+ # Determine which targets need shimming.
+ targets_to_shim = []
+ for t in target_dicts:
+ target_dict = target_dicts[t]
+ # We only want to shim targets that have msvs_large_pdb enabled.
+ if not int(target_dict.get('msvs_large_pdb', 0)):
+ continue
+ # This is intended for executable, shared_library and loadable_module
+ # targets where every configuration is set up to produce a PDB output.
+ # If any of these conditions is not true then the shim logic will fail
+ # below.
+ targets_to_shim.append(t)
+
+ large_pdb_shim_cc = _GetLargePdbShimCcPath()
+
+ for t in targets_to_shim:
+ target_dict = target_dicts[t]
+ target_name = target_dict.get('target_name')
+
+ base_dict = _DeepCopySomeKeys(target_dict,
+ ['configurations', 'default_configuration', 'toolset'])
+
+ # This is the dict for copying the source file (part of the GYP tree)
+ # to the intermediate directory of the project. This is necessary because
+ # we can't always build a relative path to the shim source file (on Windows
+ # GYP and the project may be on different drives), and Ninja hates absolute
+ # paths (it ends up generating the .obj and .obj.d alongside the source
+ # file, polluting GYPs tree).
+ copy_suffix = '_large_pdb_copy'
+ copy_target_name = target_name + '_' + copy_suffix
+ full_copy_target_name = _SuffixName(t, copy_suffix)
+ shim_cc_basename = os.path.basename(large_pdb_shim_cc)
+ shim_cc_dir = vars['SHARED_INTERMEDIATE_DIR'] + '/' + copy_target_name
+ shim_cc_path = shim_cc_dir + '/' + shim_cc_basename
+ copy_dict = copy.deepcopy(base_dict)
+ copy_dict['target_name'] = copy_target_name
+ copy_dict['type'] = 'none'
+ copy_dict['sources'] = [ large_pdb_shim_cc ]
+ copy_dict['copies'] = [{
+ 'destination': shim_cc_dir,
+ 'files': [ large_pdb_shim_cc ]
+ }]
+
+ # This is the dict for the PDB generating shim target. It depends on the
+ # copy target.
+ shim_suffix = '_large_pdb_shim'
+ shim_target_name = target_name + '_' + shim_suffix
+ full_shim_target_name = _SuffixName(t, shim_suffix)
+ shim_dict = copy.deepcopy(base_dict)
+ shim_dict['target_name'] = shim_target_name
+ shim_dict['type'] = 'static_library'
+ shim_dict['sources'] = [ shim_cc_path ]
+ shim_dict['dependencies'] = [ full_copy_target_name ]
+
+ # Set up the shim to output its PDB to the same location as the final linker
+ # target.
+ for config in shim_dict.get('configurations').itervalues():
+ msvs = config.setdefault('msvs_settings')
+
+ linker = msvs.pop('VCLinkerTool') # We want to clear this dict.
+ pdb_path = linker.get('ProgramDatabaseFile')
+
+ compiler = msvs.setdefault('VCCLCompilerTool', {})
+ compiler.setdefault('DebugInformationFormat', '3')
+ compiler.setdefault('ProgramDataBaseFileName', pdb_path)
+
+ # Add the new targets.
+ target_list.append(full_copy_target_name)
+ target_list.append(full_shim_target_name)
+ target_dicts[full_copy_target_name] = copy_dict
+ target_dicts[full_shim_target_name] = shim_dict
+
+ # Update the original target to depend on the shim target.
+ target_dict.setdefault('dependencies', []).append(full_shim_target_name)
+
+ return (target_list, target_dicts) \ No newline at end of file
diff --git a/tools/gyp/pylib/gyp/MSVSVersion.py b/tools/gyp/pylib/gyp/MSVSVersion.py
index 97caf66980..2d95cd0c9e 100644
--- a/tools/gyp/pylib/gyp/MSVSVersion.py
+++ b/tools/gyp/pylib/gyp/MSVSVersion.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# 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.
@@ -355,6 +355,13 @@ def SelectVisualStudioVersion(version='auto'):
'2012': ('11.0',),
'2012e': ('11.0',),
}
+ override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
+ if override_path:
+ msvs_version = os.environ.get('GYP_MSVS_VERSION')
+ if not msvs_version or 'e' not in msvs_version:
+ raise ValueError('GYP_MSVS_OVERRIDE_PATH requires GYP_MSVS_VERSION to be '
+ 'set to an "e" version (e.g. 2010e)')
+ return _CreateVersion(msvs_version, override_path, sdk_based=True)
version = str(version)
versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)
if not versions:
diff --git a/tools/gyp/pylib/gyp/__init__.py b/tools/gyp/pylib/gyp/__init__.py
index ac300a903c..3769c52652 100755
--- a/tools/gyp/pylib/gyp/__init__.py
+++ b/tools/gyp/pylib/gyp/__init__.py
@@ -23,8 +23,8 @@ DEBUG_VARIABLES = 'variables'
DEBUG_INCLUDES = 'includes'
-def DebugOutput(mode, message):
- if 'all' in gyp.debug.keys() or mode in gyp.debug.keys():
+def DebugOutput(mode, message, *args):
+ if 'all' in gyp.debug or mode in gyp.debug:
ctx = ('unknown', 0, 'unknown')
try:
f = traceback.extract_stack(limit=2)
@@ -32,6 +32,8 @@ def DebugOutput(mode, message):
ctx = f[0][:3]
except:
pass
+ if args:
+ message %= args
print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
ctx[1], ctx[2], message)
@@ -376,21 +378,22 @@ def gyp_main(args):
options.generator_output = g_o
if not options.parallel and options.use_environment:
- options.parallel = bool(os.environ.get('GYP_PARALLEL'))
+ p = os.environ.get('GYP_PARALLEL')
+ options.parallel = bool(p and p != '0')
for mode in options.debug:
gyp.debug[mode] = 1
# Do an extra check to avoid work when we're not debugging.
- if DEBUG_GENERAL in gyp.debug.keys():
+ if DEBUG_GENERAL in gyp.debug:
DebugOutput(DEBUG_GENERAL, 'running with these options:')
for option, value in sorted(options.__dict__.items()):
if option[0] == '_':
continue
if isinstance(value, basestring):
- DebugOutput(DEBUG_GENERAL, " %s: '%s'" % (option, value))
+ DebugOutput(DEBUG_GENERAL, " %s: '%s'", option, value)
else:
- DebugOutput(DEBUG_GENERAL, " %s: %s" % (option, str(value)))
+ DebugOutput(DEBUG_GENERAL, " %s: %s", option, value)
if not build_files:
build_files = FindBuildFiles()
@@ -440,9 +443,9 @@ def gyp_main(args):
if options.defines:
defines += options.defines
cmdline_default_variables = NameValueListToDict(defines)
- if DEBUG_GENERAL in gyp.debug.keys():
+ if DEBUG_GENERAL in gyp.debug:
DebugOutput(DEBUG_GENERAL,
- "cmdline_default_variables: %s" % cmdline_default_variables)
+ "cmdline_default_variables: %s", cmdline_default_variables)
# Set up includes.
includes = []
@@ -468,7 +471,7 @@ def gyp_main(args):
gen_flags += options.generator_flags
generator_flags = NameValueListToDict(gen_flags)
if DEBUG_GENERAL in gyp.debug.keys():
- DebugOutput(DEBUG_GENERAL, "generator_flags: %s" % generator_flags)
+ DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
# TODO: Remove this and the option after we've gotten folks to move to the
# generator flag.
diff --git a/tools/gyp/pylib/gyp/common.py b/tools/gyp/pylib/gyp/common.py
index e917a59a3c..e50f51c307 100644
--- a/tools/gyp/pylib/gyp/common.py
+++ b/tools/gyp/pylib/gyp/common.py
@@ -127,9 +127,9 @@ def RelativePath(path, relative_to):
# directory, returns a relative path that identifies path relative to
# relative_to.
- # Convert to absolute (and therefore normalized paths).
- path = os.path.abspath(path)
- relative_to = os.path.abspath(relative_to)
+ # Convert to normalized (and therefore absolute paths).
+ path = os.path.realpath(path)
+ relative_to = os.path.realpath(relative_to)
# Split the paths into components.
path_split = path.split(os.path.sep)
@@ -151,6 +151,20 @@ def RelativePath(path, relative_to):
return os.path.join(*relative_split)
+@memoize
+def InvertRelativePath(path, toplevel_dir=None):
+ """Given a path like foo/bar that is relative to toplevel_dir, return
+ the inverse relative path back to the toplevel_dir.
+
+ E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
+ should always produce the empty string, unless the path contains symlinks.
+ """
+ if not path:
+ return path
+ toplevel_dir = '.' if toplevel_dir is None else toplevel_dir
+ return RelativePath(toplevel_dir, os.path.join(toplevel_dir, path))
+
+
def FixIfRelativePath(path, relative_to):
# Like RelativePath but returns |path| unchanged if it is absolute.
if os.path.isabs(path):
@@ -378,8 +392,10 @@ def GetFlavor(params):
return 'solaris'
if sys.platform.startswith('freebsd'):
return 'freebsd'
- if sys.platform.startswith('dragonfly'):
- return 'dragonflybsd'
+ if sys.platform.startswith('openbsd'):
+ return 'openbsd'
+ if sys.platform.startswith('aix'):
+ return 'aix'
return 'linux'
diff --git a/tools/gyp/pylib/gyp/common_test.py b/tools/gyp/pylib/gyp/common_test.py
index 7fbac09d0f..ad6f9a1438 100755
--- a/tools/gyp/pylib/gyp/common_test.py
+++ b/tools/gyp/pylib/gyp/common_test.py
@@ -56,13 +56,13 @@ class TestGetFlavor(unittest.TestCase):
self.assertEqual(expected, gyp.common.GetFlavor(param))
def test_platform_default(self):
- self.assertFlavor('dragonflybsd', 'dragonfly3', {})
- self.assertFlavor('freebsd' , 'freebsd9' , {})
- self.assertFlavor('freebsd' , 'freebsd10' , {})
- self.assertFlavor('solaris' , 'sunos5' , {});
- self.assertFlavor('solaris' , 'sunos' , {});
- self.assertFlavor('linux' , 'linux2' , {});
- self.assertFlavor('linux' , 'linux3' , {});
+ self.assertFlavor('freebsd', 'freebsd9' , {})
+ self.assertFlavor('freebsd', 'freebsd10', {})
+ self.assertFlavor('openbsd', 'openbsd5' , {})
+ self.assertFlavor('solaris', 'sunos5' , {});
+ self.assertFlavor('solaris', 'sunos' , {});
+ self.assertFlavor('linux' , 'linux2' , {});
+ self.assertFlavor('linux' , 'linux3' , {});
def test_param(self):
self.assertFlavor('foobar', 'linux2' , {'flavor': 'foobar'})
diff --git a/tools/gyp/pylib/gyp/generator/android.py b/tools/gyp/pylib/gyp/generator/android.py
index 872ec844c8..a01ead020d 100644
--- a/tools/gyp/pylib/gyp/generator/android.py
+++ b/tools/gyp/pylib/gyp/generator/android.py
@@ -19,6 +19,7 @@ import gyp.common
import gyp.generator.make as make # Reuse global functions from make backend.
import os
import re
+import subprocess
generator_default_variables = {
'OS': 'android',
@@ -38,7 +39,7 @@ generator_default_variables = {
'RULE_INPUT_PATH': '$(RULE_SOURCES)',
'RULE_INPUT_EXT': '$(suffix $<)',
'RULE_INPUT_NAME': '$(notdir $<)',
- 'CONFIGURATION_NAME': 'NOT_USED_ON_ANDROID',
+ 'CONFIGURATION_NAME': '$(GYP_DEFAULT_CONFIGURATION)',
}
# Make supports multiple toolsets
@@ -131,12 +132,13 @@ class AndroidMkWriter(object):
def __init__(self, android_top_dir):
self.android_top_dir = android_top_dir
- def Write(self, qualified_target, base_path, output_filename, spec, configs,
- part_of_all):
+ def Write(self, qualified_target, relative_target, base_path, output_filename,
+ spec, configs, part_of_all):
"""The main entry point: writes a .mk file for a single target.
Arguments:
qualified_target: target we're generating
+ relative_target: qualified target name relative to the root
base_path: path relative to source root we're building in, used to resolve
target-relative paths
output_filename: output .mk file name to write
@@ -150,6 +152,7 @@ class AndroidMkWriter(object):
self.fp.write(header)
self.qualified_target = qualified_target
+ self.relative_target = relative_target
self.path = base_path
self.target = spec['target_name']
self.type = spec['type']
@@ -248,7 +251,7 @@ class AndroidMkWriter(object):
actions)
"""
for action in actions:
- name = make.StringToMakefileVariable('%s_%s' % (self.qualified_target,
+ name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
action['action_name']))
self.WriteLn('### Rules for action "%s":' % action['action_name'])
inputs = action['inputs']
@@ -295,6 +298,15 @@ class AndroidMkWriter(object):
'$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)' %
main_output)
+ # Android's envsetup.sh adds a number of directories to the path including
+ # the built host binary directory. This causes actions/rules invoked by
+ # gyp to sometimes use these instead of system versions, e.g. bison.
+ # The built host binaries may not be suitable, and can cause errors.
+ # So, we remove them from the PATH using the ANDROID_BUILD_PATHS variable
+ # set by envsetup.
+ self.WriteLn('%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))'
+ % main_output)
+
for input in inputs:
assert ' ' not in input, (
"Spaces in action input filenames not supported (%s)" % input)
@@ -334,7 +346,7 @@ class AndroidMkWriter(object):
if len(rule.get('rule_sources', [])) == 0:
continue
did_write_rule = True
- name = make.StringToMakefileVariable('%s_%s' % (self.qualified_target,
+ name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
rule['rule_name']))
self.WriteLn('\n### Generated for rule "%s":' % name)
self.WriteLn('# "%s":' % rule)
@@ -388,6 +400,10 @@ class AndroidMkWriter(object):
'$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)'
% main_output)
+ # See explanation in WriteActions.
+ self.WriteLn('%s: export PATH := '
+ '$(subst $(ANDROID_BUILD_PATHS),,$(PATH))' % main_output)
+
main_output_deps = self.LocalPathify(rule_source)
if inputs:
main_output_deps += ' '
@@ -415,7 +431,7 @@ class AndroidMkWriter(object):
"""
self.WriteLn('### Generated for copy rule.')
- variable = make.StringToMakefileVariable(self.qualified_target + '_copies')
+ variable = make.StringToMakefileVariable(self.relative_target + '_copies')
outputs = []
for copy in copies:
for path in copy['files']:
@@ -940,30 +956,16 @@ class AndroidMkWriter(object):
return path
-def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
- build_files):
- """Write the target to regenerate the Makefile."""
+def PerformBuild(data, configurations, params):
+ # The android backend only supports the default configuration.
options = params['options']
- # Sort to avoid non-functional changes to makefile.
- build_files = sorted([os.path.join('$(LOCAL_PATH)', f) for f in build_files])
- build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
- for filename in params['build_files_arg']]
- build_files_args = [os.path.join('$(PRIVATE_LOCAL_PATH)', f)
- for f in build_files_args]
- gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
- options.toplevel_dir)
- makefile_path = os.path.join('$(LOCAL_PATH)', makefile_name)
- if not gyp_binary.startswith(os.sep):
- gyp_binary = os.path.join('.', gyp_binary)
- root_makefile.write('GYP_FILES := \\\n %s\n\n' %
- '\\\n '.join(map(Sourceify, build_files)))
- root_makefile.write('%s: PRIVATE_LOCAL_PATH := $(LOCAL_PATH)\n' %
- makefile_path)
- root_makefile.write('%s: $(GYP_FILES)\n' % makefile_path)
- root_makefile.write('\techo ACTION Regenerating $@\n\t%s\n\n' %
- gyp.common.EncodePOSIXShellList([gyp_binary, '-fandroid'] +
- gyp.RegenerateFlags(options) +
- build_files_args))
+ makefile = os.path.abspath(os.path.join(options.toplevel_dir,
+ 'GypAndroid.mk'))
+ env = dict(os.environ)
+ env['ONE_SHOT_MAKEFILE'] = makefile
+ arguments = ['make', '-C', os.environ['ANDROID_BUILD_TOP'], 'gyp_all_modules']
+ print 'Building: %s' % arguments
+ subprocess.check_call(arguments, env=env)
def GenerateOutput(target_list, target_dicts, data, params):
@@ -1030,7 +1032,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
for qualified_target in target_list:
build_file, target, toolset = gyp.common.ParseQualifiedTarget(
qualified_target)
- build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
+ relative_build_file = gyp.common.RelativePath(build_file,
+ options.toplevel_dir)
+ build_files.add(relative_build_file)
included_files = data[build_file]['included_files']
for included_file in included_files:
# The included_files entries are relative to the dir of the build file
@@ -1058,9 +1062,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
not int(spec.get('suppress_wildcard', False)))
if limit_to_target_all and not part_of_all:
continue
+
+ relative_target = gyp.common.QualifiedTarget(relative_build_file, target,
+ toolset)
writer = AndroidMkWriter(android_top_dir)
- android_module = writer.Write(qualified_target, base_path, output_file,
- spec, configs, part_of_all=part_of_all)
+ android_module = writer.Write(qualified_target, relative_target, base_path,
+ output_file, spec, configs,
+ part_of_all=part_of_all)
if android_module in android_modules:
print ('ERROR: Android module names must be unique. The following '
'targets both generate Android module name %s.\n %s\n %s' %
@@ -1077,6 +1085,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
# Some tools need to know the absolute path of the top directory.
root_makefile.write('GYP_ABS_ANDROID_TOP_DIR := $(shell pwd)\n')
+ root_makefile.write('GYP_DEFAULT_CONFIGURATION := %s\n' %
+ default_configuration)
# Write out the sorted list of includes.
root_makefile.write('\n')
@@ -1084,9 +1094,6 @@ def GenerateOutput(target_list, target_dicts, data, params):
root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n')
root_makefile.write('\n')
- if generator_flags.get('auto_regeneration', True):
- WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
-
root_makefile.write(SHARED_FOOTER)
root_makefile.close()
diff --git a/tools/gyp/pylib/gyp/generator/eclipse.py b/tools/gyp/pylib/gyp/generator/eclipse.py
index 0f90b5ea60..08425da8e8 100644
--- a/tools/gyp/pylib/gyp/generator/eclipse.py
+++ b/tools/gyp/pylib/gyp/generator/eclipse.py
@@ -41,11 +41,11 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'CONFIGURATION_NAME']:
generator_default_variables[unused] = ''
-# Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as
+# Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as
# part of the path when dealing with generated headers. This value will be
# replaced dynamically for each configuration.
generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \
- '$SHARED_INTERMEDIATES_DIR'
+ '$SHARED_INTERMEDIATE_DIR'
def CalculateVariables(default_variables, params):
@@ -65,7 +65,7 @@ def CalculateGeneratorInputInfo(params):
def GetAllIncludeDirectories(target_list, target_dicts,
- shared_intermediates_dir, config_name):
+ shared_intermediate_dirs, config_name):
"""Calculate the set of include directories to be used.
Returns:
@@ -96,17 +96,18 @@ def GetAllIncludeDirectories(target_list, target_dicts,
# Find standard gyp include dirs.
if config.has_key('include_dirs'):
include_dirs = config['include_dirs']
- for include_dir in include_dirs:
- include_dir = include_dir.replace('$SHARED_INTERMEDIATES_DIR',
- shared_intermediates_dir)
- if not os.path.isabs(include_dir):
- base_dir = os.path.dirname(target_name)
+ for shared_intermediate_dir in shared_intermediate_dirs:
+ for include_dir in include_dirs:
+ include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR',
+ shared_intermediate_dir)
+ if not os.path.isabs(include_dir):
+ base_dir = os.path.dirname(target_name)
- include_dir = base_dir + '/' + include_dir
- include_dir = os.path.abspath(include_dir)
+ include_dir = base_dir + '/' + include_dir
+ include_dir = os.path.abspath(include_dir)
- if not include_dir in gyp_includes_set:
- gyp_includes_set.add(include_dir)
+ if not include_dir in gyp_includes_set:
+ gyp_includes_set.add(include_dir)
# Generate a list that has all the include dirs.
@@ -234,7 +235,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name)
toplevel_build = os.path.join(options.toplevel_dir, build_dir)
- shared_intermediate_dir = os.path.join(toplevel_build, 'obj', 'gen')
+ # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the
+ # SHARED_INTERMEDIATE_DIR. Include both possible locations.
+ shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'),
+ os.path.join(toplevel_build, 'gen')]
if not os.path.exists(toplevel_build):
os.makedirs(toplevel_build)
@@ -246,7 +250,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
'GNU C++', 'GNU C', 'Assembly']
include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
- shared_intermediate_dir, config_name)
+ shared_intermediate_dirs, config_name)
WriteIncludePaths(out, eclipse_langs, include_dirs)
defines = GetAllDefines(target_list, target_dicts, data, config_name)
WriteMacros(out, eclipse_langs, defines)
diff --git a/tools/gyp/pylib/gyp/generator/make.py b/tools/gyp/pylib/gyp/generator/make.py
index bcc2cc619d..9806c64a8f 100644
--- a/tools/gyp/pylib/gyp/generator/make.py
+++ b/tools/gyp/pylib/gyp/generator/make.py
@@ -259,7 +259,7 @@ all_deps :=
# export LINK=g++
#
# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= %(flock)s $(builddir)/linker.lock $(CXX)
+LINK ?= %(flock)s $(builddir)/linker.lock $(CXX.target)
CC.target ?= %(CC.target)s
CFLAGS.target ?= $(CFLAGS)
@@ -395,15 +395,14 @@ command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
+# Helper that executes all postbuilds until one fails.
define do_postbuilds
@E=0;\\
for p in $(POSTBUILDS); do\\
eval $$p;\\
- F=$$?;\\
- if [ $$F -ne 0 ]; then\\
- E=$$F;\\
+ E=$$?;\\
+ if [ $$E -ne 0 ]; then\\
+ break;\\
fi;\\
done;\\
if [ $$E -ne 0 ]; then\\
@@ -619,21 +618,6 @@ def QuoteSpaces(s, quote=r'\ '):
return s.replace(' ', quote)
-def InvertRelativePath(path):
- """Given a relative path like foo/bar, return the inverse relative path:
- the path from the relative path back to the origin dir.
-
- E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
- should always produce the empty string."""
-
- if not path:
- return path
- # Only need to handle relative paths into subdirectories for now.
- assert '..' not in path, path
- depth = len(path.split(os.path.sep))
- return os.path.sep.join(['..'] * depth)
-
-
# Map from qualified target to path to output.
target_outputs = {}
# Map from qualified target to any linkable output. A subset
@@ -1417,7 +1401,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
lambda p: Sourceify(self.Absolutify(p)))
# TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on.
- gyp_to_build = InvertRelativePath(self.path)
+ gyp_to_build = gyp.common.InvertRelativePath(self.path)
target_postbuild = self.xcode_settings.GetTargetPostbuilds(
configname,
QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build,
@@ -1541,7 +1525,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
for link_dep in link_deps:
assert ' ' not in link_dep, (
"Spaces in alink input filenames not supported (%s)" % link_dep)
- if (self.flavor not in ('mac', 'win') and not
+ if (self.flavor not in ('mac', 'openbsd', 'win') and not
self.is_standalone_static_library):
self.WriteDoCmd([self.output_binary], link_deps, 'alink_thin',
part_of_all, postbuilds=postbuilds)
@@ -2000,7 +1984,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
'flock_index': 2,
'extra_commands': SHARED_HEADER_SUN_COMMANDS,
})
- elif flavor == 'freebsd' or flavor == 'dragonflybsd':
+ elif flavor == 'freebsd':
+ # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific.
header_params.update({
'flock': 'lockf',
})
@@ -2018,14 +2003,22 @@ def GenerateOutput(target_list, target_dicts, data, params):
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings_array = data[build_file].get('make_global_settings', [])
+ wrappers = {}
+ wrappers['LINK'] = '%s $(builddir)/linker.lock' % flock_command
+ for key, value in make_global_settings_array:
+ if key.endswith('_wrapper'):
+ wrappers[key[:-len('_wrapper')]] = '$(abspath %s)' % value
make_global_settings = ''
for key, value in make_global_settings_array:
+ if re.match('.*_wrapper', key):
+ continue
if value[0] != '$':
value = '$(abspath %s)' % value
- if key == 'LINK':
- make_global_settings += ('%s ?= %s $(builddir)/linker.lock %s\n' %
- (key, flock_command, value))
- elif key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
+ wrapper = wrappers.get(key)
+ if wrapper:
+ value = '%s %s' % (wrapper, value)
+ del wrappers[key]
+ if key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
make_global_settings += (
'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
# Let gyp-time envvars win over global settings.
@@ -2035,6 +2028,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
make_global_settings += 'endif\n'
else:
make_global_settings += '%s ?= %s\n' % (key, value)
+ # TODO(ukai): define cmd when only wrapper is specified in
+ # make_global_settings.
+
header_params['make_global_settings'] = make_global_settings
ensure_directory_exists(makefile_path)
diff --git a/tools/gyp/pylib/gyp/generator/msvs.py b/tools/gyp/pylib/gyp/generator/msvs.py
index 47cbd36ec6..51acf2eb3e 100644
--- a/tools/gyp/pylib/gyp/generator/msvs.py
+++ b/tools/gyp/pylib/gyp/generator/msvs.py
@@ -17,6 +17,7 @@ import gyp.MSVSProject as MSVSProject
import gyp.MSVSSettings as MSVSSettings
import gyp.MSVSToolFile as MSVSToolFile
import gyp.MSVSUserFile as MSVSUserFile
+import gyp.MSVSUtil as MSVSUtil
import gyp.MSVSVersion as MSVSVersion
from gyp.common import GypError
@@ -63,6 +64,7 @@ generator_additional_path_sections = [
generator_additional_non_configuration_keys = [
'msvs_cygwin_dirs',
'msvs_cygwin_shell',
+ 'msvs_large_pdb',
'msvs_shard',
]
@@ -204,6 +206,10 @@ def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None,
def _ToolAppend(tools, tool_name, setting, value, only_if_unset=False):
if not value: return
+ _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset)
+
+
+def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):
# TODO(bradnelson): ugly hack, fix this more generally!!!
if 'Directories' in setting or 'Dependencies' in setting:
if type(value) == str:
@@ -232,7 +238,7 @@ def _ConfigPlatform(config_data):
def _ConfigBaseName(config_name, platform_name):
if config_name.endswith('_' + platform_name):
- return config_name[0:-len(platform_name)-1]
+ return config_name[0:-len(platform_name) - 1]
else:
return config_name
@@ -270,7 +276,7 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
'`cygpath -m "${INPUTPATH}"`')
for i in direct_cmd]
direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd]
- #direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
+ # direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
direct_cmd = ' '.join(direct_cmd)
# TODO(quote): regularize quoting path names throughout the module
cmd = ''
@@ -306,7 +312,7 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
# If the argument starts with a slash or dash, it's probably a command line
# switch
arguments = [i if (i[:1] in "/-") else _FixPath(i) for i in cmd[1:]]
- arguments = [i.replace('$(InputDir)','%INPUTDIR%') for i in arguments]
+ arguments = [i.replace('$(InputDir)', '%INPUTDIR%') for i in arguments]
arguments = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments]
if quote_cmd:
# Support a mode for using cmd directly.
@@ -720,7 +726,7 @@ def _EscapeCommandLineArgumentForMSBuild(s):
"""Escapes a Windows command-line argument for use by MSBuild."""
def _Replace(match):
- return (len(match.group(1))/2*4)*'\\' + '\\"'
+ return (len(match.group(1)) / 2 * 4) * '\\' + '\\"'
# Escape all quotes so that they are interpreted literally.
s = quote_replacer_regex2.sub(_Replace, s)
@@ -1001,12 +1007,12 @@ def _GetMSVSConfigurationType(spec, build_file):
}[spec['type']]
except KeyError:
if spec.get('type'):
- raise Exception('Target type %s is not a valid target type for '
- 'target %s in %s.' %
- (spec['type'], spec['target_name'], build_file))
+ raise GypError('Target type %s is not a valid target type for '
+ 'target %s in %s.' %
+ (spec['type'], spec['target_name'], build_file))
else:
- raise Exception('Missing type field for target %s in %s.' %
- (spec['target_name'], build_file))
+ raise GypError('Missing type field for target %s in %s.' %
+ (spec['target_name'], build_file))
return config_type
@@ -1041,6 +1047,10 @@ def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
# Add in user specified msvs_settings.
msvs_settings = config.get('msvs_settings', {})
MSVSSettings.ValidateMSVSSettings(msvs_settings)
+
+ # Prevent default library inheritance from the environment.
+ _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', ['$(NOINHERIT)'])
+
for tool in msvs_settings:
settings = config['msvs_settings'][tool]
for setting in settings:
@@ -1663,7 +1673,7 @@ def _CreateProjectObjects(target_list, target_dicts, options, msvs_version):
for qualified_target in target_list:
spec = target_dicts[qualified_target]
if spec['toolset'] != 'target':
- raise Exception(
+ raise GypError(
'Multiple toolsets not supported in msvs build (target %s)' %
qualified_target)
proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec,
@@ -1718,74 +1728,6 @@ def CalculateVariables(default_variables, params):
default_variables['MSVS_OS_BITS'] = 32
-def _ShardName(name, number):
- """Add a shard number to the end of a target.
-
- Arguments:
- name: name of the target (foo#target)
- number: shard number
- Returns:
- Target name with shard added (foo_1#target)
- """
- parts = name.rsplit('#', 1)
- parts[0] = '%s_%d' % (parts[0], number)
- return '#'.join(parts)
-
-
-def _ShardTargets(target_list, target_dicts):
- """Shard some targets apart to work around the linkers limits.
-
- Arguments:
- target_list: List of target pairs: 'base/base.gyp:base'.
- target_dicts: Dict of target properties keyed on target pair.
- Returns:
- Tuple of the new sharded versions of the inputs.
- """
- # Gather the targets to shard, and how many pieces.
- targets_to_shard = {}
- for t in target_dicts:
- shards = int(target_dicts[t].get('msvs_shard', 0))
- if shards:
- targets_to_shard[t] = shards
- # Shard target_list.
- new_target_list = []
- for t in target_list:
- if t in targets_to_shard:
- for i in range(targets_to_shard[t]):
- new_target_list.append(_ShardName(t, i))
- else:
- new_target_list.append(t)
- # Shard target_dict.
- new_target_dicts = {}
- for t in target_dicts:
- if t in targets_to_shard:
- for i in range(targets_to_shard[t]):
- name = _ShardName(t, i)
- new_target_dicts[name] = copy.copy(target_dicts[t])
- new_target_dicts[name]['target_name'] = _ShardName(
- new_target_dicts[name]['target_name'], i)
- sources = new_target_dicts[name].get('sources', [])
- new_sources = []
- for pos in range(i, len(sources), targets_to_shard[t]):
- new_sources.append(sources[pos])
- new_target_dicts[name]['sources'] = new_sources
- else:
- new_target_dicts[t] = target_dicts[t]
- # Shard dependencies.
- for t in new_target_dicts:
- dependencies = copy.copy(new_target_dicts[t].get('dependencies', []))
- new_dependencies = []
- for d in dependencies:
- if d in targets_to_shard:
- for i in range(targets_to_shard[d]):
- new_dependencies.append(_ShardName(d, i))
- else:
- new_dependencies.append(d)
- new_target_dicts[t]['dependencies'] = new_dependencies
-
- return (new_target_list, new_target_dicts)
-
-
def PerformBuild(data, configurations, params):
options = params['options']
msvs_version = params['msvs_version']
@@ -1825,7 +1767,12 @@ def GenerateOutput(target_list, target_dicts, data, params):
generator_flags = params.get('generator_flags', {})
# Optionally shard targets marked with 'msvs_shard': SHARD_COUNT.
- (target_list, target_dicts) = _ShardTargets(target_list, target_dicts)
+ (target_list, target_dicts) = MSVSUtil.ShardTargets(target_list, target_dicts)
+
+ # Optionally use the large PDB workaround for targets marked with
+ # 'msvs_large_pdb': 1.
+ (target_list, target_dicts) = MSVSUtil.InsertLargePdbShims(
+ target_list, target_dicts, generator_default_variables)
# Prepare the set of configurations.
configs = set()
@@ -1872,9 +1819,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
error_message = "Missing input files:\n" + \
'\n'.join(set(missing_sources))
if generator_flags.get('msvs_error_on_missing_sources', False):
- raise Exception(error_message)
+ raise GypError(error_message)
else:
- print >>sys.stdout, "Warning: " + error_message
+ print >> sys.stdout, "Warning: " + error_message
def _GenerateMSBuildFiltersFile(filters_path, source_files,
@@ -2809,8 +2756,10 @@ def _FinalizeMSBuildSettings(spec, configuration):
'AdditionalIncludeDirectories', include_dirs)
_ToolAppend(msbuild_settings, 'ResourceCompile',
'AdditionalIncludeDirectories', resource_include_dirs)
- # Add in libraries.
- _ToolAppend(msbuild_settings, 'Link', 'AdditionalDependencies', libraries)
+ # Add in libraries, note that even for empty libraries, we want this
+ # set, to prevent inheriting default libraries from the enviroment.
+ _ToolSetOrAppend(msbuild_settings, 'Link', 'AdditionalDependencies',
+ libraries)
if out_file:
_ToolAppend(msbuild_settings, msbuild_tool, 'OutputFile', out_file,
only_if_unset=True)
@@ -2844,8 +2793,7 @@ def _GetValueFormattedForMSBuild(tool_name, name, value):
if type(value) == list:
# For some settings, VS2010 does not automatically extends the settings
# TODO(jeanluc) Is this what we want?
- if name in ['AdditionalDependencies',
- 'AdditionalIncludeDirectories',
+ if name in ['AdditionalIncludeDirectories',
'AdditionalLibraryDirectories',
'AdditionalOptions',
'DelayLoadDLLs',
diff --git a/tools/gyp/pylib/gyp/generator/ninja.py b/tools/gyp/pylib/gyp/generator/ninja.py
index fa6bd86ac3..c6bceaf382 100644
--- a/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/tools/gyp/pylib/gyp/generator/ninja.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# 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.
@@ -13,7 +13,7 @@ import sys
import gyp
import gyp.common
import gyp.msvs_emulation
-import gyp.MSVSVersion
+import gyp.MSVSUtil as MSVSUtil
import gyp.xcode_emulation
from gyp.common import GetEnvironFallback
@@ -97,21 +97,6 @@ def Define(d, flavor):
return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
-def InvertRelativePath(path):
- """Given a relative path like foo/bar, return the inverse relative path:
- the path from the relative path back to the origin dir.
-
- E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
- should always produce the empty string."""
-
- if not path:
- return path
- # Only need to handle relative paths into subdirectories for now.
- assert '..' not in path, path
- depth = len(path.split(os.path.sep))
- return os.path.sep.join(['..'] * depth)
-
-
class Target:
"""Target represents the paths used within a single gyp target.
@@ -218,12 +203,12 @@ class Target:
class NinjaWriter:
def __init__(self, qualified_target, target_outputs, base_dir, build_dir,
- output_file, flavor, abs_build_dir=None):
+ output_file, flavor, toplevel_dir=None):
"""
base_dir: path from source root to directory containing this gyp file,
by gyp semantics, all input paths are relative to this
build_dir: path from source root to build output
- abs_build_dir: absolute path to the build directory
+ toplevel_dir: path to the toplevel directory
"""
self.qualified_target = qualified_target
@@ -232,7 +217,10 @@ class NinjaWriter:
self.build_dir = build_dir
self.ninja = ninja_syntax.Writer(output_file)
self.flavor = flavor
- self.abs_build_dir = abs_build_dir
+ self.abs_build_dir = None
+ if toplevel_dir is not None:
+ self.abs_build_dir = os.path.abspath(os.path.join(toplevel_dir,
+ build_dir))
self.obj_ext = '.obj' if flavor == 'win' else '.o'
if flavor == 'win':
# See docstring of msvs_emulation.GenerateEnvironmentFiles().
@@ -241,9 +229,11 @@ class NinjaWriter:
self.win_env[arch] = 'environment.' + arch
# Relative path from build output dir to base dir.
- self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir)
+ build_to_top = gyp.common.InvertRelativePath(build_dir, toplevel_dir)
+ self.build_to_base = os.path.join(build_to_top, base_dir)
# Relative path from base dir to build dir.
- self.base_to_build = os.path.join(InvertRelativePath(base_dir), build_dir)
+ base_to_top = gyp.common.InvertRelativePath(base_dir, toplevel_dir)
+ self.base_to_build = os.path.join(base_to_top, build_dir)
def ExpandSpecial(self, path, product_dir=None):
"""Expand specials like $!PRODUCT_DIR in |path|.
@@ -428,7 +418,8 @@ class NinjaWriter:
gyp.msvs_emulation.VerifyMissingSources(
sources, self.abs_build_dir, generator_flags, self.GypPathToNinja)
pch = gyp.msvs_emulation.PrecompiledHeader(
- self.msvs_settings, config_name, self.GypPathToNinja)
+ self.msvs_settings, config_name, self.GypPathToNinja,
+ self.GypPathToUniqueOutput, self.obj_ext)
else:
pch = gyp.xcode_emulation.MacPrefixHeader(
self.xcode_settings, self.GypPathToNinja,
@@ -743,7 +734,15 @@ class NinjaWriter:
cflags_c = self.msvs_settings.GetCflagsC(config_name)
cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
extra_defines = self.msvs_settings.GetComputedDefines(config_name)
- self.WriteVariableList('pdbname', [self.name + '.pdb'])
+ pdbpath = self.msvs_settings.GetCompilerPdbName(
+ config_name, self.ExpandSpecial)
+ if not pdbpath:
+ 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', [])
@@ -824,9 +823,14 @@ class NinjaWriter:
if not case_sensitive_filesystem:
output = output.lower()
implicit = precompiled_header.GetObjDependencies([input], [output])
+ variables = []
+ if self.flavor == 'win':
+ variables, output, implicit = precompiled_header.GetFlagsModifications(
+ input, output, implicit, command, cflags_c, cflags_cc,
+ self.ExpandSpecial)
self.ninja.build(output, command, input,
implicit=[gch for _, _, gch in implicit],
- order_only=predepends)
+ order_only=predepends, variables=variables)
outputs.append(output)
self.WritePchTargets(pch_commands)
@@ -848,8 +852,6 @@ class NinjaWriter:
}[lang]
map = { 'c': 'cc', 'cc': 'cxx', 'm': 'objc', 'mm': 'objcxx', }
- if self.flavor == 'win':
- map.update({'c': 'cc_pch', 'cc': 'cxx_pch'})
cmd = map.get(lang)
self.ninja.build(gch, cmd, input, variables=[(var_name, lang_flag)])
@@ -903,16 +905,12 @@ class NinjaWriter:
extra_bindings.append(('postbuilds',
self.GetPostbuildCommand(spec, output, output)))
+ is_executable = spec['type'] == 'executable'
if self.flavor == 'mac':
ldflags = self.xcode_settings.GetLdflags(config_name,
self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
self.GypPathToNinja)
elif self.flavor == 'win':
- libflags = self.msvs_settings.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 = self.msvs_settings.GetLdflags(config_name,
@@ -920,6 +918,9 @@ class NinjaWriter:
self.WriteVariableList('manifests', manifest_files)
else:
ldflags = config.get('ldflags', [])
+ if is_executable and len(solibs):
+ ldflags.append('-Wl,-rpath=\$$ORIGIN/lib/')
+ ldflags.append('-Wl,-rpath-link=lib/')
self.WriteVariableList('ldflags',
gyp.common.uniquer(map(self.ExpandSpecial,
ldflags)))
@@ -975,6 +976,10 @@ class NinjaWriter:
self.ninja.build(self.target.binary, 'alink_thin', link_deps,
order_only=compile_deps, variables=variables)
else:
+ if self.msvs_settings:
+ libflags = self.msvs_settings.GetLibFlags(config_name,
+ self.GypPathToNinja)
+ variables.append(('libflags', libflags))
self.ninja.build(self.target.binary, 'alink', link_deps,
order_only=compile_deps, variables=variables)
else:
@@ -1046,10 +1051,9 @@ class NinjaWriter:
env = self.ComputeExportEnvString(self.GetSortedXcodePostbuildEnv())
# G will be non-null if any postbuild fails. Run all postbuilds in a
# subshell.
- commands = env + ' (F=0; ' + \
- ' '.join([ninja_syntax.escape(command) + ' || F=$$?;'
- for command in postbuilds])
- command_string = (commands + ' exit $$F); G=$$?; '
+ commands = env + ' (' + \
+ ' && '.join([ninja_syntax.escape(command) for command in postbuilds])
+ command_string = (commands + '); G=$$?; '
# Remove the final output if any postbuild failed.
'((exit $$G) || rm -rf %s) ' % output + '&& exit $$G)')
if is_command_start:
@@ -1315,6 +1319,13 @@ def OpenOutput(path, mode='w'):
return open(path, mode)
+def CommandWithWrapper(cmd, wrappers, prog):
+ wrapper = wrappers.get(cmd, '')
+ if wrapper:
+ return wrapper + ' ' + prog
+ return prog
+
+
def GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name):
options = params['options']
@@ -1372,7 +1383,14 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings = data[build_file].get('make_global_settings', [])
- build_to_root = InvertRelativePath(build_dir)
+ build_to_root = gyp.common.InvertRelativePath(build_dir,
+ options.toplevel_dir)
+ flock = 'flock'
+ if flavor == 'mac':
+ flock = './gyp-mac-tool flock'
+ wrappers = {}
+ if flavor != 'win':
+ wrappers['LINK'] = flock + ' linker.lock'
for key, value in make_global_settings:
if key == 'CC':
cc = os.path.join(build_to_root, value)
@@ -1388,14 +1406,13 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
cxx_host_global_setting = value
if key == 'LD.host':
ld_host = os.path.join(build_to_root, value)
+ if key.endswith('_wrapper'):
+ wrappers[key[:-len('_wrapper')]] = 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)
+ master_ninja.variable('cc', CommandWithWrapper('CC', wrappers, cc))
cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
- master_ninja.variable('cxx', cxx)
+ master_ninja.variable('cxx', CommandWithWrapper('CXX', wrappers, cxx))
ld = GetEnvironFallback(['LD_target', 'LD'], ld)
if not cc_host:
@@ -1412,7 +1429,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.variable('mt', 'mt.exe')
master_ninja.variable('use_dep_database', '1')
else:
- master_ninja.variable('ld', flock + ' linker.lock ' + ld)
+ master_ninja.variable('ld', CommandWithWrapper('LINK', wrappers, ld))
master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
@@ -1426,12 +1443,15 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
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('cc_host',
+ CommandWithWrapper('CC.host', wrappers, cc_host))
+ master_ninja.variable('cxx_host',
+ CommandWithWrapper('CXX.host', wrappers, cxx_host))
if flavor == 'win':
master_ninja.variable('ld_host', ld_host)
else:
- master_ninja.variable('ld_host', flock + ' linker.lock ' + ld_host)
+ master_ninja.variable('ld_host', CommandWithWrapper(
+ 'LINK', wrappers, ld_host))
master_ninja.newline()
@@ -1454,45 +1474,25 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'$cflags_pch_cc -c $in -o $out'),
depfile='$out.d')
else:
- # Template for compile commands mostly shared between compiling files
- # and generating PCH. In the case of PCH, the "output" is specified by /Fp
- # rather than /Fo (for object files), but we still need to specify an /Fo
- # when compiling PCH.
- cc_template = ('ninja -t msvc -r . -o $out -e $arch '
+ cc_command = ('ninja -t msvc -o $out -e $arch '
+ '-- '
+ '$cc /nologo /showIncludes /FC '
+ '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+ cxx_command = ('ninja -t msvc -o $out -e $arch '
'-- '
- '$cc /nologo /showIncludes /FC '
- '@$out.rsp '
- '$cflags_pch_c /c $in %(outspec)s /Fd$pdbname ')
- cxx_template = ('ninja -t msvc -r . -o $out -e $arch '
- '-- '
- '$cxx /nologo /showIncludes /FC '
- '@$out.rsp '
- '$cflags_pch_cc /c $in %(outspec)s $pchobj /Fd$pdbname ')
+ '$cxx /nologo /showIncludes /FC '
+ '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
master_ninja.rule(
'cc',
description='CC $out',
- command=cc_template % {'outspec': '/Fo$out'},
- depfile='$out.d',
- rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_c')
- master_ninja.rule(
- 'cc_pch',
- description='CC PCH $out',
- command=cc_template % {'outspec': '/Fp$out /Fo$out.obj'},
+ command=cc_command,
depfile='$out.d',
rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_c')
master_ninja.rule(
'cxx',
description='CXX $out',
- command=cxx_template % {'outspec': '/Fo$out'},
- depfile='$out.d',
- rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_cc')
- master_ninja.rule(
- 'cxx_pch',
- description='CXX PCH $out',
- command=cxx_template % {'outspec': '/Fp$out /Fo$out.obj'},
+ command=cxx_command,
depfile='$out.d',
rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_cc')
@@ -1559,7 +1559,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.rule(
'link',
description='LINK $out',
- command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib '
+ command=('$ld $ldflags -o $out '
'-Wl,--start-group $in $solibs -Wl,--end-group $libs'))
elif flavor == 'win':
master_ninja.rule(
@@ -1575,6 +1575,9 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'$ld /nologo $implibflag /DLL /OUT:$dll '
'/PDB:$dll.pdb @$dll.rsp' % sys.executable)
dllcmd += (' && %s gyp-win-tool manifest-wrapper $arch '
+ 'cmd /c if exist $dll.manifest del $dll.manifest' %
+ sys.executable)
+ dllcmd += (' && %s gyp-win-tool manifest-wrapper $arch '
'$mt -nologo -manifest $manifests -out:$dll.manifest' %
sys.executable)
master_ninja.rule('solink', description=dlldesc, command=dllcmd,
@@ -1593,8 +1596,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
command=('%s gyp-win-tool link-wrapper $arch '
'$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
'%s gyp-win-tool manifest-wrapper $arch '
+ 'cmd /c if exist $out.manifest del $out.manifest && '
+ '%s gyp-win-tool manifest-wrapper $arch '
'$mt -nologo -manifest $manifests -out:$out.manifest' %
- (sys.executable, sys.executable)),
+ (sys.executable, sys.executable, sys.executable)),
rspfile='$out.rsp',
rspfile_content='$in_newline $libs $ldflags')
else:
@@ -1729,7 +1734,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
abs_build_dir = os.path.abspath(toplevel_build)
writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir,
OpenOutput(os.path.join(toplevel_build, output_file)),
- flavor, abs_build_dir=abs_build_dir)
+ flavor, toplevel_dir=options.toplevel_dir)
master_ninja.subninja(output_file)
target = writer.WriteSpec(
@@ -1777,6 +1782,11 @@ def CallGenerateOutputForConfig(arglist):
def GenerateOutput(target_list, target_dicts, data, params):
user_config = params.get('generator_flags', {}).get('config', None)
+ if gyp.common.GetFlavor(params) == 'win':
+ target_list, target_dicts = MSVSUtil.ShardTargets(target_list, target_dicts)
+ target_list, target_dicts = MSVSUtil.InsertLargePdbShims(
+ target_list, target_dicts, generator_default_variables)
+
if user_config:
GenerateOutputForConfig(target_list, target_dicts, data, params,
user_config)
diff --git a/tools/gyp/pylib/gyp/generator/xcode.py b/tools/gyp/pylib/gyp/generator/xcode.py
index 7b21bae8a9..ca3b01eea0 100644
--- a/tools/gyp/pylib/gyp/generator/xcode.py
+++ b/tools/gyp/pylib/gyp/generator/xcode.py
@@ -1110,20 +1110,29 @@ exit 1
AddHeaderToTarget(header, pbxp, xct, True)
# Add "copies".
+ pbxcp_dict = {}
for copy_group in spec.get('copies', []):
- pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
- 'name': 'Copy to ' + copy_group['destination']
- },
- parent=xct)
dest = copy_group['destination']
if dest[0] not in ('/', '$'):
# Relative paths are relative to $(SRCROOT).
dest = '$(SRCROOT)/' + dest
- pbxcp.SetDestination(dest)
- # TODO(mark): The usual comment about this knowing too much about
- # gyp.xcodeproj_file internals applies.
- xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+ # Coalesce multiple "copies" sections in the same target with the same
+ # "destination" property into the same PBXCopyFilesBuildPhase, otherwise
+ # they'll wind up with ID collisions.
+ pbxcp = pbxcp_dict.get(dest, None)
+ if pbxcp is None:
+ pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
+ 'name': 'Copy to ' + copy_group['destination']
+ },
+ parent=xct)
+ pbxcp.SetDestination(dest)
+
+ # TODO(mark): The usual comment about this knowing too much about
+ # gyp.xcodeproj_file internals applies.
+ xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+
+ pbxcp_dict[dest] = pbxcp
for file in copy_group['files']:
pbxcp.AddFile(file)
diff --git a/tools/gyp/pylib/gyp/input.py b/tools/gyp/pylib/gyp/input.py
index 65236671f9..eca0eb93aa 100644
--- a/tools/gyp/pylib/gyp/input.py
+++ b/tools/gyp/pylib/gyp/input.py
@@ -46,21 +46,16 @@ base_path_sections = [
]
path_sections = []
+is_path_section_charset = set('=+?!')
+is_path_section_match_re = re.compile('_(dir|file|path)s?$')
def IsPathSection(section):
# If section ends in one of these characters, it's applied to a section
# without the trailing characters. '/' is notably absent from this list,
# because there's no way for a regular expression to be treated as a path.
- while section[-1:] in ('=', '+', '?', '!'):
- section = section[0:-1]
-
- if section in path_sections or \
- section.endswith('_dir') or section.endswith('_dirs') or \
- section.endswith('_file') or section.endswith('_files') or \
- section.endswith('_path') or section.endswith('_paths'):
- return True
- return False
-
+ while section[-1:] in is_path_section_charset:
+ section = section[:-1]
+ return section in path_sections or is_path_section_match_re.search(section)
# base_non_configuraiton_keys is a list of key names that belong in the target
# itself and should not be propagated into its configurations. It is merged
@@ -269,7 +264,7 @@ def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
aux_data[subdict_path]['included'] = []
aux_data[subdict_path]['included'].append(include)
- gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'" % include)
+ gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'", include)
MergeDicts(subdict,
LoadOneBuildFile(include, data, aux_data, variables, None,
@@ -359,7 +354,7 @@ def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
data['target_build_files'].add(build_file_path)
gyp.DebugOutput(gyp.DEBUG_INCLUDES,
- "Loading Target Build File '%s'" % build_file_path)
+ "Loading Target Build File '%s'", build_file_path)
build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables,
includes, True, check)
@@ -494,7 +489,7 @@ def CallLoadTargetBuildFile(global_flags,
aux_data_out,
dependencies)
except Exception, e:
- print "Exception: ", e
+ print >>sys.stderr, 'Exception: ', e
return None
@@ -569,6 +564,12 @@ def LoadTargetBuildFileParallel(build_file_path, data, aux_data,
parallel_state.condition.acquire()
while parallel_state.dependencies or parallel_state.pending:
if parallel_state.error:
+ print >>sys.stderr, (
+ '\n'
+ 'Note: an error occurred while running gyp using multiprocessing.\n'
+ 'For more verbose output, set GYP_PARALLEL=0 in your environment.\n'
+ 'If the error only occurs when GYP_PARALLEL=1, '
+ 'please report a bug!')
break
if not parallel_state.dependencies:
parallel_state.condition.wait()
@@ -608,32 +609,27 @@ def LoadTargetBuildFileParallel(build_file_path, data, aux_data,
# the input is something like "<(foo <(bar)) blah", then it would
# return (1, 13), indicating the entire string except for the leading
# "<" and trailing " blah".
-def FindEnclosingBracketGroup(input):
- brackets = { '}': '{',
- ']': '[',
- ')': '(', }
+LBRACKETS= set('{[(')
+BRACKETS = {'}': '{', ']': '[', ')': '('}
+def FindEnclosingBracketGroup(input_str):
stack = []
- count = 0
start = -1
- for char in input:
- if char in brackets.values():
+ for index, char in enumerate(input_str):
+ if char in LBRACKETS:
stack.append(char)
if start == -1:
- start = count
- if char in brackets.keys():
- try:
- last_bracket = stack.pop()
- except IndexError:
+ start = index
+ elif char in BRACKETS:
+ if not stack:
return (-1, -1)
- if last_bracket != brackets[char]:
+ if stack.pop() != BRACKETS[char]:
return (-1, -1)
- if len(stack) == 0:
- return (start, count + 1)
- count = count + 1
+ if not stack:
+ return (start, index + 1)
return (-1, -1)
-canonical_int_re = re.compile('^(0|-?[1-9][0-9]*)$')
+canonical_int_re = re.compile('(0|-?[1-9][0-9]*)$')
def IsStrCanonicalInt(string):
@@ -641,10 +637,7 @@ def IsStrCanonicalInt(string):
The canonical form is such that str(int(string)) == string.
"""
- if not isinstance(string, str) or not canonical_int_re.match(string):
- return False
-
- return True
+ return isinstance(string, str) and canonical_int_re.match(string)
# This matches things like "<(asdf)", "<!(cmd)", "<!@(cmd)", "<|(list)",
@@ -713,7 +706,7 @@ def ExpandVariables(input, phase, variables, build_file):
# Get the entire list of matches as a list of MatchObject instances.
# (using findall here would return strings instead of MatchObjects).
- matches = [match for match in variable_re.finditer(input_str)]
+ matches = list(variable_re.finditer(input_str))
if not matches:
return input_str
@@ -725,8 +718,7 @@ def ExpandVariables(input, phase, variables, build_file):
matches.reverse()
for match_group in matches:
match = match_group.groupdict()
- gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Matches: %s" % repr(match))
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Matches: %r", match)
# match['replace'] is the substring to look for, match['type']
# is the character code for the replacement type (< > <! >! <| >| <@
# >@ <!@ >!@), match['is_array'] contains a '[' for command
@@ -839,8 +831,8 @@ def ExpandVariables(input, phase, variables, build_file):
cached_value = cached_command_results.get(cache_key, None)
if cached_value is None:
gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Executing command '%s' in directory '%s'" %
- (contents,build_file_dir))
+ "Executing command '%s' in directory '%s'",
+ contents, build_file_dir)
replacement = ''
@@ -852,12 +844,17 @@ def ExpandVariables(input, phase, variables, build_file):
# <!(python modulename param eters). Do this in |build_file_dir|.
oldwd = os.getcwd() # Python doesn't like os.open('.'): no fchdir.
os.chdir(build_file_dir)
-
- parsed_contents = shlex.split(contents)
- py_module = __import__(parsed_contents[0])
- replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip()
-
- os.chdir(oldwd)
+ try:
+
+ parsed_contents = shlex.split(contents)
+ try:
+ py_module = __import__(parsed_contents[0])
+ except ImportError as e:
+ raise GypError("Error importing pymod_do_main"
+ "module (%s): %s" % (parsed_contents[0], e))
+ replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip()
+ finally:
+ os.chdir(oldwd)
assert replacement != None
elif command_string:
raise GypError("Unknown command string '%s' in '%s'." %
@@ -884,8 +881,8 @@ def ExpandVariables(input, phase, variables, build_file):
cached_command_results[cache_key] = replacement
else:
gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Had cache value for command '%s' in directory '%s'" %
- (contents,build_file_dir))
+ "Had cache value for command '%s' in directory '%s'",
+ contents,build_file_dir)
replacement = cached_value
else:
@@ -960,8 +957,7 @@ def ExpandVariables(input, phase, variables, build_file):
# Look for more matches now that we've replaced some, to deal with
# expanding local variables (variables defined in the same
# variables block as this one).
- gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Found output %s, recursing." % repr(output))
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output)
if isinstance(output, list):
if output and isinstance(output[0], list):
# Leave output alone if it's a list of lists.
@@ -1062,7 +1058,7 @@ def ProcessConditionsInDict(the_dict, phase, variables, build_file):
except NameError, e:
gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
(cond_expr_expanded, build_file))
- raise
+ raise GypError(e)
if merge_dict != None:
# Expand variables and nested conditinals in the merge_dict before
@@ -1407,6 +1403,25 @@ def RemoveDuplicateDependencies(targets):
target_dict[dependency_key] = Unify(dependencies)
+def Filter(l, item):
+ """Removes item from l."""
+ res = {}
+ return [res.setdefault(e, e) for e in l if e != 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 dependency_key in dependency_sections:
+ dependencies = target_dict.get(dependency_key, [])
+ if dependencies:
+ for t in dependencies:
+ if t == target_name:
+ if targets[t].get('variables', {}).get('prune_self_dependency', 0):
+ target_dict[dependency_key] = Filter(dependencies, target_name)
+
+
class DependencyGraphNode(object):
"""
@@ -1845,12 +1860,10 @@ def MakePathRelative(to_file, fro_file, item):
return ret
def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
- def is_hashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- return True
+ # Python documentation recommends objects which do not support hash
+ # set this value to None. Python library objects follow this rule.
+ is_hashable = lambda val: val.__hash__
+
# If x is hashable, returns whether x is in s. Else returns whether x is in l.
def is_in_set_or_list(x, s, l):
if is_hashable(x):
@@ -1861,8 +1874,7 @@ def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
# Make membership testing of hashables in |to| (in particular, strings)
# faster.
- hashable_to_set = set([x for x in to if is_hashable(x)])
-
+ hashable_to_set = set(x for x in to if is_hashable(x))
for item in fro:
singleton = False
if isinstance(item, str) or isinstance(item, int):
@@ -2056,7 +2068,7 @@ 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 in target_dict['configurations'].keys()
+ concrete = [i for i in target_dict['configurations'].iterkeys()
if not target_dict['configurations'][i].get('abstract')]
target_dict['default_configuration'] = sorted(concrete)[0]
@@ -2315,8 +2327,8 @@ def ValidateTargetType(target, target_dict):
def ValidateSourcesInTarget(target, target_dict, build_file):
- # TODO: Check if MSVC allows this for non-static_library targets.
- if target_dict.get('type', None) != 'static_library':
+ # TODO: Check if MSVC allows this for loadable_module targets.
+ if target_dict.get('type', None) not in ('static_library', 'shared_library'):
return
sources = target_dict.get('sources', [])
basenames = {}
@@ -2548,7 +2560,7 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
build_file = os.path.normpath(build_file)
try:
if parallel:
- print >>sys.stderr, 'Using parallel processing (experimental).'
+ print >>sys.stderr, 'Using parallel processing.'
LoadTargetBuildFileParallel(build_file, data, aux_data,
variables, includes, depth, check)
else:
@@ -2564,6 +2576,10 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
# Fully qualify all dependency links.
QualifyDependencies(targets)
+ # Remove self-dependencies from targets that have 'prune_self_dependencies'
+ # set to 1.
+ RemoveSelfDependencies(targets)
+
# Expand dependencies specified as build_file:*.
ExpandWildcardDependencies(targets, data)
diff --git a/tools/gyp/pylib/gyp/mac_tool.py b/tools/gyp/pylib/gyp/mac_tool.py
index 69267694dc..c06e3bebbf 100755
--- a/tools/gyp/pylib/gyp/mac_tool.py
+++ b/tools/gyp/pylib/gyp/mac_tool.py
@@ -80,6 +80,19 @@ class MacTool(object):
def _CopyStringsFile(self, source, dest):
"""Copies a .strings file using iconv to reconvert the input into UTF-16."""
input_code = self._DetectInputEncoding(source) or "UTF-8"
+
+ # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
+ # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
+ # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
+ # semicolon in dictionary.
+ # on invalid files. Do the same kind of validation.
+ import CoreFoundation
+ s = open(source).read()
+ d = CoreFoundation.CFDataCreate(None, s, len(s))
+ _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
+ if error:
+ return
+
fp = open(dest, 'w')
args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code',
'UTF-16', source]
diff --git a/tools/gyp/pylib/gyp/msvs_emulation.py b/tools/gyp/pylib/gyp/msvs_emulation.py
index 840a79b673..bc2afca3e0 100644
--- a/tools/gyp/pylib/gyp/msvs_emulation.py
+++ b/tools/gyp/pylib/gyp/msvs_emulation.py
@@ -168,8 +168,6 @@ class MsvsSettings(object):
equivalents."""
target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
replacements = {
- '$(VSInstallDir)': self.vs_version.Path(),
- '$(VCInstallDir)': os.path.join(self.vs_version.Path(), 'VC') + '\\',
'$(OutDir)\\': base_to_build + '\\' if base_to_build else '',
'$(IntDir)': '$!INTERMEDIATE_DIR',
'$(InputPath)': '${source}',
@@ -178,6 +176,12 @@ class MsvsSettings(object):
'$(PlatformName)': target_platform,
'$(ProjectDir)\\': '',
}
+ # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
+ # Visual Studio is actually installed.
+ if self.vs_version.Path():
+ replacements['$(VSInstallDir)'] = self.vs_version.Path()
+ replacements['$(VCInstallDir)'] = os.path.join(self.vs_version.Path(),
+ 'VC') + '\\'
# Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
# set. This happens when the SDK is sync'd via src-internal, rather than
# by typical end-user installation of the SDK. If it's not set, we don't
@@ -275,6 +279,16 @@ class MsvsSettings(object):
('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[]))
return defines
+ def GetCompilerPdbName(self, config, expand_special):
+ """Get the pdb file name that should be used for compiler invocations, or
+ None if there's no explicit name specified."""
+ config = self._TargetConfig(config)
+ pdbname = self._Setting(
+ ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config)
+ if pdbname:
+ pdbname = expand_special(self.ConvertVSMacros(pdbname))
+ return pdbname
+
def GetOutputName(self, config, expand_special):
"""Gets the explicitly overridden output name for a target or returns None
if it's not overridden."""
@@ -309,6 +323,7 @@ class MsvsSettings(object):
map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O')
cl('InlineFunctionExpansion', prefix='/Ob')
cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
+ cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi')
cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
cl('WholeProgramOptimization', map={'true': '/GL'})
cl('WarningLevel', prefix='/W')
@@ -323,8 +338,13 @@ class MsvsSettings(object):
cl('RuntimeLibrary',
map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
+ cl('DefaultCharIsUnsigned', map={'true': '/J'})
+ cl('TreatWChar_tAsBuiltInType',
+ map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t')
cl('EnablePREfast', map={'true': '/analyze'})
cl('AdditionalOptions', prefix='')
+ cflags.extend(['/FI' + f for f in self._Setting(
+ ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
# ninja handles parallelism by itself, don't have the compiler do it too.
cflags = filter(lambda x: not x.startswith('/MP'), cflags)
return cflags
@@ -378,6 +398,7 @@ class MsvsSettings(object):
'VCLibrarianTool', append=libflags)
libflags.extend(self._GetAdditionalLibraryDirectories(
'VCLibrarianTool', config, gyp_to_build_path))
+ lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
lib('AdditionalOptions')
return libflags
@@ -414,6 +435,7 @@ class MsvsSettings(object):
ldflags.append('/PDB:' + pdb)
ld('AdditionalOptions', prefix='')
ld('SubSystem', map={'1': 'CONSOLE', '2': 'WINDOWS'}, prefix='/SUBSYSTEM:')
+ ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
ld('RandomizedBaseAddress',
@@ -426,13 +448,11 @@ class MsvsSettings(object):
ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
ld('EntryPointSymbol', prefix='/ENTRY:')
- ld('Profile', map={ 'true': '/PROFILE'})
+ ld('Profile', map={'true': '/PROFILE'})
+ ld('LargeAddressAware',
+ map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
# TODO(scottmg): This should sort of be somewhere else (not really a flag).
ld('AdditionalDependencies', prefix='')
- # TODO(scottmg): These too.
- ldflags.extend(('kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib',
- 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib',
- 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'DelayImp.lib'))
# If the base address is not specifically controlled, DYNAMICBASE should
# be on by default.
@@ -576,7 +596,8 @@ class MsvsSettings(object):
('iid', iid),
('proxy', proxy)]
# TODO(scottmg): Are there configuration settings to set these flags?
- flags = ['/char', 'signed', '/env', 'win32', '/Oicf']
+ target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
+ flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
return outdir, output, variables, flags
@@ -586,29 +607,25 @@ def _LanguageMatchesForPch(source_ext, pch_source_ext):
return ((source_ext in c_exts and pch_source_ext in c_exts) or
(source_ext in cc_exts and pch_source_ext in cc_exts))
+
class PrecompiledHeader(object):
"""Helper to generate dependencies and build rules to handle generation of
precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
"""
- def __init__(self, settings, config, gyp_to_build_path):
+ def __init__(
+ self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext):
self.settings = settings
self.config = config
- self.gyp_to_build_path = gyp_to_build_path
+ pch_source = self.settings.msvs_precompiled_source[self.config]
+ self.pch_source = gyp_to_build_path(pch_source)
+ filename, _ = os.path.splitext(pch_source)
+ self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
def _PchHeader(self):
"""Get the header that will appear in an #include line for all source
files."""
return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
- def _PchSource(self):
- """Get the source file that is built once to compile the pch data."""
- return self.gyp_to_build_path(
- self.settings.msvs_precompiled_source[self.config])
-
- def _PchOutput(self):
- """Get the name of the output of the compiled pch data."""
- return '${pchprefix}.' + self._PchHeader() + '.pch'
-
def GetObjDependencies(self, sources, objs):
"""Given a list of sources files and the corresponding object files,
returns a list of the pch files that should be depended upon. The
@@ -616,24 +633,30 @@ class PrecompiledHeader(object):
with make.py on Mac, and xcode_emulation.py."""
if not self._PchHeader():
return []
- source = self._PchSource()
- assert source
- pch_ext = os.path.splitext(self._PchSource())[1]
+ pch_ext = os.path.splitext(self.pch_source)[1]
for source in sources:
if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
- return [(None, None, self._PchOutput())]
+ return [(None, None, self.output_obj)]
return []
def GetPchBuildCommands(self):
- """Returns [(path_to_pch, language_flag, language, header)].
- |path_to_gch| and |header| are relative to the build directory."""
- header = self._PchHeader()
- source = self._PchSource()
- if not source or not header:
- return []
- ext = os.path.splitext(source)[1]
- lang = 'c' if ext == '.c' else 'cc'
- return [(self._PchOutput(), '/Yc' + header, lang, source)]
+ """Not used on Windows as there are no additional build steps required
+ (instead, existing steps are modified in GetFlagsModifications below)."""
+ return []
+
+ def GetFlagsModifications(self, input, output, implicit, command,
+ cflags_c, cflags_cc, expand_special):
+ """Get the modified cflags and implicit dependencies that should be used
+ for the pch compilation step."""
+ if input == self.pch_source:
+ pch_output = ['/Yc' + self._PchHeader()]
+ if command == 'cxx':
+ return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
+ self.output_obj, [])
+ elif command == 'cc':
+ return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
+ self.output_obj, [])
+ return [], output, implicit
vs_version = None
@@ -711,7 +734,13 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out):
of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
sets up the environment, and then we do not prefix the compiler with
an absolute path, instead preferring something like "cl.exe" in the rule
- which will then run whichever the environment setup has put in the path."""
+ which will then run whichever the environment setup has put in the path.
+ When the following procedure to generate environment files does not
+ meet your requirement (e.g. for custom toolchains), you can pass
+ "-G ninja_use_custom_environment_files" to the gyp to suppress file
+ generation and use custom environment files prepared by yourself."""
+ if generator_flags.get('ninja_use_custom_environment_files', 0):
+ return
vs = GetVSVersion(generator_flags)
for arch in ('x86', 'x64'):
args = vs.SetupScript(arch)
diff --git a/tools/gyp/pylib/gyp/xcode_emulation.py b/tools/gyp/pylib/gyp/xcode_emulation.py
index ef5b46046e..806f92b57a 100644
--- a/tools/gyp/pylib/gyp/xcode_emulation.py
+++ b/tools/gyp/pylib/gyp/xcode_emulation.py
@@ -11,13 +11,16 @@ import gyp.common
import os.path
import re
import shlex
+import subprocess
+import sys
+from gyp.common import GypError
class XcodeSettings(object):
"""A class that understands the gyp 'xcode_settings' object."""
- # Computed lazily by _GetSdkBaseDir(). Shared by all XcodeSettings, so cached
+ # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
# at class-level for efficiency.
- _sdk_base_dir = None
+ _sdk_path_cache = {}
def __init__(self, spec):
self.spec = spec
@@ -219,34 +222,34 @@ class XcodeSettings(object):
else:
return self._GetStandaloneBinaryPath()
- def _GetSdkBaseDir(self):
- """Returns the root of the 'Developer' directory. On Xcode 4.2 and prior,
- this is usually just /Developer. Xcode 4.3 moved that folder into the Xcode
- bundle."""
- if not XcodeSettings._sdk_base_dir:
- import subprocess
- job = subprocess.Popen(['xcode-select', '-print-path'],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, err = job.communicate()
- if job.returncode != 0:
- print out
- raise Exception('Error %d running xcode-select' % job.returncode)
- # The Developer folder moved in Xcode 4.3.
- xcode43_sdk_path = os.path.join(
- out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
- if os.path.isdir(xcode43_sdk_path):
- XcodeSettings._sdk_base_dir = xcode43_sdk_path
- else:
- XcodeSettings._sdk_base_dir = os.path.join(out.rstrip(), 'SDKs')
- return XcodeSettings._sdk_base_dir
+ def _GetSdkVersionInfoItem(self, sdk, infoitem):
+ job = subprocess.Popen(['xcodebuild', '-version', '-sdk', sdk, infoitem],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out = job.communicate()[0]
+ if job.returncode != 0:
+ sys.stderr.write(out + '\n')
+ raise GypError('Error %d running xcodebuild' % job.returncode)
+ return out.rstrip('\n')
def _SdkPath(self):
- sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5')
- if sdk_root.startswith('macosx'):
- return os.path.join(self._GetSdkBaseDir(),
- 'MacOSX' + sdk_root[len('macosx'):] + '.sdk')
- return sdk_root
+ sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx')
+ if sdk_root not in XcodeSettings._sdk_path_cache:
+ XcodeSettings._sdk_path_cache[sdk_root] = self._GetSdkVersionInfoItem(
+ sdk_root, 'Path')
+ return XcodeSettings._sdk_path_cache[sdk_root]
+
+ def _AppendPlatformVersionMinFlags(self, lst):
+ self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+ if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings():
+ # TODO: Implement this better?
+ sdk_path_basename = os.path.basename(self._SdkPath())
+ if sdk_path_basename.lower().startswith('iphonesimulator'):
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+ '-mios-simulator-version-min=%s')
+ else:
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+ '-miphoneos-version-min=%s')
def GetCflags(self, configname):
"""Returns flags that need to be added to .c, .cc, .m, and .mm
@@ -261,6 +264,9 @@ class XcodeSettings(object):
if 'SDKROOT' in self._Settings():
cflags.append('-isysroot %s' % sdk_root)
+ if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
+ cflags.append('-Wconstant-conversion')
+
if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'):
cflags.append('-funsigned-char')
@@ -301,7 +307,7 @@ class XcodeSettings(object):
if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
cflags.append('-Wnewline-eof')
- self._Appendf(cflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+ self._AppendPlatformVersionMinFlags(cflags)
# TODO:
if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'):
@@ -354,6 +360,16 @@ class XcodeSettings(object):
"""Returns flags that need to be added to .cc, and .mm compilations."""
self.configname = configname
cflags_cc = []
+
+ clang_cxx_language_standard = self._Settings().get(
+ 'CLANG_CXX_LANGUAGE_STANDARD')
+ # Note: Don't make c++0x to c++11 so that c++0x can be used with older
+ # clangs that don't understand c++11 yet (like Xcode 4.2's).
+ if clang_cxx_language_standard:
+ cflags_cc.append('-std=%s' % clang_cxx_language_standard)
+
+ self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
+
if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'):
cflags_cc.append('-fno-rtti')
if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'):
@@ -362,6 +378,7 @@ class XcodeSettings(object):
cflags_cc.append('-fvisibility-inlines-hidden')
if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'):
cflags_cc.append('-fno-threadsafe-statics')
+ # Note: This flag is a no-op for clang, it only has an effect for gcc.
if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'):
cflags_cc.append('-Wno-invalid-offsetof')
@@ -524,8 +541,9 @@ class XcodeSettings(object):
ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s')
self._Appendf(
ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s')
- self._Appendf(
- ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+
+ self._AppendPlatformVersionMinFlags(ldflags)
+
if 'SDKROOT' in self._Settings():
ldflags.append('-isysroot ' + self._SdkPath())
@@ -1042,7 +1060,7 @@ def _TopologicallySortedEnvVarKeys(env):
order.reverse()
return order
except gyp.common.CycleError, e:
- raise Exception(
+ raise GypError(
'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
diff --git a/tools/gyp/pylib/gyp/xcodeproj_file.py b/tools/gyp/pylib/gyp/xcodeproj_file.py
index ec4cb96bc2..47712a7f6e 100644
--- a/tools/gyp/pylib/gyp/xcodeproj_file.py
+++ b/tools/gyp/pylib/gyp/xcodeproj_file.py
@@ -1503,6 +1503,7 @@ class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject):
'r': 'sourcecode.rez',
'rez': 'sourcecode.rez',
's': 'sourcecode.asm',
+ 'storyboard': 'file.storyboard',
'strings': 'text.plist.strings',
'ttf': 'file',
'xcconfig': 'text.xcconfig',
diff --git a/tools/gyp/tools/emacs/gyp-tests.el b/tools/gyp/tools/emacs/gyp-tests.el
index e988a350ed..11b8497886 100644
--- a/tools/gyp/tools/emacs/gyp-tests.el
+++ b/tools/gyp/tools/emacs/gyp-tests.el
@@ -26,11 +26,20 @@
(insert-file-contents-literally (concat filename ".fontified"))
(read (current-buffer))))
+(defun equivalent-face (face)
+ "For the purposes of face comparison, we're not interested in the
+ differences between certain faces. For example, the difference between
+ font-lock-comment-delimiter and font-lock-comment-face."
+ (case face
+ ((font-lock-comment-delimiter-face) font-lock-comment-face)
+ (t face)))
+
(defun text-face-properties (s)
"Extract the text properties from s"
(let ((result (list t)))
(dotimes (i (length s))
- (setq result (cons (get-text-property i 'face s) result)))
+ (setq result (cons (equivalent-face (get-text-property i 'face s))
+ result)))
(nreverse result)))
(ert-deftest test-golden-samples ()
diff --git a/tools/gyp/tools/emacs/gyp.el b/tools/gyp/tools/emacs/gyp.el
index c20fc8de97..f558b53135 100644
--- a/tools/gyp/tools/emacs/gyp.el
+++ b/tools/gyp/tools/emacs/gyp.el
@@ -135,7 +135,7 @@
(setq sections (cdr sections)) ; pop out a level
(cond ((looking-at-p "['\"]") ; a string
(setq string-start (point))
- (forward-sexp 1)
+ (goto-char (scan-sexps (point) 1))
(if (gyp-inside-dictionary-p)
;; Look for sections inside a dictionary
(let ((section (gyp-section-name