Browse Source

Upgrade GYP to r1477

v0.8.9-release
Ryan Dahl 13 years ago
parent
commit
f90c9ce0e2
  1. 10
      tools/gyp/gyptest.py
  2. 28
      tools/gyp/pylib/gyp/MSVSSettings.py
  3. 34
      tools/gyp/pylib/gyp/MSVSVersion.py
  4. 54
      tools/gyp/pylib/gyp/__init__.py
  5. 9
      tools/gyp/pylib/gyp/common.py
  6. 17
      tools/gyp/pylib/gyp/easy_xml.py
  7. 9
      tools/gyp/pylib/gyp/easy_xml_test.py
  8. 1077
      tools/gyp/pylib/gyp/generator/android.py
  9. 6
      tools/gyp/pylib/gyp/generator/eclipse.py
  10. 76
      tools/gyp/pylib/gyp/generator/make.py
  11. 83
      tools/gyp/pylib/gyp/generator/msvs.py
  12. 149
      tools/gyp/pylib/gyp/generator/ninja.py
  13. 16
      tools/gyp/pylib/gyp/generator/xcode.py
  14. 59
      tools/gyp/pylib/gyp/msvs_emulation.py
  15. 4
      tools/gyp/pylib/gyp/ninja_syntax.py
  16. 35
      tools/gyp/pylib/gyp/win_tool.py
  17. 12
      tools/gyp/pylib/gyp/xcode_emulation.py
  18. 10
      tools/gyp/pylib/gyp/xcodeproj_file.py
  19. 12
      tools/gyp/tools/emacs/README
  20. 54
      tools/gyp/tools/emacs/gyp-tests.el
  21. 251
      tools/gyp/tools/emacs/gyp.el
  22. 7
      tools/gyp/tools/emacs/run-unit-tests.sh
  23. 1105
      tools/gyp/tools/emacs/testdata/media.gyp
  24. 1107
      tools/gyp/tools/emacs/testdata/media.gyp.fontified

10
tools/gyp/gyptest.py

@ -153,6 +153,8 @@ def main(argv=None):
help="chdir to the specified directory") help="chdir to the specified directory")
parser.add_option("-f", "--format", action="store", default='', parser.add_option("-f", "--format", action="store", default='',
help="run tests with the specified formats") help="run tests with the specified formats")
parser.add_option("-G", '--gyp_option', action="append", default=[],
help="Add -G options to the gyp command line")
parser.add_option("-l", "--list", action="store_true", parser.add_option("-l", "--list", action="store_true",
help="list available tests and exit") help="list available tests and exit")
parser.add_option("-n", "--no-exec", action="store_true", parser.add_option("-n", "--no-exec", action="store_true",
@ -220,8 +222,14 @@ def main(argv=None):
if not opts.quiet: if not opts.quiet:
sys.stdout.write('TESTGYP_FORMAT=%s\n' % format) sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
gyp_options = []
for option in opts.gyp_option:
gyp_options += ['-G', option]
if gyp_options and not opts.quiet:
sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
for test in tests: for test in tests:
status = cr.run([sys.executable, test], status = cr.run([sys.executable, test] + gyp_options,
stdout=sys.stdout, stdout=sys.stdout,
stderr=sys.stderr) stderr=sys.stderr)
if status == 2: if status == 2:

28
tools/gyp/pylib/gyp/MSVSSettings.py

@ -1,4 +1,4 @@
# Copyright (c) 2012 The Chromium Authors. All rights reserved. # Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
@ -15,7 +15,7 @@ MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
""" """
import sys import sys
import re
# Dictionaries of settings validators. The key is the tool name, the value is # Dictionaries of settings validators. The key is the tool name, the value is
# a dictionary mapping setting names to validation functions. # a dictionary mapping setting names to validation functions.
@ -362,6 +362,24 @@ def _CustomGeneratePreprocessedFile(tool, msvs_name):
_msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate
fix_vc_macro_slashes_regex_list = ('IntDir', 'OutDir')
fix_vc_macro_slashes_regex = re.compile(
r'(\$\((?:%s)\))(?:[\\/]+)' % "|".join(fix_vc_macro_slashes_regex_list)
)
def FixVCMacroSlashes(s):
"""Replace macros which have excessive following slashes.
These macros are known to have a built-in trailing slash. Furthermore, many
scripts hiccup on processing paths with extra slashes in the middle.
This list is probably not exhaustive. Add as needed.
"""
if '$' in s:
s = fix_vc_macro_slashes_regex.sub(r'\1', s)
return s
def ConvertVCMacrosToMSBuild(s): def ConvertVCMacrosToMSBuild(s):
"""Convert the the MSVS macros found in the string to the MSBuild equivalent. """Convert the the MSVS macros found in the string to the MSBuild equivalent.
@ -378,14 +396,10 @@ def ConvertVCMacrosToMSBuild(s):
'$(ParentName)': '$(ProjectFileName)', '$(ParentName)': '$(ProjectFileName)',
'$(PlatformName)': '$(Platform)', '$(PlatformName)': '$(Platform)',
'$(SafeInputName)': '%(Filename)', '$(SafeInputName)': '%(Filename)',
'$(IntDir)\\': '$(IntDir)',
'$(OutDir)\\': '$(OutDir)',
'$(IntDir)/': '$(IntDir)',
'$(OutDir)/': '$(OutDir)',
} }
for old, new in replace_map.iteritems(): for old, new in replace_map.iteritems():
s = s.replace(old, new) s = s.replace(old, new)
s = FixVCMacroSlashes(s)
return s return s

34
tools/gyp/pylib/gyp/MSVSVersion.py

