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")
parser.add_option("-f", "--format", action="store", default='',
help="run tests with the specified formats")
parser.add_option("-G", '--gyp_option', action="append", default=[],
help="Add -G options to the gyp command line")
parser.add_option("-l", "--list", action="store_true",
help="list available tests and exit")
parser.add_option("-n", "--no-exec", action="store_true",
@ -220,8 +222,14 @@ def main(argv=None):
if not opts.quiet:
sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
gyp_options = []
for option in opts.gyp_option:
gyp_options += ['-G', option]
if gyp_options and not opts.quiet:
sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
for test in tests:
status = cr.run([sys.executable, test],
status = cr.run([sys.executable, test] + gyp_options,
stdout=sys.stdout,
stderr=sys.stderr)
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
# found in the LICENSE file.
@ -15,7 +15,7 @@ MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
"""
import sys
import re
# Dictionaries of settings validators. The key is the tool name, the value is
# 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
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):
"""Convert the the MSVS macros found in the string to the MSBuild equivalent.
@ -378,14 +396,10 @@ def ConvertVCMacrosToMSBuild(s):
'$(ParentName)': '$(ProjectFileName)',
'$(PlatformName)': '$(Platform)',
'$(SafeInputName)': '%(Filename)',
'$(IntDir)\\': '$(IntDir)',
'$(OutDir)\\': '$(OutDir)',
'$(IntDir)/': '$(IntDir)',
'$(OutDir)/': '$(OutDir)',
}
for old, new in replace_map.iteritems():
s = s.replace(old, new)
s = FixVCMacroSlashes(s)
return s

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

@ -16,7 +16,7 @@ class VisualStudioVersion(object):
def __init__(self, short_name, description,
solution_version, project_version, flat_sln, uses_vcxproj,
path, sdk_based):
path, sdk_based, default_toolset=None):
self.short_name = short_name
self.description = description
self.solution_version = solution_version
@ -25,6 +25,7 @@ class VisualStudioVersion(object):
self.uses_vcxproj = uses_vcxproj
self.path = path
self.sdk_based = sdk_based
self.default_toolset = default_toolset
def ShortName(self):
return self.short_name
@ -60,6 +61,11 @@ class VisualStudioVersion(object):
"""Returns the path to a given compiler 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):
"""Returns a command (with arguments) to be used to set up the
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.
"""
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',
'Visual Studio 2010',
solution_version='11.00',
@ -252,9 +276,11 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
2005(e) - Visual Studio 2005 (8)
2008(e) - Visual Studio 2008 (9)
2010(e) - Visual Studio 2010 (10)
2012(e) - Visual Studio 2012 (11)
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 = []
for version in versions_to_check:
# Old method of searching for which VS version is installed
@ -306,13 +332,15 @@ def SelectVisualStudioVersion(version='auto'):
if version == 'auto':
version = os.environ.get('GYP_MSVS_VERSION', 'auto')
version_map = {
'auto': ('10.0', '9.0', '8.0'),
'auto': ('10.0', '9.0', '8.0', '11.0'),
'2005': ('8.0',),
'2005e': ('8.0',),
'2008': ('9.0',),
'2008e': ('9.0',),
'2010': ('10.0',),
'2010e': ('10.0',),
'2012': ('11.0',),
'2012e': ('11.0',),
}
version = str(version)
versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)

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

@ -1,6 +1,6 @@
#!/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
# found in the LICENSE file.
@ -39,11 +39,18 @@ def FindBuildFiles():
files = os.listdir(os.getcwd())
build_files = []
for file in files:
if file[-len(extension):] == extension:
if file.endswith(extension):
build_files.append(file)
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={},
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.
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)
# because ActivePython cannot handle key parameters to __import__.
generator = __import__(generator_name, globals(), locals(), generator_name)
@ -157,7 +179,10 @@ def RegenerateAppendFlag(flag, values, predicate, env_name, options):
flags = []
if options.use_environment and 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:
for flag_value in values:
flags.append(FormatOpt(flag, predicate(flag_value)))
@ -254,7 +279,7 @@ class RegeneratableOptionParser(optparse.OptionParser):
values._regeneration_metadata = self.__regeneratable_options
return values, args
def main(args):
def gyp_main(args):
my_name = os.path.basename(sys.argv[0])
parser = RegeneratableOptionParser()
@ -366,9 +391,8 @@ def main(args):
if not build_files:
build_files = FindBuildFiles()
if not build_files:
print >>sys.stderr, (usage + '\n\n%s: error: no build_file') % \
(my_name, my_name)
return 1
raise GypError((usage + '\n\n%s: error: no build_file') %
(my_name, my_name))
# TODO(mark): Chromium-specific hack!
# For Chromium, the gyp "depth" variable should always be a relative path
@ -393,10 +417,9 @@ def main(args):
break
if not options.depth:
raise Exception, \
'Could not automatically locate src directory. This is a ' + \
'temporary Chromium feature that will be removed. Use ' + \
'--depth as a workaround.'
raise GypError('Could not automatically locate src directory. This is'
'a temporary Chromium feature that will be removed. Use'
'--depth as a workaround.')
# If toplevel-dir is not set, we assume that depth is the root of our source
# tree.
@ -483,5 +506,12 @@ def main(args):
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__':
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]
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):
# "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:

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

@ -3,6 +3,7 @@
# found in the LICENSE file.
import re
import os
def XmlToString(content, encoding='utf-8', pretty=False):
@ -79,7 +80,7 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
rest = specification[1:]
if rest and isinstance(rest[0], dict):
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:]
if rest:
xml_parts.append('>')
@ -101,7 +102,8 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
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.
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.
"""
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
try:
@ -142,7 +146,12 @@ _xml_escape_re = re.compile(
"(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
def _XmlEscape(value):
def _XmlEscape(value, attr=False):
""" 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)

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

@ -32,11 +32,12 @@ class TestSequenceFunctions(unittest.TestCase):
def test_EasyXml_escaping(self):
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(
easy_xml.XmlToString(['test3', {'a': original}, original]),
'<?xml version="1.0" encoding="utf-8"?><test3 a="%s">%s</test3>' %
(converted, converted))
(converted, converted_apos))
def test_EasyXml_pretty(self):
self.assertEqual(
@ -73,8 +74,8 @@ class TestSequenceFunctions(unittest.TestCase):
'</PropertyGroup>'
'<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>'
'<PropertyGroup '
'Condition="&apos;$(Configuration)|$(Platform)&apos;=='
'&apos;Debug|Win32&apos;" Label="Configuration">'
'Condition="\'$(Configuration)|$(Platform)\'=='
'\'Debug|Win32\'" Label="Configuration">'
'<ConfigurationType>Application</ConfigurationType>'
'<CharacterSet>Unicode</CharacterSet>'
'</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.
"""
from xml.sax.saxutils import escape
import os.path
import subprocess
import gyp
@ -36,7 +37,8 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
'EXECUTABLE_PREFIX', 'EXECUTABLE_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] = ''
# 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)
for key in sorted(defines.iterkeys()):
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(' </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
# the side to keep the the files readable.
import os
import re
import sys
import gyp
import gyp.common
import gyp.system_test
import gyp.xcode_emulation
import os
import re
import sys
from gyp.common import GetEnvironFallback
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
@ -60,7 +61,6 @@ generator_extra_sources_for_rules = []
def CalculateVariables(default_variables, params):
"""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)
if flavor == '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.
LINK ?= %(flock)s $(builddir)/linker.lock $(CXX)
CC.target ?= $(CC)
CC.target ?= %(CC.target)s
CFLAGS.target ?= $(CFLAGS)
CXX.target ?= $(CXX)
CXX.target ?= %(CXX.target)s
CXXFLAGS.target ?= $(CXXFLAGS)
LINK.target ?= $(LINK)
LINK.target ?= %(LINK.target)s
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
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.
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= gcc
CC.host ?= %(CC.host)s
CFLAGS.host ?=
CXX.host ?= g++
CXX.host ?= %(CXX.host)s
CXXFLAGS.host ?=
LINK.host ?= g++
LINK.host ?= %(LINK.host)s
LDFLAGS.host ?=
AR.host ?= ar
AR.host ?= %(AR.host)s
ARFLAGS.host := %(ARFLAGS.host)s
# Define a dir function that can handle spaces.
@ -1590,18 +1590,19 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
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.
E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
foo = blaha blahb
but in a pretty-printed style.
"""
self.fp.write(variable + " := ")
if list:
list = [quoter(prefix + l) for l in list]
self.fp.write(" \\\n\t".join(list))
self.fp.write("\n\n")
values = ''
if value_list:
value_list = [quoter(prefix + l) for l in value_list]
values = ' \\\n\t' + ' \\\n\t'.join(value_list)
self.fp.write('%s :=%s\n\n' % (variable, values))
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."""
if '$(' in path:
path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
return path
return '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
if not '$(obj)' in path:
path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
return path
def Pchify(self, path, lang):
@ -1890,8 +1892,8 @@ def RunSystemTests(flavor):
# Compute flags used for building static archives.
# N.B.: this fallback logic should match the logic in SHARED_HEADER.
# See comment there for more details.
ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar'))
cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
ar_target = GetEnvironFallback(('AR_target', 'AR'), 'ar')
cc_target = GetEnvironFallback(('CC_target', 'CC'), 'cc')
arflags_target = 'crs'
# 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).
@ -1899,12 +1901,12 @@ def RunSystemTests(flavor):
cc_command=cc_target):
arflags_target = 'crsT'
ar_host = os.environ.get('AR.host', 'ar')
cc_host = os.environ.get('CC.host', 'gcc')
ar_host = os.environ.get('AR_host', 'ar')
cc_host = os.environ.get('CC_host', 'gcc')
arflags_host = 'crs'
# 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'
# while CC.target defaults to 'cc', so the commands really are different
# 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
# even though they're nearly guaranteed to run the same code underneath.
if flavor != 'mac' and gyp.system_test.TestArSupportsT(ar_command=ar_host,
cc_command=cc_host):
@ -1993,18 +1995,29 @@ def GenerateOutput(target_list, target_dicts, data, params):
header_params.update({
'flock': 'lockf',
})
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])
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 = ''
for key, value in make_global_settings_dict:
for key, value in make_global_settings_array:
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', 'CXX']:
elif 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.
@ -2046,8 +2059,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
build_file, target, toolset = gyp.common.ParseQualifiedTarget(
qualified_target)
this_make_global_settings = data[build_file].get('make_global_settings', {})
assert make_global_settings_dict == this_make_global_settings, (
this_make_global_settings = data[build_file].get('make_global_settings', [])
assert make_global_settings_array == this_make_global_settings, (
"make_global_settings needs to be the same for all targets.")
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('\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)
root_makefile.write(SHARED_FOOTER)

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

@ -39,10 +39,10 @@ generator_default_variables = {
'STATIC_LIB_SUFFIX': '.lib',
'SHARED_LIB_SUFFIX': '.dll',
'INTERMEDIATE_DIR': '$(IntDir)',
'SHARED_INTERMEDIATE_DIR': '$(OutDir)/obj/global_intermediate',
'SHARED_INTERMEDIATE_DIR': '$(OutDir)obj/global_intermediate',
'OS': 'win',
'PRODUCT_DIR': '$(OutDir)',
'LIB_DIR': '$(OutDir)\\lib',
'LIB_DIR': '$(OutDir)lib',
'RULE_INPUT_ROOT': '$(InputName)',
'RULE_INPUT_DIRNAME': '$(InputDir)',
'RULE_INPUT_EXT': '$(InputExt)',
@ -268,8 +268,7 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
direct_cmd = [i.replace('$(InputPath)',
'`cygpath -m "${INPUTPATH}"`')
for i in direct_cmd]
direct_cmd = ['"%s"' % i for i in direct_cmd]
direct_cmd = [i.replace('"', '\\"') for i in direct_cmd]
direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd]
#direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
direct_cmd = ' '.join(direct_cmd)
# TODO(quote): regularize quoting path names throughout the module
@ -295,10 +294,19 @@ def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
command = ['type']
else:
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
# If the argument starts with a slash, it's probably a command line switch
arguments = [i.startswith('/') and i or _FixPath(i) for i in cmd[1:]]
# TODO(quote): This is a really ugly heuristic, and will miss path fixing
# 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 = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments]
if quote_cmd:
# Support a mode for using cmd directly.
# Convert any paths to native form (first element is used directly).
@ -830,18 +838,22 @@ def _GetGuidOfProject(proj_path, spec):
return guid
def _GetMsbuildToolsetOfProject(proj_path, spec):
def _GetMsbuildToolsetOfProject(proj_path, spec, version):
"""Get the platform toolset for the project.
Arguments:
proj_path: Path of the vcproj or vcxproj file to generate.
spec: The target dictionary containing the properties of the target.
version: The MSVSVersion object.
Returns:
the platform toolset string or None.
"""
# Pluck out the default configuration.
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):
@ -896,7 +908,8 @@ def _GenerateMSVSProject(project, options, version, generator_flags):
# Prepare list of sources and excluded sources.
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.
actions_to_add = {}
@ -1046,7 +1059,7 @@ def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
defines)
# Change program database directory to prevent collisions.
_ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName',
'$(IntDir)\\$(ProjectName)\\vc80.pdb', only_if_unset=True)
'$(IntDir)$(ProjectName)\\vc80.pdb', only_if_unset=True)
# Add disabled warnings.
_ToolAppend(tools, 'VCCLCompilerTool',
'DisableSpecificWarnings', disabled_warnings)
@ -1133,10 +1146,10 @@ def _GetOutputFilePathAndTool(spec):
vc_tool = ''
msbuild_tool = ''
output_file_map = {
'executable': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.exe'),
'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'),
'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'),
'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)\\lib\\', '.lib'),
'executable': ('VCLinkerTool', 'Link', '$(OutDir)', '.exe'),
'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)lib\\', '.lib'),
}
output_file_props = output_file_map.get(spec['type'])
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
output_dir = prepared_attrs.get('OutputDirectory',
'$(SolutionDir)$(ConfigurationName)')
prepared_attrs['OutputDirectory'] = output_dir
prepared_attrs['OutputDirectory'] = _FixPath(output_dir) + '\\'
if 'IntermediateDirectory' not in prepared_attrs:
intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)'
prepared_attrs['IntermediateDirectory'] = _FixPath(intermediate) + '\\'
else:
intermediate = _FixPath(prepared_attrs['IntermediateDirectory']) + '\\'
intermediate = MSVSSettings.FixVCMacroSlashes(intermediate)
prepared_attrs['IntermediateDirectory'] = intermediate
return prepared_attrs
@ -1261,7 +1278,7 @@ def _AddNormalizedSources(sources_set, sources_array):
sources_set.update(set(sources))
def _PrepareListOfSources(spec, gyp_file):
def _PrepareListOfSources(spec, generator_flags, gyp_file):
"""Prepare list of sources and excluded sources.
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', []))
excluded_sources = set()
# 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.
for a in spec.get('actions', []):
@ -1598,7 +1616,7 @@ def _GetPathOfProject(qualified_target, spec, options, msvs_version):
msvs_version.ProjectExtension())
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
if options.generator_output:
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)
# Set project toolset if any (MS build only)
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
# Set all the dependencies
for project in projects.values():
@ -1804,9 +1823,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
for build_file in data:
# Validate build_file extension
if build_file[-4:] != '.gyp':
if not build_file.endswith('.gyp'):
continue
sln_path = build_file[:-4] + options.suffix + '.sln'
sln_path = os.path.splitext(build_file)[0] + options.suffix + '.sln'
if options.generator_output:
sln_path = os.path.join(options.generator_output, sln_path)
# Get projects in the solution, and their dependents.
@ -1856,7 +1875,7 @@ def _GenerateMSBuildFiltersFile(filters_path, source_files,
['ItemGroup'] + filter_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):
# We don't need this filter anymore. Delete the old filter file.
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):
@ -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):
@ -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):
@ -2505,9 +2524,6 @@ def _GetMSBuildPropertySheets(configurations):
return sheets
def _ConvertMSVSBuildAttributes(spec, config, build_file):
config_type = _GetMSVSConfigurationType(spec, build_file)
msvs_attributes = _GetMSVSAttributes(spec, config, config_type)
msbuild_attributes = {}
@ -2558,10 +2574,10 @@ def _GetMSBuildAttributes(spec, config, build_file):
msbuild_attributes['ConfigurationType'] = config_type
output_dir = msbuild_attributes.get('OutputDirectory',
'$(SolutionDir)$(Configuration)\\')
msbuild_attributes['OutputDirectory'] = output_dir
msbuild_attributes['OutputDirectory'] = _FixPath(output_dir)
if 'IntermediateDirectory' not in msbuild_attributes:
intermediate = '$(Configuration)\\'
msbuild_attributes['IntermediateDirectory'] = intermediate
msbuild_attributes['IntermediateDirectory'] = _FixPath(intermediate)
if 'CharacterSet' in msbuild_attributes:
msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet(
msbuild_attributes['CharacterSet'])
@ -2584,7 +2600,7 @@ def _GetMSBuildAttributes(spec, config, build_file):
msbuild_settings = config['finalized_msbuild_settings']
out_file = msbuild_settings[msbuild_tool].get('OutputFile')
if out_file:
msbuild_attributes['TargetPath'] = out_file
msbuild_attributes['TargetPath'] = _FixPath(out_file)
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)
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.
actions_to_add = {}
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:
# 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

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

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

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