@ -16,7 +16,7 @@ class VisualStudioVersion(object):
def __init__(self, short_name, description, def __init__(self, short_name, description,
solution_version, project_version, flat_sln, uses_vcxproj, solution_version, project_version, flat_sln, uses_vcxproj,
path, sdk_based): path, sdk_based, default_toolset=None):
self.short_name = short_name self.short_name = short_name
self.description = description self.description = description
self.solution_version = solution_version self.solution_version = solution_version
@ -25,6 +25,7 @@ class VisualStudioVersion(object):
self.uses_vcxproj = uses_vcxproj self.uses_vcxproj = uses_vcxproj
self.path = path self.path = path
self.sdk_based = sdk_based self.sdk_based = sdk_based
self.default_toolset = default_toolset
def ShortName(self): def ShortName(self):
return self.short_name return self.short_name
@ -60,6 +61,11 @@ class VisualStudioVersion(object):
"""Returns the path to a given compiler tool. """ """Returns the path to a given compiler tool. """
return os.path.normpath(os.path.join(self.path, "VC/bin", tool)) return os.path.normpath(os.path.join(self.path, "VC/bin", tool))
def DefaultToolset(self):
"""Returns the msbuild toolset version that will be used in the absence
of a user override."""
return self.default_toolset
def SetupScript(self, target_arch): def SetupScript(self, target_arch):
"""Returns a command (with arguments) to be used to set up the """Returns a command (with arguments) to be used to set up the
environment.""" environment."""
@ -188,6 +194,24 @@ def _CreateVersion(name, path, sdk_based=False):
passed in that doesn't match a value in versions python will throw a error. passed in that doesn't match a value in versions python will throw a error.
""" """
versions = { versions = {
'2012': VisualStudioVersion('2012',
'Visual Studio 2012',
solution_version='12.00',
project_version='4.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v110'),
'2012e': VisualStudioVersion('2012e',
'Visual Studio 2012',
solution_version='12.00',
project_version='4.0',
flat_sln=True,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v110'),
'2010': VisualStudioVersion('2010', '2010': VisualStudioVersion('2010',
'Visual Studio 2010', 'Visual Studio 2010',
solution_version='11.00', solution_version='11.00',
@ -252,9 +276,11 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
2005(e) - Visual Studio 2005 (8) 2005(e) - Visual Studio 2005 (8)
2008(e) - Visual Studio 2008 (9) 2008(e) - Visual Studio 2008 (9)
2010(e) - Visual Studio 2010 (10) 2010(e) - Visual Studio 2010 (10)
2012(e) - Visual Studio 2012 (11)
Where (e) is e for express editions of MSVS and blank otherwise. Where (e) is e for express editions of MSVS and blank otherwise.
""" """
version_to_year = {'8.0': '2005', '9.0': '2008', '10.0': '2010'} version_to_year = {
'8.0': '2005', '9.0': '2008', '10.0': '2010', '11.0': '2012'}
versions = [] versions = []
for version in versions_to_check: for version in versions_to_check:
# Old method of searching for which VS version is installed # Old method of searching for which VS version is installed
@ -306,13 +332,15 @@ def SelectVisualStudioVersion(version='auto'):
if version == 'auto': if version == 'auto':
version = os.environ.get('GYP_MSVS_VERSION', 'auto') version = os.environ.get('GYP_MSVS_VERSION', 'auto')
version_map = { version_map = {
'auto': ('10.0', '9.0', '8.0'), 'auto': ('10.0', '9.0', '8.0', '11.0'),
'2005': ('8.0',), '2005': ('8.0',),
'2005e': ('8.0',), '2005e': ('8.0',),
'2008': ('9.0',), '2008': ('9.0',),
'2008e': ('9.0',), '2008e': ('9.0',),
'2010': ('10.0',), '2010': ('10.0',),
'2010e': ('10.0',), '2010e': ('10.0',),
'2012': ('11.0',),
'2012e': ('11.0',),
} }
version = str(version) version = str(version)
versions = _DetectVisualStudioVersions(version_map[version], 'e' in version) versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)

54
tools/gyp/pylib/gyp/__init__.py

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (c) 2011 Google Inc. All rights reserved. # Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
@ -39,11 +39,18 @@ def FindBuildFiles():
files = os.listdir(os.getcwd()) files = os.listdir(os.getcwd())
build_files = [] build_files = []
for file in files: for file in files:
if file[-len(extension):] == extension: if file.endswith(extension):
build_files.append(file) build_files.append(file)
return build_files return build_files
class GypError(Exception):
"""Error class representing an error, which is to be presented
to the user. The main entry point will catch and display this.
"""
pass
def Load(build_files, format, default_variables={}, def Load(build_files, format, default_variables={},
includes=[], depth='.', params=None, check=False, circular_check=True): includes=[], depth='.', params=None, check=False, circular_check=True):
""" """
@ -66,7 +73,22 @@ def Load(build_files, format, default_variables={},
# avoiding collisions with user and automatic variables. # avoiding collisions with user and automatic variables.
default_variables['GENERATOR'] = format default_variables['GENERATOR'] = format
generator_name = 'gyp.generator.' + format # Format can be a custom python file, or by default the name of a module
# within gyp.generator.
if format.endswith('.py'):
generator_name = os.path.splitext(format)[0]
path, generator_name = os.path.split(generator_name)
# Make sure the path to the custom generator is in sys.path
# Don't worry about removing it once we are done. Keeping the path
# to each generator that is used in sys.path is likely harmless and
# arguably a good idea.
path = os.path.abspath(path)
if path not in sys.path:
sys.path.insert(0, path)
else:
generator_name = 'gyp.generator.' + format
# These parameters are passed in order (as opposed to by key) # These parameters are passed in order (as opposed to by key)
# because ActivePython cannot handle key parameters to __import__. # because ActivePython cannot handle key parameters to __import__.
generator = __import__(generator_name, globals(), locals(), generator_name) generator = __import__(generator_name, globals(), locals(), generator_name)
@ -157,7 +179,10 @@ def RegenerateAppendFlag(flag, values, predicate, env_name, options):
flags = [] flags = []
if options.use_environment and env_name: if options.use_environment and env_name:
for flag_value in ShlexEnv(env_name): for flag_value in ShlexEnv(env_name):
flags.append(FormatOpt(flag, predicate(flag_value))) value = FormatOpt(flag, predicate(flag_value))
if value in flags:
flags.remove(value)
flags.append(value)
if values: if values:
for flag_value in values: for flag_value in values:
flags.append(FormatOpt(flag, predicate(flag_value))) flags.append(FormatOpt(flag, predicate(flag_value)))
@ -254,7 +279,7 @@ class RegeneratableOptionParser(optparse.OptionParser):
values._regeneration_metadata = self.__regeneratable_options values._regeneration_metadata = self.__regeneratable_options
return values, args return values, args
def main(args): def gyp_main(args):
my_name = os.path.basename(sys.argv[0]) my_name = os.path.basename(sys.argv[0])
parser = RegeneratableOptionParser() parser = RegeneratableOptionParser()
@ -366,9 +391,8 @@ def main(args):
if not build_files: if not build_files:
build_files = FindBuildFiles() build_files = FindBuildFiles()
if not build_files: if not build_files:
print >>sys.stderr, (usage + '\n\n%s: error: no build_file') % \ raise GypError((usage + '\n\n%s: error: no build_file') %
(my_name, my_name) (my_name, my_name))
return 1
# TODO(mark): Chromium-specific hack! # TODO(mark): Chromium-specific hack!
# For Chromium, the gyp "depth" variable should always be a relative path # For Chromium, the gyp "depth" variable should always be a relative path
@ -393,10 +417,9 @@ def main(args):
break break
if not options.depth: if not options.depth:
raise Exception, \ raise GypError('Could not automatically locate src directory. This is'
'Could not automatically locate src directory. This is a ' + \ 'a temporary Chromium feature that will be removed. Use'
'temporary Chromium feature that will be removed. Use ' + \ '--depth as a workaround.')
'--depth as a workaround.'
# If toplevel-dir is not set, we assume that depth is the root of our source # If toplevel-dir is not set, we assume that depth is the root of our source
# tree. # tree.
@ -483,5 +506,12 @@ def main(args):
return 0 return 0
def main(args):
try:
return gyp_main(args)
except GypError, e:
sys.stderr.write("gyp: %s\n" % e)
return 1
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv[1:])) sys.exit(main(sys.argv[1:]))

9
tools/gyp/pylib/gyp/common.py

@ -95,6 +95,15 @@ def BuildFile(fully_qualified_target):
return ParseQualifiedTarget(fully_qualified_target)[0] return ParseQualifiedTarget(fully_qualified_target)[0]
def GetEnvironFallback(var_list, default):
"""Look up a key in the environment, with fallback to secondary keys
and finally falling back to a default value."""
for var in var_list:
if var in os.environ:
return os.environ[var]
return default
def QualifiedTarget(build_file, target, toolset): def QualifiedTarget(build_file, target, toolset):
# "Qualified" means the file that a target was defined in and the target # "Qualified" means the file that a target was defined in and the target
# name, separated by a colon, suffixed by a # and the toolset name: # name, separated by a colon, suffixed by a # and the toolset name:

17
tools/gyp/pylib/gyp/easy_xml.py

@ -3,6 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
import re import re
import os
def XmlToString(content, encoding='utf-8', pretty=False): def XmlToString(content, encoding='utf-8', pretty=False):
@ -79,7 +80,7 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
rest = specification[1:] rest = specification[1:]
if rest and isinstance(rest[0], dict): if rest and isinstance(rest[0], dict):
for at, val in sorted(rest[0].iteritems()): for at, val in sorted(rest[0].iteritems()):
xml_parts.append(' %s="%s"' % (at, _XmlEscape(val))) xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
rest = rest[1:] rest = rest[1:]
if rest: if rest:
xml_parts.append('>') xml_parts.append('>')
@ -101,7 +102,8 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
xml_parts.append('/>%s' % new_line) xml_parts.append('/>%s' % new_line)
def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False): def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
win32=False):
""" Writes the XML content to disk, touching the file only if it has changed. """ Writes the XML content to disk, touching the file only if it has changed.
Args: Args:
@ -111,6 +113,8 @@ def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False):
pretty: True if we want pretty printing with indents and new lines. pretty: True if we want pretty printing with indents and new lines.
""" """
xml_string = XmlToString(content, encoding, pretty) xml_string = XmlToString(content, encoding, pretty)
if win32 and os.linesep != '\r\n':
xml_string = xml_string.replace('\n', '\r\n')
# Get the old content # Get the old content
try: try:
@ -142,7 +146,12 @@ _xml_escape_re = re.compile(
"(%s)" % "|".join(map(re.escape, _xml_escape_map.keys()))) "(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
def _XmlEscape(value): def _XmlEscape(value, attr=False):
""" Escape a string for inclusion in XML.""" """ Escape a string for inclusion in XML."""
replace = lambda m: _xml_escape_map[m.string[m.start() : m.end()]] def replace(match):
m = match.string[match.start() : match.end()]
# don't replace single quotes in attrs
if attr and m == "'":
return m
return _xml_escape_map[m]
return _xml_escape_re.sub(replace, value) return _xml_escape_re.sub(replace, value)

9
tools/gyp/pylib/gyp/easy_xml_test.py

@ -32,11 +32,12 @@ class TestSequenceFunctions(unittest.TestCase):
def test_EasyXml_escaping(self): def test_EasyXml_escaping(self):
original = '<test>\'"\r&\nfoo' original = '<test>\'"\r&\nfoo'
converted = '&lt;test&gt;&apos;&quot;&#xD;&amp;&#xA;foo' converted = '&lt;test&gt;\'&quot;&#xD;&amp;&#xA;foo'
converted_apos = converted.replace("'", '&apos;')
self.assertEqual( self.assertEqual(
easy_xml.XmlToString(['test3', {'a': original}, original]), easy_xml.XmlToString(['test3', {'a': original}, original]),
'<?xml version="1.0" encoding="utf-8"?><test3 a="%s">%s</test3>' % '<?xml version="1.0" encoding="utf-8"?><test3 a="%s">%s</test3>' %
(converted, converted)) (converted, converted_apos))
def test_EasyXml_pretty(self): def test_EasyXml_pretty(self):
self.assertEqual( self.assertEqual(
@ -73,8 +74,8 @@ class TestSequenceFunctions(unittest.TestCase):
'</PropertyGroup>' '</PropertyGroup>'
'<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>' '<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>'
'<PropertyGroup ' '<PropertyGroup '
'Condition="&apos;$(Configuration)|$(Platform)&apos;==' 'Condition="\'$(Configuration)|$(Platform)\'=='
'&apos;Debug|Win32&apos;" Label="Configuration">' '\'Debug|Win32\'" Label="Configuration">'
'<ConfigurationType>Application</ConfigurationType>' '<ConfigurationType>Application</ConfigurationType>'
'<CharacterSet>Unicode</CharacterSet>' '<CharacterSet>Unicode</CharacterSet>'
'</PropertyGroup>' '</PropertyGroup>'

1077
tools/gyp/pylib/gyp/generator/android.py

File diff suppressed because it is too large

6
tools/gyp/pylib/gyp/generator/eclipse.py

@ -17,6 +17,7 @@ still result in a few indexer issues here and there.
This generator has no automated tests, so expect it to be broken. This generator has no automated tests, so expect it to be broken.
""" """
from xml.sax.saxutils import escape
import os.path import os.path
import subprocess import subprocess
import gyp import gyp
@ -36,7 +37,8 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX']: 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
'CONFIGURATION_NAME']:
generator_default_variables[unused] = '' generator_default_variables[unused] = ''
# Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as # Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as
@ -216,7 +218,7 @@ def WriteMacros(out, eclipse_langs, defines):
out.write(' <language name="%s">\n' % lang) out.write(' <language name="%s">\n' % lang)
for key in sorted(defines.iterkeys()): for key in sorted(defines.iterkeys()):
out.write(' <macro><name>%s</name><value>%s</value></macro>\n' % out.write(' <macro><name>%s</name><value>%s</value></macro>\n' %
(key, defines[key])) (escape(key), escape(defines[key])))
out.write(' </language>\n') out.write(' </language>\n')
out.write(' </section>\n') out.write(' </section>\n')

76
tools/gyp/pylib/gyp/generator/make.py

@ -21,13 +21,14 @@
# toplevel Makefile. It may make sense to generate some .mk files on # toplevel Makefile. It may make sense to generate some .mk files on
# the side to keep the the files readable. # the side to keep the the files readable.
import os
import re
import sys
import gyp import gyp
import gyp.common import gyp.common
import gyp.system_test import gyp.system_test
import gyp.xcode_emulation import gyp.xcode_emulation
import os from gyp.common import GetEnvironFallback
import re
import sys
generator_default_variables = { generator_default_variables = {
'EXECUTABLE_PREFIX': '', 'EXECUTABLE_PREFIX': '',
@ -60,7 +61,6 @@ generator_extra_sources_for_rules = []
def CalculateVariables(default_variables, params): def CalculateVariables(default_variables, params):
"""Calculate additional variables for use in the build (called by gyp).""" """Calculate additional variables for use in the build (called by gyp)."""
cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
flavor = gyp.common.GetFlavor(params) flavor = gyp.common.GetFlavor(params)
if flavor == 'mac': if flavor == 'mac':
default_variables.setdefault('OS', 'mac') default_variables.setdefault('OS', 'mac')
@ -255,11 +255,11 @@ all_deps :=
# This will allow make to invoke N linker processes as specified in -jN. # 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)
CC.target ?= $(CC) CC.target ?= %(CC.target)s
CFLAGS.target ?= $(CFLAGS) CFLAGS.target ?= $(CFLAGS)
CXX.target ?= $(CXX) CXX.target ?= %(CXX.target)s
CXXFLAGS.target ?= $(CXXFLAGS) CXXFLAGS.target ?= $(CXXFLAGS)
LINK.target ?= $(LINK) LINK.target ?= %(LINK.target)s
LDFLAGS.target ?= $(LDFLAGS) LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR) AR.target ?= $(AR)
ARFLAGS.target ?= %(ARFLAGS.target)s ARFLAGS.target ?= %(ARFLAGS.target)s
@ -268,13 +268,13 @@ ARFLAGS.target ?= %(ARFLAGS.target)s
# in gyp's make.py where ARFLAGS.host etc. is computed. # in gyp's make.py where ARFLAGS.host etc. is computed.
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need # TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well. # to replicate this environment fallback in make as well.
CC.host ?= gcc CC.host ?= %(CC.host)s
CFLAGS.host ?= CFLAGS.host ?=
CXX.host ?= g++ CXX.host ?= %(CXX.host)s
CXXFLAGS.host ?= CXXFLAGS.host ?=
LINK.host ?= g++ LINK.host ?= %(LINK.host)s
LDFLAGS.host ?= LDFLAGS.host ?=
AR.host ?= ar AR.host ?= %(AR.host)s
ARFLAGS.host := %(ARFLAGS.host)s ARFLAGS.host := %(ARFLAGS.host)s
# Define a dir function that can handle spaces. # Define a dir function that can handle spaces.
@ -1590,18 +1590,19 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
phony = True) phony = True)
def WriteList(self, list, variable=None, prefix='', quoter=QuoteIfNecessary): def WriteList(self, value_list, variable=None, prefix='',
quoter=QuoteIfNecessary):
"""Write a variable definition that is a list of values. """Write a variable definition that is a list of values.
E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
foo = blaha blahb foo = blaha blahb
but in a pretty-printed style. but in a pretty-printed style.
""" """
self.fp.write(variable + " := ") values = ''
if list: if value_list:
list = [quoter(prefix + l) for l in list] value_list = [quoter(prefix + l) for l in value_list]
self.fp.write(" \\\n\t".join(list)) values = ' \\\n\t' + ' \\\n\t'.join(value_list)
self.fp.write("\n\n") self.fp.write('%s :=%s\n\n' % (variable, values))
def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None, def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None,
@ -1810,8 +1811,9 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
"""Convert a path to its output directory form.""" """Convert a path to its output directory form."""
if '$(' in path: if '$(' in path:
path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset) path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
return path if not '$(obj)' in path:
return '$(obj).%s/$(TARGET)/%s' % (self.toolset, path) path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
return path
def Pchify(self, path, lang): def Pchify(self, path, lang):
@ -1890,8 +1892,8 @@ def RunSystemTests(flavor):
# Compute flags used for building static archives. # Compute flags used for building static archives.
# N.B.: this fallback logic should match the logic in SHARED_HEADER. # N.B.: this fallback logic should match the logic in SHARED_HEADER.
# See comment there for more details. # See comment there for more details.
ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar')) ar_target = GetEnvironFallback(('AR_target', 'AR'), 'ar')
cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc')) cc_target = GetEnvironFallback(('CC_target', 'CC'), 'cc')
arflags_target = 'crs' arflags_target = 'crs'
# ar -T enables thin archives on Linux. OS X's ar supports a -T flag, but it # ar -T enables thin archives on Linux. OS X's ar supports a -T flag, but it
# does something useless (it limits filenames in the archive to 15 chars). # does something useless (it limits filenames in the archive to 15 chars).
@ -1899,12 +1901,12 @@ def RunSystemTests(flavor):
cc_command=cc_target): cc_command=cc_target):
arflags_target = 'crsT' arflags_target = 'crsT'
ar_host = os.environ.get('AR.host', 'ar') ar_host = os.environ.get('AR_host', 'ar')
cc_host = os.environ.get('CC.host', 'gcc') cc_host = os.environ.get('CC_host', 'gcc')
arflags_host = 'crs' arflags_host = 'crs'
# It feels redundant to compute this again given that most builds aren't # It feels redundant to compute this again given that most builds aren't
# cross-compiles, but due to quirks of history CC.host defaults to 'gcc' # cross-compiles, but due to quirks of history CC_host defaults to 'gcc'
# while CC.target defaults to 'cc', so the commands really are different # while CC_target defaults to 'cc', so the commands really are different
# even though they're nearly guaranteed to run the same code underneath. # even though they're nearly guaranteed to run the same code underneath.
if flavor != 'mac' and gyp.system_test.TestArSupportsT(ar_command=ar_host, if flavor != 'mac' and gyp.system_test.TestArSupportsT(ar_command=ar_host,
cc_command=cc_host): cc_command=cc_host):
@ -1993,18 +1995,29 @@ def GenerateOutput(target_list, target_dicts, data, params):
header_params.update({ header_params.update({
'flock': 'lockf', 'flock': 'lockf',
}) })
header_params.update(RunSystemTests(flavor)) header_params.update(RunSystemTests(flavor))
header_params.update({
'CC.target': GetEnvironFallback(('CC_target', 'CC'), '$(CC)'),
'AR.target': GetEnvironFallback(('AR_target', 'AR'), '$(AR)'),
'CXX.target': GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'),
'LINK.target': GetEnvironFallback(('LD_target', 'LD'), '$(LINK)'),
'CC.host': GetEnvironFallback(('CC_host',), 'gcc'),
'AR.host': GetEnvironFallback(('AR_host',), 'ar'),
'CXX.host': GetEnvironFallback(('CXX_host',), 'g++'),
'LINK.host': GetEnvironFallback(('LD_host',), 'g++'),
})
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings_dict = data[build_file].get('make_global_settings', {}) make_global_settings_array = data[build_file].get('make_global_settings', [])
make_global_settings = '' make_global_settings = ''
for key, value in make_global_settings_dict: for key, value in make_global_settings_array:
if value[0] != '$': if value[0] != '$':
value = '$(abspath %s)' % value value = '$(abspath %s)' % value
if key == 'LINK': if key == 'LINK':
make_global_settings += ('%s ?= %s $(builddir)/linker.lock %s\n' % make_global_settings += ('%s ?= %s $(builddir)/linker.lock %s\n' %
(key, flock_command, value)) (key, flock_command, value))
elif key in ['CC', 'CXX']: elif key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
make_global_settings += ( make_global_settings += (
'ifneq (,$(filter $(origin %s), undefined default))\n' % key) 'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
# Let gyp-time envvars win over global settings. # Let gyp-time envvars win over global settings.
@ -2046,8 +2059,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
build_file, target, toolset = gyp.common.ParseQualifiedTarget( build_file, target, toolset = gyp.common.ParseQualifiedTarget(
qualified_target) qualified_target)
this_make_global_settings = data[build_file].get('make_global_settings', {}) this_make_global_settings = data[build_file].get('make_global_settings', [])
assert make_global_settings_dict == this_make_global_settings, ( assert make_global_settings_array == this_make_global_settings, (
"make_global_settings needs to be the same for all targets.") "make_global_settings needs to be the same for all targets.")
build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir)) build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
@ -2123,7 +2136,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
root_makefile.write("endif\n") root_makefile.write("endif\n")
root_makefile.write('\n') root_makefile.write('\n')
if generator_flags.get('auto_regeneration', True): if (not generator_flags.get('standalone')
and generator_flags.get('auto_regeneration', True)):
WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files) WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
root_makefile.write(SHARED_FOOTER) root_makefile.write(SHARED_FOOTER)

83
tools/gyp/pylib/gyp/generator/msvs.py