@ -7,6 +7,7 @@ import gyp.common
import gyp.xcodeproj_file
import errno
import os
import sys
import posixpath
import re
import shutil
@ -145,7 +146,6 @@ class XcodeProject(object):
xccl = CreateXCConfigurationList(configurations)
self.project.SetProperty('buildConfigurationList', xccl)
except:
import sys
sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path)
raise
@ -526,7 +526,7 @@ def AddSourceToTarget(source, type, pbxp, xct):
basename = posixpath.basename(source)
(root, ext) = posixpath.splitext(basename)
if ext != '':
if ext:
ext = ext[1:].lower()
if ext in source_extensions and type != 'none':
@ -614,11 +614,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
if project_version:
xcp.project_file.SetXcodeVersion(project_version)
main_group = pbxp.GetProperty('mainGroup')
build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
main_group.AppendChild(build_group)
for included_file in build_file_dict['included_files']:
build_group.AddOrGetFileByPath(included_file, False)
# Add gyp/gypi files to project
if not generator_flags.get('standalone'):
main_group = pbxp.GetProperty('mainGroup')
build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
main_group.AppendChild(build_group)
for included_file in build_file_dict['included_files']:
build_group.AddOrGetFileByPath(included_file, False)
xcode_targets = {}
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
standard environment variable, and if that doesn't exist, try to find
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')
if not dxsdk_dir:
# Setup params to pass to and attempt to launch reg.exe.
@ -121,6 +125,9 @@ def _FindDirectXInstallation():
for line in p.communicate()[0].splitlines():
if 'InstallPath' in line:
dxsdk_dir = line.split(' ')[3] + "\\"
# Cache return value
_FindDirectXInstallation.dxsdk_dir = dxsdk_dir
return dxsdk_dir
@ -169,6 +176,7 @@ class MsvsSettings(object):
'$(InputName)': '${root}',
'$(ProjectName)': self.spec['target_name'],
'$(PlatformName)': target_platform,
'$(ProjectDir)\\': '',
}
# 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
@ -362,8 +370,10 @@ class MsvsSettings(object):
elif len(def_files) > 1:
raise Exception("Multiple .def files")
def GetLdflags(self, config, gyp_to_build_path, expand_special):
"""Returns the flags that need to be added to link commands."""
def GetLdflags(self, config, gyp_to_build_path, expand_special,
manifest_base_name, is_executable):
"""Returns the flags that need to be added to link commands, and the
manifest files."""
config = self._RealConfig(config)
ldflags = []
ld = self._GetWrapper(self, self.msvs_settings[config],
@ -412,7 +422,46 @@ class MsvsSettings(object):
if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
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):
"""Returns whether the target should be linked via Use Library Dependency
@ -447,8 +496,8 @@ class MsvsSettings(object):
cygwin_dir = os.path.normpath(
os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
cd = ('cd %s' % path_to_base).replace('\\', '/')
args = [a.replace('\\', '/') for a in args]
args = ["'%s'" % a.replace("'", "\\'") for a in args]
args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
args = ["'%s'" % a.replace("'", "'\\''") for a in args]
bash_cmd = ' '.join(args)
cmd = (
'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)
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):
self._line('rule %s' % name)
self.variable('command', command, indent=1)
@ -43,8 +43,6 @@ class Writer(object):
self.variable('description', description, indent=1)
if depfile:
self.variable('depfile', depfile, indent=1)
if deplist:
self.variable('deplist', deplist, indent=1)
if generator:
self.variable('generator', '1', indent=1)
if restat:

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

@ -13,6 +13,9 @@ import os
import shutil
import subprocess
import sys
import win32con
import win32file
import pywintypes
def main(args):
@ -22,6 +25,22 @@ def main(args):
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):
"""This class performs all the Windows tooling steps. The methods can either
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'
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)
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 '):
if line and 'manifest authoring warning 81010002' not in line:
print line
return popen.returncode

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