@ -39,10 +39,10 @@ generator_default_variables = {
'STATIC_LIB_SUFFIX': '.lib', 'STATIC_LIB_SUFFIX': '.lib',
'SHARED_LIB_SUFFIX': '.dll', 'SHARED_LIB_SUFFIX': '.dll',
'INTERMEDIATE_DIR': '$(IntDir)', 'INTERMEDIATE_DIR': '$(IntDir)',
'SHARED_INTERMEDIATE_DIR': '$(OutDir)/obj/global_intermediate', 'SHARED_INTERMEDIATE_DIR': '$(OutDir)obj/global_intermediate',
'OS': 'win', 'OS': 'win',
'PRODUCT_DIR': '$(OutDir)', 'PRODUCT_DIR': '$(OutDir)',
'LIB_DIR': '$(OutDir)\\lib', 'LIB_DIR': '$(OutDir)lib',
'RULE_INPUT_ROOT': '$(InputName)', 'RULE_INPUT_ROOT': '$(InputName)',
'RULE_INPUT_DIRNAME': '$(InputDir)', 'RULE_INPUT_DIRNAME': '$(InputDir)',
'RULE_INPUT_EXT': '$(InputExt)', 'RULE_INPUT_EXT': '$(InputExt)',
@ -268,8 +268,7 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
direct_cmd = [i.replace('$(InputPath)', direct_cmd = [i.replace('$(InputPath)',
'`cygpath -m "${INPUTPATH}"`') '`cygpath -m "${INPUTPATH}"`')
for i in direct_cmd] for i in direct_cmd]
direct_cmd = ['"%s"' % i for i in direct_cmd] direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd]
direct_cmd = [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) direct_cmd = ' '.join(direct_cmd)
# TODO(quote): regularize quoting path names throughout the module # TODO(quote): regularize quoting path names throughout the module
@ -295,10 +294,19 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
command = ['type'] command = ['type']
else: else:
command = [cmd[0].replace('/', '\\')] command = [cmd[0].replace('/', '\\')]
# Add call before command to ensure that commands can be tied together one
# after the other without aborting in Incredibuild, since IB makes a bat
# file out of the raw command string, and some commands (like python) are
# actually batch files themselves.
command.insert(0, 'call')
# Fix the paths # Fix the paths
# If the argument starts with a slash, it's probably a command line switch # TODO(quote): This is a really ugly heuristic, and will miss path fixing
arguments = [i.startswith('/') and i or _FixPath(i) for i in cmd[1:]] # for arguments like "--arg=path" or "/opt: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: if quote_cmd:
# Support a mode for using cmd directly. # Support a mode for using cmd directly.
# Convert any paths to native form (first element is used directly). # Convert any paths to native form (first element is used directly).
@ -830,18 +838,22 @@ def _GetGuidOfProject(proj_path, spec):
return guid return guid
def _GetMsbuildToolsetOfProject(proj_path, spec): def _GetMsbuildToolsetOfProject(proj_path, spec, version):
"""Get the platform toolset for the project. """Get the platform toolset for the project.
Arguments: Arguments:
proj_path: Path of the vcproj or vcxproj file to generate. proj_path: Path of the vcproj or vcxproj file to generate.
spec: The target dictionary containing the properties of the target. spec: The target dictionary containing the properties of the target.
version: The MSVSVersion object.
Returns: Returns:
the platform toolset string or None. the platform toolset string or None.
""" """
# Pluck out the default configuration. # Pluck out the default configuration.
default_config = _GetDefaultConfiguration(spec) default_config = _GetDefaultConfiguration(spec)
return default_config.get('msbuild_toolset') toolset = default_config.get('msbuild_toolset')
if not toolset and version.DefaultToolset():
toolset = version.DefaultToolset()
return toolset
def _GenerateProject(project, options, version, generator_flags): def _GenerateProject(project, options, version, generator_flags):
@ -896,7 +908,8 @@ def _GenerateMSVSProject(project, options, version, generator_flags):
# Prepare list of sources and excluded sources. # Prepare list of sources and excluded sources.
gyp_file = os.path.split(project.build_file)[1] gyp_file = os.path.split(project.build_file)[1]
sources, excluded_sources = _PrepareListOfSources(spec, gyp_file) sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
gyp_file)
# Add rules. # Add rules.
actions_to_add = {} actions_to_add = {}
@ -1046,7 +1059,7 @@ def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
defines) defines)
# Change program database directory to prevent collisions. # Change program database directory to prevent collisions.
_ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName', _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName',
'$(IntDir)\\$(ProjectName)\\vc80.pdb', only_if_unset=True) '$(IntDir)$(ProjectName)\\vc80.pdb', only_if_unset=True)
# Add disabled warnings. # Add disabled warnings.
_ToolAppend(tools, 'VCCLCompilerTool', _ToolAppend(tools, 'VCCLCompilerTool',
'DisableSpecificWarnings', disabled_warnings) 'DisableSpecificWarnings', disabled_warnings)
@ -1133,10 +1146,10 @@ def _GetOutputFilePathAndTool(spec):
vc_tool = '' vc_tool = ''
msbuild_tool = '' msbuild_tool = ''
output_file_map = { output_file_map = {
'executable': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.exe'), 'executable': ('VCLinkerTool', 'Link', '$(OutDir)', '.exe'),
'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'), 'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'), 'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)\\lib\\', '.lib'), 'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)lib\\', '.lib'),
} }
output_file_props = output_file_map.get(spec['type']) output_file_props = output_file_map.get(spec['type'])
if output_file_props and int(spec.get('msvs_auto_output_file', 1)): if output_file_props and int(spec.get('msvs_auto_output_file', 1)):
@ -1249,9 +1262,13 @@ def _GetMSVSAttributes(spec, config, config_type):
prepared_attrs['ConfigurationType'] = config_type prepared_attrs['ConfigurationType'] = config_type
output_dir = prepared_attrs.get('OutputDirectory', output_dir = prepared_attrs.get('OutputDirectory',
'$(SolutionDir)$(ConfigurationName)') '$(SolutionDir)$(ConfigurationName)')
prepared_attrs['OutputDirectory'] = output_dir prepared_attrs['OutputDirectory'] = _FixPath(output_dir) + '\\'
if 'IntermediateDirectory' not in prepared_attrs: if 'IntermediateDirectory' not in prepared_attrs:
intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)' intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)'
prepared_attrs['IntermediateDirectory'] = _FixPath(intermediate) + '\\'
else:
intermediate = _FixPath(prepared_attrs['IntermediateDirectory']) + '\\'
intermediate = MSVSSettings.FixVCMacroSlashes(intermediate)
prepared_attrs['IntermediateDirectory'] = intermediate prepared_attrs['IntermediateDirectory'] = intermediate
return prepared_attrs return prepared_attrs
@ -1261,7 +1278,7 @@ def _AddNormalizedSources(sources_set, sources_array):
sources_set.update(set(sources)) sources_set.update(set(sources))
def _PrepareListOfSources(spec, gyp_file): def _PrepareListOfSources(spec, generator_flags, gyp_file):
"""Prepare list of sources and excluded sources. """Prepare list of sources and excluded sources.
Besides the sources specified directly in the spec, adds the gyp file so Besides the sources specified directly in the spec, adds the gyp file so
@ -1280,7 +1297,8 @@ def _PrepareListOfSources(spec, gyp_file):
_AddNormalizedSources(sources, spec.get('sources', [])) _AddNormalizedSources(sources, spec.get('sources', []))
excluded_sources = set() excluded_sources = set()
# Add in the gyp file. # Add in the gyp file.
sources.add(gyp_file) if not generator_flags.get('standalone'):
sources.add(gyp_file)
# Add in 'action' inputs and outputs. # Add in 'action' inputs and outputs.
for a in spec.get('actions', []): for a in spec.get('actions', []):
@ -1598,7 +1616,7 @@ def _GetPathOfProject(qualified_target, spec, options, msvs_version):
msvs_version.ProjectExtension()) msvs_version.ProjectExtension())
build_file = gyp.common.BuildFile(qualified_target) build_file = gyp.common.BuildFile(qualified_target)
proj_path = os.path.join(os.path.split(build_file)[0], proj_filename) proj_path = os.path.join(os.path.dirname(build_file), proj_filename)
fix_prefix = None fix_prefix = None
if options.generator_output: if options.generator_output:
project_dir_path = os.path.dirname(os.path.abspath(proj_path)) project_dir_path = os.path.dirname(os.path.abspath(proj_path))
@ -1657,7 +1675,8 @@ def _CreateProjectObjects(target_list, target_dicts, options, msvs_version):
fixpath_prefix=fixpath_prefix) fixpath_prefix=fixpath_prefix)
# Set project toolset if any (MS build only) # Set project toolset if any (MS build only)
if msvs_version.UsesVcxproj(): if msvs_version.UsesVcxproj():
obj.set_msbuild_toolset(_GetMsbuildToolsetOfProject(proj_path, spec)) obj.set_msbuild_toolset(
_GetMsbuildToolsetOfProject(proj_path, spec, msvs_version))
projects[qualified_target] = obj projects[qualified_target] = obj
# Set all the dependencies # Set all the dependencies
for project in projects.values(): for project in projects.values():
@ -1804,9 +1823,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
for build_file in data: for build_file in data:
# Validate build_file extension # Validate build_file extension
if build_file[-4:] != '.gyp': if not build_file.endswith('.gyp'):
continue continue
sln_path = build_file[:-4] + options.suffix + '.sln' sln_path = os.path.splitext(build_file)[0] + options.suffix + '.sln'
if options.generator_output: if options.generator_output:
sln_path = os.path.join(options.generator_output, sln_path) sln_path = os.path.join(options.generator_output, sln_path)
# Get projects in the solution, and their dependents. # Get projects in the solution, and their dependents.
@ -1856,7 +1875,7 @@ def _GenerateMSBuildFiltersFile(filters_path, source_files,
['ItemGroup'] + filter_group, ['ItemGroup'] + filter_group,
['ItemGroup'] + source_group ['ItemGroup'] + source_group
] ]
easy_xml.WriteXmlIfChanged(content, filters_path) easy_xml.WriteXmlIfChanged(content, filters_path, pretty=True, win32=True)
elif os.path.exists(filters_path): elif os.path.exists(filters_path):
# We don't need this filter anymore. Delete the old filter file. # We don't need this filter anymore. Delete the old filter file.
os.unlink(filters_path) os.unlink(filters_path)
@ -2057,7 +2076,7 @@ def _GenerateMSBuildRulePropsFile(props_path, msbuild_rules):
], ],
] ]
]) ])
easy_xml.WriteXmlIfChanged(content, props_path) easy_xml.WriteXmlIfChanged(content, props_path, pretty=True, win32=True)
def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules): def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
@ -2219,7 +2238,7 @@ def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
] ]
], ],
]) ])
easy_xml.WriteXmlIfChanged(content, targets_path) easy_xml.WriteXmlIfChanged(content, targets_path, pretty=True, win32=True)
def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules): def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules):
@ -2397,7 +2416,7 @@ def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules):
} }
] ]
]) ])
easy_xml.WriteXmlIfChanged(content, xml_path) easy_xml.WriteXmlIfChanged(content, xml_path, pretty=True, win32=True)
def _GetConfigurationAndPlatform(name, settings): def _GetConfigurationAndPlatform(name, settings):
@ -2505,9 +2524,6 @@ def _GetMSBuildPropertySheets(configurations):
return sheets return sheets
def _ConvertMSVSBuildAttributes(spec, config, build_file): def _ConvertMSVSBuildAttributes(spec, config, build_file):
config_type = _GetMSVSConfigurationType(spec, build_file) config_type = _GetMSVSConfigurationType(spec, build_file)
msvs_attributes = _GetMSVSAttributes(spec, config, config_type) msvs_attributes = _GetMSVSAttributes(spec, config, config_type)
msbuild_attributes = {} msbuild_attributes = {}
@ -2558,10 +2574,10 @@ def _GetMSBuildAttributes(spec, config, build_file):
msbuild_attributes['ConfigurationType'] = config_type msbuild_attributes['ConfigurationType'] = config_type
output_dir = msbuild_attributes.get('OutputDirectory', output_dir = msbuild_attributes.get('OutputDirectory',
'$(SolutionDir)$(Configuration)\\') '$(SolutionDir)$(Configuration)\\')
msbuild_attributes['OutputDirectory'] = output_dir msbuild_attributes['OutputDirectory'] = _FixPath(output_dir)
if 'IntermediateDirectory' not in msbuild_attributes: if 'IntermediateDirectory' not in msbuild_attributes:
intermediate = '$(Configuration)\\' intermediate = '$(Configuration)\\'
msbuild_attributes['IntermediateDirectory'] = intermediate msbuild_attributes['IntermediateDirectory'] = _FixPath(intermediate)
if 'CharacterSet' in msbuild_attributes: if 'CharacterSet' in msbuild_attributes:
msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet( msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet(
msbuild_attributes['CharacterSet']) msbuild_attributes['CharacterSet'])
@ -2584,7 +2600,7 @@ def _GetMSBuildAttributes(spec, config, build_file):
msbuild_settings = config['finalized_msbuild_settings'] msbuild_settings = config['finalized_msbuild_settings']
out_file = msbuild_settings[msbuild_tool].get('OutputFile') out_file = msbuild_settings[msbuild_tool].get('OutputFile')
if out_file: if out_file:
msbuild_attributes['TargetPath'] = out_file msbuild_attributes['TargetPath'] = _FixPath(out_file)
return msbuild_attributes return msbuild_attributes
@ -2960,7 +2976,8 @@ def _GenerateMSBuildProject(project, options, version, generator_flags):
relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir) relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
gyp_file = os.path.split(project.build_file)[1] gyp_file = os.path.split(project.build_file)[1]
sources, excluded_sources = _PrepareListOfSources(spec, gyp_file) sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
gyp_file)
# Add rules. # Add rules.
actions_to_add = {} actions_to_add = {}
props_files_of_rules = set() props_files_of_rules = set()
@ -3034,7 +3051,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags):
# TODO(jeanluc) File a bug to get rid of runas. We had in MSVS: # TODO(jeanluc) File a bug to get rid of runas. We had in MSVS:
# has_run_as = _WriteMSVSUserFile(project.path, version, spec) # has_run_as = _WriteMSVSUserFile(project.path, version, spec)
easy_xml.WriteXmlIfChanged(content, project.path) easy_xml.WriteXmlIfChanged(content, project.path, pretty=True, win32=True)
return missing_sources return missing_sources

149
tools/gyp/pylib/gyp/generator/ninja.py

@ -3,18 +3,19 @@
# found in the LICENSE file. # found in the LICENSE file.
import copy import copy
import hashlib
import os.path
import re
import subprocess
import sys
import gyp import gyp
import gyp.common import gyp.common
import gyp.msvs_emulation import gyp.msvs_emulation
import gyp.MSVSVersion import gyp.MSVSVersion
import gyp.system_test import gyp.system_test
import gyp.xcode_emulation import gyp.xcode_emulation
import hashlib
import os.path
import re
import subprocess
import sys
from gyp.common import GetEnvironFallback
import gyp.ninja_syntax as ninja_syntax import gyp.ninja_syntax as ninja_syntax
generator_default_variables = { generator_default_variables = {
@ -27,14 +28,18 @@ generator_default_variables = {
# Gyp expects the following variables to be expandable by the build # Gyp expects the following variables to be expandable by the build
# system to the appropriate locations. Ninja prefers paths to be # system to the appropriate locations. Ninja prefers paths to be
# known at gyp time. To resolve this, introduce special # known at gyp time. To resolve this, introduce special
# variables starting with $! (which begin with a $ so gyp knows it # variables starting with $! and $| (which begin with a $ so gyp knows it
# should be treated as a path, but is otherwise an invalid # should be treated specially, but is otherwise an invalid
# ninja/shell variable) that are passed to gyp here but expanded # ninja/shell variable) that are passed to gyp here but expanded
# before writing out into the target .ninja files; see # before writing out into the target .ninja files; see
# ExpandSpecial. # ExpandSpecial.
# $! is used for variables that represent a path and that can only appear at
# the start of a string, while $| is used for variables that can appear
# anywhere in a string.
'INTERMEDIATE_DIR': '$!INTERMEDIATE_DIR', 'INTERMEDIATE_DIR': '$!INTERMEDIATE_DIR',
'SHARED_INTERMEDIATE_DIR': '$!PRODUCT_DIR/gen', 'SHARED_INTERMEDIATE_DIR': '$!PRODUCT_DIR/gen',
'PRODUCT_DIR': '$!PRODUCT_DIR', 'PRODUCT_DIR': '$!PRODUCT_DIR',
'CONFIGURATION_NAME': '$|CONFIGURATION_NAME',
# Special variables that may be used by gyp 'rule' targets. # Special variables that may be used by gyp 'rule' targets.
# We generate definitions for these variables on the fly when processing a # We generate definitions for these variables on the fly when processing a
@ -54,7 +59,12 @@ generator_extra_sources_for_rules = []
# TODO: figure out how to not build extra host objects in the non-cross-compile # TODO: figure out how to not build extra host objects in the non-cross-compile
# case when this is enabled, and enable unconditionally. # case when this is enabled, and enable unconditionally.
generator_supports_multiple_toolsets = ( generator_supports_multiple_toolsets = (
os.environ.get('AR_target') or os.environ.get('CC_target') or os.environ.get('GYP_CROSSCOMPILE') or
os.environ.get('AR_host') or
os.environ.get('CC_host') or
os.environ.get('CXX_host') or
os.environ.get('AR_target') or
os.environ.get('CC_target') or
os.environ.get('CXX_target')) os.environ.get('CXX_target'))
@ -258,6 +268,10 @@ class NinjaWriter:
# so insert product_dir in front if it is provided. # so insert product_dir in front if it is provided.
path = path.replace(INTERMEDIATE_DIR, path = path.replace(INTERMEDIATE_DIR,
os.path.join(product_dir or '', int_dir)) os.path.join(product_dir or '', int_dir))
CONFIGURATION_NAME = '$|CONFIGURATION_NAME'
path = path.replace(CONFIGURATION_NAME, self.config_name)
return path return path
def ExpandRuleVariables(self, path, root, dirname, source, ext, name): def ExpandRuleVariables(self, path, root, dirname, source, ext, name):
@ -287,6 +301,8 @@ class NinjaWriter:
if self.flavor == 'win': if self.flavor == 'win':
expanded = os.path.normpath(expanded) expanded = os.path.normpath(expanded)
return expanded return expanded
if '$|' in path:
path = self.ExpandSpecial(path)
assert '$' not in path, path assert '$' not in path, path
return os.path.normpath(os.path.join(self.build_to_base, path)) return os.path.normpath(os.path.join(self.build_to_base, path))
@ -695,11 +711,11 @@ class NinjaWriter:
def WriteSources(self, config_name, config, sources, predepends, def WriteSources(self, config_name, config, sources, predepends,
precompiled_header): precompiled_header):
"""Write build rules to compile all of |sources|.""" """Write build rules to compile all of |sources|."""
if self.toolset == 'target': if self.toolset == 'host':
self.ninja.variable('ar', '$ar_target') self.ninja.variable('ar', '$ar_host')
self.ninja.variable('cc', '$cc_target') self.ninja.variable('cc', '$cc_host')
self.ninja.variable('cxx', '$cxx_target') self.ninja.variable('cxx', '$cxx_host')
self.ninja.variable('ld', '$ld_target') self.ninja.variable('ld', '$ld_host')
extra_defines = [] extra_defines = []
if self.flavor == 'mac': if self.flavor == 'mac':
@ -875,8 +891,12 @@ class NinjaWriter:
self.GypPathToNinja) self.GypPathToNinja)
self.WriteVariableList( self.WriteVariableList(
'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags))) 'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags)))
ldflags = self.msvs_settings.GetLdflags(config_name, is_executable = spec['type'] == 'executable'
self.GypPathToNinja, self.ExpandSpecial) manifest_name = self.GypPathToUniqueOutput(
self.ComputeOutputFileName(spec))
ldflags, manifest_files = self.msvs_settings.GetLdflags(config_name,
self.GypPathToNinja, self.ExpandSpecial, manifest_name, is_executable)
self.WriteVariableList('manifests', manifest_files)
else: else:
ldflags = config.get('ldflags', []) ldflags = config.get('ldflags', [])
self.WriteVariableList('ldflags', self.WriteVariableList('ldflags',
@ -1182,7 +1202,6 @@ def CalculateVariables(default_variables, params):
"""Calculate additional variables for use in the build (called by gyp).""" """Calculate additional variables for use in the build (called by gyp)."""
global generator_additional_non_configuration_keys global generator_additional_non_configuration_keys
global generator_additional_path_sections global generator_additional_path_sections
cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
flavor = gyp.common.GetFlavor(params) flavor = gyp.common.GetFlavor(params)
if flavor == 'mac': if flavor == 'mac':
default_variables.setdefault('OS', 'mac') default_variables.setdefault('OS', 'mac')
@ -1274,41 +1293,92 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
gyp.common.CopyTool(flavor, toplevel_build) gyp.common.CopyTool(flavor, toplevel_build)
# Grab make settings for CC/CXX. # 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 == 'win': if flavor == 'win':
cc = cxx = 'cl.exe' cc = 'cl.exe'
cxx = 'cl.exe'
ld = 'link.exe'
gyp.msvs_emulation.GenerateEnvironmentFiles( gyp.msvs_emulation.GenerateEnvironmentFiles(
toplevel_build, generator_flags, OpenOutput) toplevel_build, generator_flags, OpenOutput)
ld_host = '$ld'
else: else:
cc, cxx = 'gcc', 'g++' 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_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings = data[build_file].get('make_global_settings', []) make_global_settings = data[build_file].get('make_global_settings', [])
build_to_root = InvertRelativePath(build_dir) build_to_root = InvertRelativePath(build_dir)
for key, value in make_global_settings: for key, value in make_global_settings:
if key == 'CC': cc = os.path.join(build_to_root, value) if key == 'CC':
if key == 'CXX': cxx = os.path.join(build_to_root, value) 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' flock = 'flock'
if flavor == 'mac': if flavor == 'mac':
flock = './gyp-mac-tool flock' flock = './gyp-mac-tool flock'
master_ninja.variable('cc', os.environ.get('CC', cc)) cc = GetEnvironFallback(['CC_target', 'CC'], cc)
master_ninja.variable('cxx', os.environ.get('CXX', cxx)) master_ninja.variable('cc', cc)
cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
master_ninja.variable('cxx', cxx)
ld = GetEnvironFallback(['LD_target', 'LD'], ld)
if not cc_host:
cc_host = cc
if not cxx_host:
cxx_host = cxx
if flavor == 'win': if flavor == 'win':
master_ninja.variable('ld', 'link.exe') master_ninja.variable('ld', ld)
master_ninja.variable('idl', 'midl.exe') master_ninja.variable('idl', 'midl.exe')
master_ninja.variable('ar', 'lib.exe') master_ninja.variable('ar', 'lib.exe')
master_ninja.variable('rc', 'rc.exe') master_ninja.variable('rc', 'rc.exe')
master_ninja.variable('asm', 'ml.exe') master_ninja.variable('asm', 'ml.exe')
master_ninja.variable('mt', 'mt.exe')
master_ninja.variable('use_dep_database', '1')
else: else:
master_ninja.variable('ld', flock + ' linker.lock $cxx') master_ninja.variable('ld', flock + ' linker.lock ' + ld)
master_ninja.variable('ar', os.environ.get('AR', 'ar')) master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
master_ninja.variable('ar_target', os.environ.get('AR_target', '$ar')) master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
master_ninja.variable('cc_target', os.environ.get('CC_target', '$cc')) cc_host = GetEnvironFallback(['CC_host'], cc_host)
master_ninja.variable('cxx_target', os.environ.get('CXX_target', '$cxx')) cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
ld_host = GetEnvironFallback(['LD_host'], ld_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)
if flavor == 'win': if flavor == 'win':
master_ninja.variable('ld_target', os.environ.get('LD_target', '$ld')) master_ninja.variable('ld_host', ld_host)
else: else:
master_ninja.variable('ld_target', flock + ' linker.lock $cxx_target') master_ninja.variable('ld_host', flock + ' linker.lock ' + ld_host)
if flavor == 'mac': if flavor == 'mac':
master_ninja.variable('mac_tool', os.path.join('.', 'gyp-mac-tool')) master_ninja.variable('mac_tool', os.path.join('.', 'gyp-mac-tool'))
@ -1348,28 +1418,28 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'cc', 'cc',
description='CC $out', description='CC $out',
command=cc_template % {'outspec': '/Fo$out'}, command=cc_template % {'outspec': '/Fo$out'},
deplist='$out.dl', depfile='$out.dl',
rspfile='$out.rsp', rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_c') rspfile_content='$defines $includes $cflags $cflags_c')
master_ninja.rule( master_ninja.rule(
'cc_pch', 'cc_pch',
description='CC PCH $out', description='CC PCH $out',
command=cc_template % {'outspec': '/Fp$out /Fo$out.obj'}, command=cc_template % {'outspec': '/Fp$out /Fo$out.obj'},
deplist='$out.dl', depfile='$out.dl',
rspfile='$out.rsp', rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_c') rspfile_content='$defines $includes $cflags $cflags_c')
master_ninja.rule( master_ninja.rule(
'cxx', 'cxx',
description='CXX $out', description='CXX $out',
command=cxx_template % {'outspec': '/Fo$out'}, command=cxx_template % {'outspec': '/Fo$out'},
deplist='$out.dl', depfile='$out.dl',
rspfile='$out.rsp', rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_cc') rspfile_content='$defines $includes $cflags $cflags_cc')
master_ninja.rule( master_ninja.rule(
'cxx_pch', 'cxx_pch',
description='CXX PCH $out', description='CXX PCH $out',
command=cxx_template % {'outspec': '/Fp$out /Fo$out.obj'}, command=cxx_template % {'outspec': '/Fp$out /Fo$out.obj'},
deplist='$out.dl', depfile='$out.dl',
rspfile='$out.rsp', rspfile='$out.rsp',
rspfile_content='$defines $includes $cflags $cflags_cc') rspfile_content='$defines $includes $cflags $cflags_cc')
master_ninja.rule( master_ninja.rule(
@ -1446,6 +1516,9 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
dllcmd = ('%s gyp-win-tool link-wrapper $arch ' dllcmd = ('%s gyp-win-tool link-wrapper $arch '
'$ld /nologo /IMPLIB:$implib /DLL /OUT:$dll ' '$ld /nologo /IMPLIB:$implib /DLL /OUT:$dll '
'/PDB:$dll.pdb @$dll.rsp' % sys.executable) '/PDB:$dll.pdb @$dll.rsp' % 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, master_ninja.rule('solink', description=dlldesc, command=dllcmd,
rspfile='$dll.rsp', rspfile='$dll.rsp',
rspfile_content='$libs $in_newline $ldflags', rspfile_content='$libs $in_newline $ldflags',
@ -1460,8 +1533,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'link', 'link',
description='LINK $out', description='LINK $out',
command=('%s gyp-win-tool link-wrapper $arch ' command=('%s gyp-win-tool link-wrapper $arch '
'$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' % '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
sys.executable), '%s gyp-win-tool manifest-wrapper $arch '
'$mt -nologo -manifest $manifests -out:$out.manifest' %
(sys.executable, sys.executable)),
rspfile='$out.rsp', rspfile='$out.rsp',
rspfile_content='$in_newline $libs $ldflags') rspfile_content='$in_newline $libs $ldflags')
else: else:

16
tools/gyp/pylib/gyp/generator/xcode.py

@ -7,6 +7,7 @@ import gyp.common
import gyp.xcodeproj_file import gyp.xcodeproj_file
import errno import errno
import os import os
import sys
import posixpath import posixpath
import re import re
import shutil import shutil
@ -145,7 +146,6 @@ class XcodeProject(object):
xccl = CreateXCConfigurationList(configurations) xccl = CreateXCConfigurationList(configurations)
self.project.SetProperty('buildConfigurationList', xccl) self.project.SetProperty('buildConfigurationList', xccl)
except: except:
import sys
sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path) sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path)
raise raise
@ -526,7 +526,7 @@ def AddSourceToTarget(source, type, pbxp, xct):
basename = posixpath.basename(source) basename = posixpath.basename(source)
(root, ext) = posixpath.splitext(basename) (root, ext) = posixpath.splitext(basename)
if ext != '': if ext:
ext = ext[1:].lower() ext = ext[1:].lower()
if ext in source_extensions and type != 'none': if ext in source_extensions and type != 'none':
@ -614,11 +614,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
if project_version: if project_version:
xcp.project_file.SetXcodeVersion(project_version) xcp.project_file.SetXcodeVersion(project_version)
main_group = pbxp.GetProperty('mainGroup') # Add gyp/gypi files to project
build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'}) if not generator_flags.get('standalone'):
main_group.AppendChild(build_group) main_group = pbxp.GetProperty('mainGroup')
for included_file in build_file_dict['included_files']: build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
build_group.AddOrGetFileByPath(included_file, False) main_group.AppendChild(build_group)
for included_file in build_file_dict['included_files']:
build_group.AddOrGetFileByPath(included_file, False)
xcode_targets = {} xcode_targets = {}
xcode_target_to_target_dict = {} xcode_target_to_target_dict = {}

59
tools/gyp/pylib/gyp/msvs_emulation.py

@ -113,6 +113,10 @@ def _FindDirectXInstallation():
"""Try to find an installation location for the DirectX SDK. Check for the """Try to find an installation location for the DirectX SDK. Check for the
standard environment variable, and if that doesn't exist, try to find standard environment variable, and if that doesn't exist, try to find
via the registry. May return None if not found in either location.""" via the registry. May return None if not found in either location."""
# Return previously calculated value, if there is one
if hasattr(_FindDirectXInstallation, 'dxsdk_dir'):
return _FindDirectXInstallation.dxsdk_dir
dxsdk_dir = os.environ.get('DXSDK_DIR') dxsdk_dir = os.environ.get('DXSDK_DIR')
if not dxsdk_dir: if not dxsdk_dir:
# Setup params to pass to and attempt to launch reg.exe. # Setup params to pass to and attempt to launch reg.exe.
@ -121,6 +125,9 @@ def _FindDirectXInstallation():
for line in p.communicate()[0].splitlines(): for line in p.communicate()[0].splitlines():
if 'InstallPath' in line: if 'InstallPath' in line:
dxsdk_dir = line.split(' ')[3] + "\\" dxsdk_dir = line.split(' ')[3] + "\\"
# Cache return value
_FindDirectXInstallation.dxsdk_dir = dxsdk_dir
return dxsdk_dir return dxsdk_dir
@ -169,6 +176,7 @@ class MsvsSettings(object):
'$(InputName)': '${root}', '$(InputName)': '${root}',
'$(ProjectName)': self.spec['target_name'], '$(ProjectName)': self.spec['target_name'],
'$(PlatformName)': target_platform, '$(PlatformName)': target_platform,
'$(ProjectDir)\\': '',
} }
# Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be # 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 # set. This happens when the SDK is sync'd via src-internal, rather than
@ -362,8 +370,10 @@ class MsvsSettings(object):
elif len(def_files) > 1: elif len(def_files) > 1:
raise Exception("Multiple .def files") raise Exception("Multiple .def files")
def GetLdflags(self, config, gyp_to_build_path, expand_special): def GetLdflags(self, config, gyp_to_build_path, expand_special,
"""Returns the flags that need to be added to link commands.""" manifest_base_name, is_executable):
"""Returns the flags that need to be added to link commands, and the
manifest files."""
config = self._RealConfig(config) config = self._RealConfig(config)
ldflags = [] ldflags = []
ld = self._GetWrapper(self, self.msvs_settings[config], ld = self._GetWrapper(self, self.msvs_settings[config],
@ -412,7 +422,46 @@ class MsvsSettings(object):
if not filter(lambda x: 'NXCOMPAT' in x, ldflags): if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
ldflags.append('/NXCOMPAT') ldflags.append('/NXCOMPAT')
return ldflags have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
manifest_flags, intermediate_manifest_file = self._GetLdManifestFlags(
config, manifest_base_name, is_executable and not have_def_file)
ldflags.extend(manifest_flags)
manifest_files = self._GetAdditionalManifestFiles(config, gyp_to_build_path)
manifest_files.append(intermediate_manifest_file)
return ldflags, manifest_files
def _GetLdManifestFlags(self, config, name, allow_isolation):
"""Returns the set of flags that need to be added to the link to generate
a default manifest, as well as the name of the generated file."""
# Add manifest flags that mirror the defaults in VS. Chromium dev builds
# do not currently use any non-default settings, but we could parse
# VCManifestTool blocks if Chromium or other projects need them in the
# future. Of particular note, we do not yet support EmbedManifest because
# it complicates incremental linking.
output_name = name + '.intermediate.manifest'
flags = [
'/MANIFEST',
'/ManifestFile:' + output_name,
'''/MANIFESTUAC:"level='asInvoker' uiAccess='false'"'''
]
if allow_isolation:
flags.append('/ALLOWISOLATION')
return flags, output_name
def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
"""Gets additional manifest files that are added to the default one
generated by the linker."""
files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config,
default=[])
if (self._Setting(
('VCManifestTool', 'EmbedManifest'), config, default='') == 'true'):
print 'gyp/msvs_emulation.py: "EmbedManifest: true" not yet supported.'
if isinstance(files, str):
files = files.split(';')
return [os.path.normpath(
gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
for f in files]
def IsUseLibraryDependencyInputs(self, config): def IsUseLibraryDependencyInputs(self, config):
"""Returns whether the target should be linked via Use Library Dependency """Returns whether the target should be linked via Use Library Dependency
@ -447,8 +496,8 @@ class MsvsSettings(object):
cygwin_dir = os.path.normpath( cygwin_dir = os.path.normpath(
os.path.join(path_to_base, self.msvs_cygwin_dirs[0])) os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
cd = ('cd %s' % path_to_base).replace('\\', '/') cd = ('cd %s' % path_to_base).replace('\\', '/')
args = [a.replace('\\', '/') for a in args] args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
args = ["'%s'" % a.replace("'", "\\'") for a in args] args = ["'%s'" % a.replace("'", "'\\''") for a in args]
bash_cmd = ' '.join(args) bash_cmd = ' '.join(args)
cmd = ( cmd = (
'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir + 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +

4
tools/gyp/pylib/gyp/ninja_syntax.py

@ -35,7 +35,7 @@ class Writer(object):
self._line('%s = %s' % (key, value), indent) self._line('%s = %s' % (key, value), indent)
def rule(self, name, command, description=None, depfile=None, def rule(self, name, command, description=None, depfile=None,
generator=False, restat=False, deplist=None, rspfile=None, generator=False, restat=False, rspfile=None,
rspfile_content=None): rspfile_content=None):
self._line('rule %s' % name) self._line('rule %s' % name)
self.variable('command', command, indent=1) self.variable('command', command, indent=1)
@ -43,8 +43,6 @@ class Writer(object):
self.variable('description', description, indent=1) self.variable('description', description, indent=1)
if depfile: if depfile:
self.variable('depfile', depfile, indent=1) self.variable('depfile', depfile, indent=1)
if deplist:
self.variable('deplist', deplist, indent=1)
if generator: if generator:
self.variable('generator', '1', indent=1) self.variable('generator', '1', indent=1)
if restat: if restat:

35
tools/gyp/pylib/gyp/win_tool.py

@ -13,6 +13,9 @@ import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
import win32con
import win32file
import pywintypes
def main(args): def main(args):
@ -22,6 +25,22 @@ def main(args):
sys.exit(exit_code) sys.exit(exit_code)
class LinkLock(object):
"""A flock-style lock to limit the number of concurrent links to one. Based on
http://code.activestate.com/recipes/65203-portalocker-cross-platform-posixnt-api-for-flock-s/
"""
def __enter__(self):
self.file = open('LinkLock', 'w+')
self.file_handle = win32file._get_osfhandle(self.file.fileno())
win32file.LockFileEx(self.file_handle, win32con.LOCKFILE_EXCLUSIVE_LOCK,
0, -0x10000, pywintypes.OVERLAPPED())
def __exit__(self, type, value, traceback):
win32file.UnlockFileEx(
self.file_handle, 0, -0x10000, pywintypes.OVERLAPPED())
self.file.close()
class WinTool(object): class WinTool(object):
"""This class performs all the Windows tooling steps. The methods can either """This class performs all the Windows tooling steps. The methods can either
be executed directly, or dispatched from an argument list.""" be executed directly, or dispatched from an argument list."""
@ -68,12 +87,26 @@ class WinTool(object):
' Creating library ui.dll.lib and object ui.dll.exp' ' Creating library ui.dll.lib and object ui.dll.exp'
This happens when there are exports from the dll or exe. This happens when there are exports from the dll or exe.
""" """
with LinkLock():
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate()
for line in out.splitlines():
if not line.startswith(' Creating library '):
print line
return popen.returncode
def ExecManifestWrapper(self, arch, *args):
"""Run manifest tool with environment set. Strip out undesirable warning
(some XML blocks are recognized by the OS loader, but not the manifest
tool)."""
env = self._GetEnv(arch) env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env, popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate() out, _ = popen.communicate()
for line in out.splitlines(): for line in out.splitlines():
if not line.startswith(' Creating library '): if line and 'manifest authoring warning 81010002' not in line:
print line print line
return popen.returncode return popen.returncode

12
tools/gyp/pylib/gyp/xcode_emulation.py

@ -244,8 +244,9 @@ class XcodeSettings(object):
def _SdkPath(self): def _SdkPath(self):
sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5') sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5')
if sdk_root.startswith('macosx'): if sdk_root.startswith('macosx'):
sdk_root = 'MacOSX' + sdk_root[len('macosx'):] return os.path.join(self._GetSdkBaseDir(),
return os.path.join(self._GetSdkBaseDir(), '%s.sdk' % sdk_root) 'MacOSX' + sdk_root[len('macosx'):] + '.sdk')
return sdk_root
def GetCflags(self, configname): def GetCflags(self, configname):
"""Returns flags that need to be added to .c, .cc, .m, and .mm """Returns flags that need to be added to .c, .cc, .m, and .mm
@ -335,7 +336,7 @@ class XcodeSettings(object):
config = self.spec['configurations'][self.configname] config = self.spec['configurations'][self.configname]
framework_dirs = config.get('mac_framework_dirs', []) framework_dirs = config.get('mac_framework_dirs', [])
for directory in framework_dirs: for directory in framework_dirs:
cflags.append('-F ' + directory.replace('$(SDKROOT)', sdk_root)) cflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
self.configname = None self.configname = None
return cflags return cflags
@ -553,6 +554,11 @@ class XcodeSettings(object):
for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []): for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []):
ldflags.append('-Wl,-rpath,' + rpath) ldflags.append('-Wl,-rpath,' + rpath)
config = self.spec['configurations'][self.configname]
framework_dirs = config.get('mac_framework_dirs', [])
for directory in framework_dirs:
ldflags.append('-F' + directory.replace('$(SDKROOT)', self._SdkPath()))
self.configname = None self.configname = None
return ldflags return ldflags

10
tools/gyp/pylib/gyp/xcodeproj_file.py

@ -1,4 +1,4 @@
# Copyright (c) 2009 Google Inc. All rights reserved. # Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
@ -1199,11 +1199,9 @@ class PBXGroup(XCHierarchicalElement):
is_dir = False is_dir = False
if path.endswith('/'): if path.endswith('/'):
is_dir = True is_dir = True
normpath = posixpath.normpath(path) path = posixpath.normpath(path)
if is_dir: if is_dir:
normpath = path + '/' path = path + '/'
else:
normpath = path
# Adding or getting a variant? Variants are files inside directories # Adding or getting a variant? Variants are files inside directories
# with an ".lproj" extension. Xcode uses variants for localization. For # with an ".lproj" extension. Xcode uses variants for localization. For
@ -1232,7 +1230,7 @@ class PBXGroup(XCHierarchicalElement):
# this PBXGroup, no recursion necessary. # this PBXGroup, no recursion necessary.
if variant_name is None: if variant_name is None:
# Add or get a PBXFileReference. # Add or get a PBXFileReference.
file_ref = self.GetChildByPath(normpath) file_ref = self.GetChildByPath(path)
if file_ref != None: if file_ref != None:
assert file_ref.__class__ == PBXFileReference assert file_ref.__class__ == PBXFileReference
else: else:

12
tools/gyp/tools/emacs/README

@ -0,0 +1,12 @@
How to install gyp-mode for emacs:
Add the following to your ~/.emacs (replace ... with the path to your gyp
checkout).
(setq load-path (cons ".../tools/emacs" load-path))
(require 'gyp)
Restart emacs (or eval-region the added lines) and you should be all set.
Please note that ert is required for running the tests, which is included in
Emacs 24, or available separately from https://github.com/ohler/ert

54
tools/gyp/tools/emacs/gyp-tests.el

@ -0,0 +1,54 @@
;;; gyp-tests.el - unit tests for gyp-mode.
;; 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.
;; The recommended way to run these tests is to run them from the command-line,
;; with the run-unit-tests.sh script.
(require 'cl)
(require 'ert)
(require 'gyp)
(defconst samples (directory-files "testdata" t ".gyp$")
"List of golden samples to check")
(defun fontify (filename)
(with-temp-buffer
(insert-file-contents-literally filename)
(gyp-mode)
(font-lock-fontify-buffer)
(buffer-string)))
(defun read-golden-sample (filename)
(with-temp-buffer
(insert-file-contents-literally (concat filename ".fontified"))
(read (current-buffer))))
(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)))
(nreverse result)))
(ert-deftest test-golden-samples ()
"Check that fontification produces the same results as the golden samples"
(dolist (sample samples)
(let ((golden (read-golden-sample sample))
(fontified (fontify sample)))
(should (equal golden fontified))
(should (equal (text-face-properties golden)
(text-face-properties fontified))))))
(defun create-golden-sample (filename)
"Create a golden sample by fontifying filename and writing out the printable
representation of the fontified buffer (with text properties) to the
FILENAME.fontified"
(with-temp-file (concat filename ".fontified")
(print (fontify filename) (current-buffer))))
(defun create-golden-samples ()
"Recreate the golden samples"
(dolist (sample samples) (create-golden-sample sample)))

251
tools/gyp/tools/emacs/gyp.el

@ -0,0 +1,251 @@
;;; gyp.el - font-lock-mode support for gyp files.
;; 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.
;; Put this somewhere in your load-path and
;; (require 'gyp)
(require 'python)
(require 'cl)
(when (string-match "python-mode.el" (symbol-file 'python-mode 'defun))
(error (concat "python-mode must be loaded from python.el (bundled with "
"recent emacsen), not from the older and less maintained "
"python-mode.el")))
(defadvice python-calculate-indentation (after ami-outdent-closing-parens
activate)
"De-indent closing parens, braces, and brackets in gyp-mode."
(if (and (eq major-mode 'gyp-mode)
(string-match "^ *[])}][],)}]* *$"
(buffer-substring-no-properties
(line-beginning-position) (line-end-position))))
(setq ad-return-value (- ad-return-value 2))))
(define-derived-mode gyp-mode python-mode "Gyp"
"Major mode for editing .gyp files. See http://code.google.com/p/gyp/"
;; gyp-parse-history is a stack of (POSITION . PARSE-STATE) tuples,
;; with greater positions at the top of the stack. PARSE-STATE
;; is a list of section symbols (see gyp-section-name and gyp-parse-to)
;; with most nested section symbol at the front of the list.
(set (make-local-variable 'gyp-parse-history) '((1 . (list))))
(gyp-add-font-lock-keywords))
(defun gyp-set-indentation ()
"Hook function to configure python indentation to suit gyp mode."
(setq python-continuation-offset 2
python-indent 2
python-guess-indent nil))
(add-hook 'gyp-mode-hook 'gyp-set-indentation)
(add-to-list 'auto-mode-alist '("\\.gyp\\'" . gyp-mode))
(add-to-list 'auto-mode-alist '("\\.gypi\\'" . gyp-mode))
;;; Font-lock support
(defconst gyp-dependencies-regexp
(regexp-opt (list "dependencies" "export_dependent_settings"))
"Regular expression to introduce 'dependencies' section")
(defconst gyp-sources-regexp
(regexp-opt (list "action" "files" "include_dirs" "includes" "inputs"
"libraries" "outputs" "sources"))
"Regular expression to introduce 'sources' sections")
(defconst gyp-conditions-regexp
(regexp-opt (list "conditions" "target_conditions"))
"Regular expression to introduce conditions sections")
(defconst gyp-variables-regexp
"^variables"
"Regular expression to introduce variables sections")
(defconst gyp-defines-regexp
"^defines"
"Regular expression to introduce 'defines' sections")
(defconst gyp-targets-regexp
"^targets"
"Regular expression to introduce 'targets' sections")
(defun gyp-section-name (section)
"Map the sections we are interested in from SECTION to symbol.
SECTION is a string from the buffer that introduces a section. The result is
a symbol representing the kind of section.
This allows us to treat (for the purposes of font-lock) several different
section names as the same kind of section. For example, a 'sources section
can be introduced by the 'sources', 'inputs', 'outputs' keyword.
'other is the default section kind when a more specific match is not made."
(cond ((string-match-p gyp-dependencies-regexp section) 'dependencies)
((string-match-p gyp-sources-regexp section) 'sources)
((string-match-p gyp-variables-regexp section) 'variables)
((string-match-p gyp-conditions-regexp section) 'conditions)
((string-match-p gyp-targets-regexp section) 'targets)
((string-match-p gyp-defines-regexp section) 'defines)
(t 'other)))
(defun gyp-invalidate-parse-states-after (target-point)
"Erase any parse information after target-point."
(while (> (caar gyp-parse-history) target-point)
(setq gyp-parse-history (cdr gyp-parse-history))))
(defun gyp-parse-point ()
"The point of the last parse state added by gyp-parse-to."
(caar gyp-parse-history))
(defun gyp-parse-sections ()
"A list of section symbols holding at the last parse state point."
(cdar gyp-parse-history))
(defun gyp-inside-dictionary-p ()
"Predicate returning true if the parser is inside a dictionary."
(not (eq (cadar gyp-parse-history) 'list)))
(defun gyp-add-parse-history (point sections)
"Add parse state SECTIONS to the parse history at POINT so that parsing can be
resumed instantly."
(while (>= (caar gyp-parse-history) point)
(setq gyp-parse-history (cdr gyp-parse-history)))
(setq gyp-parse-history (cons (cons point sections) gyp-parse-history)))
(defun gyp-parse-to (target-point)
"Parses from (point) to TARGET-POINT adding the parse state information to
gyp-parse-state-history. Parsing stops if TARGET-POINT is reached or if a
string literal has been parsed. Returns nil if no further parsing can be
done, otherwise returns the position of the start of a parsed string, leaving
the point at the end of the string."
(let ((parsing t)
string-start)
(while parsing
(setq string-start nil)
;; Parse up to a character that starts a sexp, or if the nesting
;; level decreases.
(let ((state (parse-partial-sexp (gyp-parse-point)
target-point
-1
t))
(sections (gyp-parse-sections)))
(if (= (nth 0 state) -1)
(setq sections (cdr sections)) ; pop out a level
(cond ((looking-at-p "['\"]") ; a string
(setq string-start (point))
(forward-sexp 1)
(if (gyp-inside-dictionary-p)
;; Look for sections inside a dictionary
(let ((section (gyp-section-name
(buffer-substring-no-properties
(+ 1 string-start)
(- (point) 1)))))
(setq sections (cons section (cdr sections)))))
;; Stop after the string so it can be fontified.
(setq target-point (point)))
((looking-at-p "{")
;; Inside a dictionary. Increase nesting.
(forward-char 1)
(setq sections (cons 'unknown sections)))
((looking-at-p "\\[")
;; Inside a list. Increase nesting
(forward-char 1)
(setq sections (cons 'list sections)))
((not (eobp))
;; other
(forward-char 1))))
(gyp-add-parse-history (point) sections)
(setq parsing (< (point) target-point))))
string-start))
(defun gyp-section-at-point ()
"Transform the last parse state, which is a list of nested sections and return
the section symbol that should be used to determine font-lock information for
the string. Can return nil indicating the string should not have any attached
section."
(let ((sections (gyp-parse-sections)))
(cond
((eq (car sections) 'conditions)
;; conditions can occur in a variables section, but we still want to
;; highlight it as a keyword.
nil)
((and (eq (car sections) 'list)
(eq (cadr sections) 'list))
;; conditions and sources can have items in [[ ]]
(caddr sections))
(t (cadr sections)))))
(defun gyp-section-match (limit)
"Parse from (point) to LIMIT returning by means of match data what was
matched. The group of the match indicates what style font-lock should apply.
See also `gyp-add-font-lock-keywords'."
(gyp-invalidate-parse-states-after (point))
(let ((group nil)
(string-start t))
(while (and (< (point) limit)
(not group)
string-start)
(setq string-start (gyp-parse-to limit))
(if string-start
(setq group (case (gyp-section-at-point)
('dependencies 1)
('variables 2)
('conditions 2)
('sources 3)
('defines 4)
(nil nil)))))
(if group
(progn
;; Set the match data to indicate to the font-lock mechanism the
;; highlighting to be performed.
(set-match-data (append (list string-start (point))
(make-list (* (1- group) 2) nil)
(list (1+ string-start) (1- (point)))))
t))))
;;; Please see http://code.google.com/p/gyp/wiki/GypLanguageSpecification for
;;; canonical list of keywords.
(defun gyp-add-font-lock-keywords ()
"Add gyp-mode keywords to font-lock mechanism."
;; TODO(jknotten): Move all the keyword highlighting into gyp-section-match
;; so that we can do the font-locking in a single font-lock pass.
(font-lock-add-keywords
nil
(list
;; Top-level keywords
(list (concat "['\"]\\("
(regexp-opt (list "action" "action_name" "actions" "cflags"
"conditions" "configurations" "copies" "defines"
"dependencies" "destination"
"direct_dependent_settings"
"export_dependent_settings" "extension" "files"
"include_dirs" "includes" "inputs" "libraries"
"link_settings" "mac_bundle" "message"
"msvs_external_rule" "outputs" "product_name"
"process_outputs_as_sources" "rules" "rule_name"
"sources" "suppress_wildcard"
"target_conditions" "target_defaults"
"target_defines" "target_name" "toolsets"
"targets" "type" "variables" "xcode_settings"))
"[!/+=]?\\)") 1 'font-lock-keyword-face t)
;; Type of target
(list (concat "['\"]\\("
(regexp-opt (list "loadable_module" "static_library"
"shared_library" "executable" "none"))
"\\)") 1 'font-lock-type-face t)
(list "\\(?:target\\|action\\)_name['\"]\\s-*:\\s-*['\"]\\([^ '\"]*\\)" 1
'font-lock-function-name-face t)
(list 'gyp-section-match
(list 1 'font-lock-function-name-face t t) ; dependencies
(list 2 'font-lock-variable-name-face t t) ; variables, conditions
(list 3 'font-lock-constant-face t t) ; sources
(list 4 'font-lock-preprocessor-face t t)) ; preprocessor
;; Variable expansion
(list "<@?(\\([^\n )]+\\))" 1 'font-lock-variable-name-face t)
;; Command expansion
(list "<!@?(\\([^\n )]+\\))" 1 'font-lock-variable-name-face t)
)))
(provide 'gyp)

7
tools/gyp/tools/emacs/run-unit-tests.sh

@ -0,0 +1,7 @@
#!/bin/sh
# 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.
emacs --no-site-file --no-init-file --batch \
--load ert.el --load gyp.el --load gyp-tests.el \
-f ert-run-tests-batch-and-exit

1105
tools/gyp/tools/emacs/testdata/media.gyp

File diff suppressed because it is too large

1107
tools/gyp/tools/emacs/testdata/media.gyp.fontified

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save