@ -244,8 +244,9 @@ class XcodeSettings(object):
def _SdkPath(self):
sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5')
if sdk_root.startswith('macosx'):
sdk_root = 'MacOSX' + sdk_root[len('macosx'):]
return os.path.join(self._GetSdkBaseDir(), '%s.sdk' % sdk_root)
return os.path.join(self._GetSdkBaseDir(),
'MacOSX' + sdk_root[len('macosx'):] + '.sdk')
return sdk_root
def GetCflags(self, configname):
"""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]
framework_dirs = config.get('mac_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
return cflags
@ -553,6 +554,11 @@ class XcodeSettings(object):
for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []):
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
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
# found in the LICENSE file.
@ -1199,11 +1199,9 @@ class PBXGroup(XCHierarchicalElement):
is_dir = False
if path.endswith('/'):
is_dir = True
normpath = posixpath.normpath(path)
path = posixpath.normpath(path)
if is_dir:
normpath = path + '/'
else:
normpath = path
path = path + '/'
# Adding or getting a variant? Variants are files inside directories
# with an ".lproj" extension. Xcode uses variants for localization. For
@ -1232,7 +1230,7 @@ class PBXGroup(XCHierarchicalElement):
# this PBXGroup, no recursion necessary.
if variant_name is None:
# Add or get a PBXFileReference.
file_ref = self.GetChildByPath(normpath)
file_ref = self.GetChildByPath(path)
if file_ref != None:
assert file_ref.__class__ == PBXFileReference
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