Issue #2974 - Part 34: Import new version of gyp, ensure it finds six.

Dropping this in actually just works for NSS (no promises this will hold true
with Basilisk), because gyp's design is a lot more conservative and consistent
compared with upstream Mozilla code. For some reason, the new gyp couldn't find
the six library it relies on that's already in our tree, and the library also
needed a small update. Also incorporates a few simple Python 3 tweaks to our
gyp_reader code.
This commit is contained in:
Jeremy Andrews committed 2026-03-11 01:59:39 -05:00
1 parent cb559a5eb2
commit 3dd092c8d8
34 files changed
+1468 -1090

No files matched your search

+1
View File
@@ -29,6 +29,7 @@ moztreedocs.pth:tools/docs
packages.txt:testing/mozbase/packages.txt
objdir:build
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
six.pth:python/requests/requests/packages/urllib3/packages
pyasn1.pth:python/pyasn1
pyasn1_modules.pth:python/pyasn1-modules
bitstring.pth:python/bitstring
@@ -6,6 +6,7 @@
import os
import random
import sys
import gyp.common
@@ -21,6 +22,13 @@ except ImportError:
_new_md5 = md5.new
try:
# cmp was removed in python3.
cmp
except NameError:
def cmp(a, b):
return (a > b) - (a < b)
# Initialize random number generator
random.seed()
@@ -49,8 +57,11 @@ def MakeGuid(name, seed='msvs_new'):
determine the GUID to refer to explicitly. It also means that the GUID will
not change when the project for a target is rebuilt.
"""
to_hash = str(seed) + str(name)
to_hash = to_hash.encode('utf-8')
# Calculate a MD5 signature for the seed and name.
d = _new_md5(str(seed) + str(name)).hexdigest().upper()
d = _new_md5(to_hash).hexdigest().upper()
# Convert most of the signature to GUID form (discard the rest)
guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20]
+ '-' + d[20:32] + '}')
@@ -64,6 +75,8 @@ class MSVSSolutionEntry(object):
# Sort by name then guid (so things are in order on vs2008).
return cmp((self.name, self.get_guid()), (other.name, other.get_guid()))
def __lt__(self, other):
return (self.name, self.get_guid()) < (other.name, other.get_guid())
class MSVSFolder(MSVSSolutionEntry):
"""Folder in a Visual Studio project or solution."""
@@ -14,9 +14,17 @@ The MSBuild schemas were also considered. They are typically found in the
MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
"""
from __future__ import print_function
import sys
import re
try:
# basestring was removed in python3.
basestring
except NameError:
basestring = str
# Dictionaries of settings validators. The key is the tool name, the value is
# a dictionary mapping setting names to validation functions.
_msvs_validators = {}
@@ -463,7 +471,8 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
msvs_tool[msvs_setting](msvs_value, msbuild_settings)
except ValueError as e:
print(('Warning: while converting %s/%s to MSBuild, '
'%s' % (msvs_tool_name, msvs_setting, e)), file=stderr)
'%s' % (msvs_tool_name, msvs_setting, e)),
file=stderr)
else:
_ValidateExclusionSetting(msvs_setting,
msvs_tool,
@@ -6,7 +6,10 @@
"""Unit tests for the MSVSSettings.py file."""
import io
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import unittest
import gyp.MSVSSettings as MSVSSettings
@@ -14,7 +17,7 @@ import gyp.MSVSSettings as MSVSSettings
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.stderr = io.StringIO()
self.stderr = StringIO()
def _ExpectedWarnings(self, expected):
"""Compares recorded lines to expected warnings."""
@@ -13,12 +13,20 @@ import gyp
import glob
def JoinPath(*args):
return os.path.normpath(os.path.join(*args))
def version_to_tuple(version_str):
return tuple(int(x) for x in version_str.split('.'))
class VisualStudioVersion(object):
"""Information regarding a version of Visual Studio."""
def __init__(self, short_name, description,
solution_version, project_version, flat_sln, uses_vcxproj,
path, sdk_based, default_toolset=None):
path, sdk_based, default_toolset=None, compatible_sdks=None):
self.short_name = short_name
self.description = description
self.solution_version = solution_version
@@ -28,6 +36,9 @@ class VisualStudioVersion(object):
self.path = path
self.sdk_based = sdk_based
self.default_toolset = default_toolset
compatible_sdks = compatible_sdks or []
compatible_sdks.sort(key=lambda v: float(v.replace('v', '')), reverse=True)
self.compatible_sdks = compatible_sdks
def ShortName(self):
return self.short_name
@@ -68,45 +79,59 @@ class VisualStudioVersion(object):
of a user override."""
return self.default_toolset
def _SetupScriptInternal(self, target_arch):
"""Returns a command (with arguments) to be used to set up the
environment."""
assert target_arch in ('x86', 'x64'), "target_arch not supported"
# If WindowsSDKDir is set and SetEnv.Cmd exists then we are using the
# depot_tools build tools and should run SetEnv.Cmd to set up the
# environment. The check for WindowsSDKDir alone is not sufficient because
# this is set by running vcvarsall.bat.
assert target_arch in ('x86', 'x64')
sdk_dir = os.environ.get('WindowsSDKDir')
if sdk_dir:
setup_path = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd'))
sdk_dir = os.environ.get('WindowsSDKDir', '')
setup_path = JoinPath(sdk_dir, 'Bin', 'SetEnv.Cmd')
if self.sdk_based and sdk_dir and os.path.exists(setup_path):
return [setup_path, '/' + target_arch]
else:
# We don't use VC/vcvarsall.bat for x86 because vcvarsall calls
# vcvars32, which it can only find if VS??COMNTOOLS is set, which it
# isn't always.
if target_arch == 'x86':
if self.short_name >= '2013' and self.short_name[-1] != 'e' and (
os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
# VS2013 and later, non-Express have a x64-x86 cross that we want
# to prefer.
return [os.path.normpath(
os.path.join(self.path, 'VC/vcvarsall.bat')), 'amd64_x86']
# Otherwise, the standard x86 compiler.
return [os.path.normpath(
os.path.join(self.path, 'Common7/Tools/vsvars32.bat'))]
is_host_arch_x64 = (
os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'
)
# For VS2017 (and newer) it's fairly easy
if self.short_name >= '2017':
script_path = JoinPath(self.path,
'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')
# Always use a native executable, cross-compiling if necessary.
host_arch = 'amd64' if is_host_arch_x64 else 'x86'
msvc_target_arch = 'amd64' if target_arch == 'x64' else 'x86'
arg = host_arch
if host_arch != msvc_target_arch:
arg += '_' + msvc_target_arch
return [script_path, arg]
# We try to find the best version of the env setup batch.
vcvarsall = JoinPath(self.path, 'VC', 'vcvarsall.bat')
if target_arch == 'x86':
if self.short_name >= '2013' and self.short_name[-1] != 'e' and \
is_host_arch_x64:
# VS2013 and later, non-Express have a x64-x86 cross that we want
# to prefer.
return [vcvarsall, 'amd64_x86']
else:
assert target_arch == 'x64'
arg = 'x86_amd64'
# Use the 64-on-64 compiler if we're not using an express
# edition and we're running on a 64bit OS.
if self.short_name[-1] != 'e' and (
os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
arg = 'amd64'
return [os.path.normpath(
os.path.join(self.path, 'VC/vcvarsall.bat')), arg]
# Otherwise, the standard x86 compiler. We don't use VC/vcvarsall.bat
# for x86 because vcvarsall calls vcvars32, which it can only find if
# VS??COMNTOOLS is set, which isn't guaranteed.
return [JoinPath(self.path, 'Common7', 'Tools', 'vsvars32.bat')]
elif target_arch == 'x64':
arg = 'x86_amd64'
# Use the 64-on-64 compiler if we're not using an express edition and
# we're running on a 64bit OS.
if self.short_name[-1] != 'e' and is_host_arch_x64:
arg = 'amd64'
return [vcvarsall, arg]
def SetupScript(self, target_arch):
script_data = self._SetupScriptInternal(target_arch)
@@ -186,7 +211,10 @@ def _RegistryGetValueUsingWinReg(key, value):
contents of the registry key's value, or None on failure. Throws
ImportError if _winreg is unavailable.
"""
import winreg
try:
import _winreg as winreg
except ImportError:
import winreg
try:
root, subkey = key.split('\\', 1)
assert root == 'HKLM' # Only need HKLM for now.
@@ -236,6 +264,36 @@ def _CreateVersion(name, path, sdk_based=False):
if path:
path = os.path.normpath(path)
versions = {
'2022': VisualStudioVersion('2022',
'Visual Studio 2022',
solution_version='12.00',
project_version='17.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v143',
compatible_sdks=['v8.1', 'v10.0']),
'2019': VisualStudioVersion('2019',
'Visual Studio 2019',
solution_version='12.00',
project_version='16.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v142',
compatible_sdks=['v8.1', 'v10.0']),
'2017': VisualStudioVersion('2017',
'Visual Studio 2017',
solution_version='12.00',
project_version='15.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v141',
compatible_sdks=['v8.1', 'v10.0']),
'2015': VisualStudioVersion('2015',
'Visual Studio 2015',
solution_version='12.00',
@@ -348,7 +406,6 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
A list of visual studio versions installed in descending order of
usage preference.
Base this on the registry and a quick check if devenv.exe exists.
Only versions 8-10 are considered.
Possibilities are:
2005(e) - Visual Studio 2005 (8)
2008(e) - Visual Studio 2008 (9)
@@ -356,6 +413,9 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
2012(e) - Visual Studio 2012 (11)
2013(e) - Visual Studio 2013 (12)
2015 - Visual Studio 2015 (14)
2017 - Visual Studio 2017 (15)
2019 - Visual Studio 2019 (16)
2022 - Visual Studio 2022 (17)
Where (e) is e for express editions of MSVS and blank otherwise.
"""
version_to_year = {
@@ -365,8 +425,19 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
'11.0': '2012',
'12.0': '2013',
'14.0': '2015',
'15.0': '2017',
'16.0': '2019',
'17.0': '2022',
}
versions = []
# MSVC's vcvars*.bat scripts set up extra environment variables we can use:
# * path to the VS installation root, for example:
# C:\Program Files\Microsoft Visual Studio\2022\Professional
env_vs_path = os.getenv('VSINSTALLDIR')
# * VS version, e.g. 17.0
env_vs_version = os.getenv('VisualStudioVersion')
for version in versions_to_check:
# Old method of searching for which VS version is installed
# We don't use the 2010-encouraged-way because we also want to get the
@@ -395,16 +466,25 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
# The old method above does not work when only SDK is installed.
keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7',
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7']
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7',
r'HKLM\Software\Microsoft\VisualStudio\SxS\VS7',
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VS7']
for index in range(len(keys)):
path = _RegistryGetValue(keys[index], version)
if not path:
continue
path = _ConvertToCygpath(path)
if version != '14.0': # There is no Express edition for 2015.
if version_to_tuple(version) >= (15, 0):
if os.path.exists(path):
versions.append(_CreateVersion(version_to_year[version], path))
elif version != '14.0': # There is no Express edition for 2015.
versions.append(_CreateVersion(version_to_year[version] + 'e',
os.path.join(path, '..'), sdk_based=True))
if env_vs_version and env_vs_path and env_vs_version == version:
versions.append(_CreateVersion(version_to_year[env_vs_version],
env_vs_path))
return versions
@@ -420,7 +500,8 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
if version == 'auto':
version = os.environ.get('GYP_MSVS_VERSION', 'auto')
version_map = {
'auto': ('14.0', '12.0', '10.0', '9.0', '8.0', '11.0'),
'auto': ('17.0', '16.0', '15.0', '14.0', '12.0', '10.0', '9.0', '8.0',
'11.0'),
'2005': ('8.0',),
'2005e': ('8.0',),
'2008': ('9.0',),
@@ -432,6 +513,9 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
'2013': ('12.0',),
'2013e': ('12.0',),
'2015': ('14.0',),
'2017': ('15.0',),
'2019': ('16.0',),
'2022': ('17.0',),
}
override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
if override_path:
@@ -4,6 +4,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
import copy
import gyp.input
import optparse
@@ -14,6 +16,12 @@ import sys
import traceback
from gyp.common import GypError
try:
# basestring was removed in python3.
basestring
except NameError:
basestring = str
# Default debug modes for GYP
debug = {}
@@ -22,7 +30,6 @@ DEBUG_GENERAL = 'general'
DEBUG_VARIABLES = 'variables'
DEBUG_INCLUDES = 'includes'
def DebugOutput(mode, message, *args):
if 'all' in gyp.debug or mode in gyp.debug:
ctx = ('unknown', 0, 'unknown')
@@ -70,9 +77,6 @@ def Load(build_files, format, default_variables={},
default_variables['GENERATOR'] = format
default_variables['GENERATOR_FLAVOR'] = params.get('flavor', '')
# Provide a PYTHON value to run sub-commands with the same python
default_variables['PYTHON'] = sys.executable
# Format can be a custom python file, or by default the name of a module
# within gyp.generator.
if format.endswith('.py'):
@@ -92,7 +96,7 @@ def Load(build_files, format, default_variables={},
# 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)
for (key, val) in list(generator.generator_default_variables.items()):
for (key, val) in generator.generator_default_variables.items():
default_variables.setdefault(key, val)
# Give the generator the opportunity to set additional variables based on
@@ -231,7 +235,8 @@ def RegenerateFlags(options):
elif options.use_environment and env_name:
print(('Warning: environment regeneration unimplemented '
'for %s flag %r env_name %r' % (action, opt,
env_name)), file=sys.stderr)
env_name)),
file=sys.stderr)
else:
print(('Warning: regeneration unimplemented for action %r '
'flag %r' % (action, opt)), file=sys.stderr)
@@ -434,12 +439,11 @@ def gyp_main(args):
for build_file in build_files:
build_file_dir = os.path.abspath(os.path.dirname(build_file))
build_file_dir_components = build_file_dir.split(os.path.sep)
components_len = len(build_file_dir_components)
for index in range(components_len - 1, -1, -1):
if build_file_dir_components[index] == 'src':
for component in reversed(build_file_dir_components):
if component == 'src':
options.depth = os.path.sep.join(build_file_dir_components)
break
del build_file_dir_components[index]
del build_file_dir_components[-1]
# If the inner loop found something, break without advancing to another
# build file.
@@ -493,7 +497,7 @@ def gyp_main(args):
if options.generator_flags:
gen_flags += options.generator_flags
generator_flags = NameValueListToDict(gen_flags)
if DEBUG_GENERAL in list(gyp.debug.keys()):
if DEBUG_GENERAL in gyp.debug:
DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
# Generate all requested formats (use a set in case we got one format request
@@ -526,7 +530,7 @@ def gyp_main(args):
generator.GenerateOutput(flat_list, targets, data, params)
if options.configs:
valid_configs = list(targets[flat_list[0]]['configurations'].keys())
valid_configs = targets[flat_list[0]]['configurations']
for conf in options.configs:
if conf not in valid_configs:
raise GypError('Invalid config specified via --build: %s' % conf)
@@ -4,7 +4,6 @@
from __future__ import with_statement
import collections
import errno
import filecmp
import os.path
@@ -12,6 +11,8 @@ import re
import tempfile
import sys
from six.moves import collections_abc
# A minimal memoizing decorator. It'll blow up if the args aren't immutable,
# among other "problems".
@@ -345,7 +346,7 @@ def WriteOnDiff(filename):
prefix=os.path.split(filename)[1] + '.gyp.',
dir=os.path.split(filename)[0])
try:
self.tmp_file = os.fdopen(tmp_fd, 'wb')
self.tmp_file = os.fdopen(tmp_fd, 'w')
except Exception:
# Don't leave turds behind.
os.unlink(self.tmp_path)
@@ -429,6 +430,10 @@ def GetFlavor(params):
return 'netbsd'
if sys.platform.startswith('aix'):
return 'aix'
if sys.platform.startswith('zos'):
return 'zos'
if sys.platform.startswith('os390'):
return 'zos'
return 'linux'
@@ -490,7 +495,7 @@ def uniquer(seq, idfun=None):
# Based on http://code.activestate.com/recipes/576694/.
class OrderedSet(collections.MutableSet):
class OrderedSet(collections_abc.MutableSet):
def __init__(self, iterable=None):
self.end = end = []
end += [None, end, end] # sentinel node for doubly linked list
@@ -580,7 +585,7 @@ def TopologicallySorted(graph, get_edges):
graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'}
def GetEdges(node):
return re.findall(r'\$\(([^))]\)', graph[node])
print TopologicallySorted(graph.keys(), GetEdges)
print(TopologicallySorted(graph.keys(), GetEdges))
==>
['a', 'c', b']
"""
@@ -23,7 +23,7 @@ class TestTopologicallySorted(unittest.TestCase):
def GetEdge(node):
return tuple(graph[node])
self.assertEqual(
gyp.common.TopologicallySorted(list(graph.keys()), GetEdge),
gyp.common.TopologicallySorted(graph.keys(), GetEdge),
['a', 'c', 'd', 'b'])
def test_Cycle(self):
@@ -38,7 +38,7 @@ class TestTopologicallySorted(unittest.TestCase):
return tuple(graph[node])
self.assertRaises(
gyp.common.CycleError, gyp.common.TopologicallySorted,
list(graph.keys()), GetEdge)
graph.keys(), GetEdge)
class TestGetFlavor(unittest.TestCase):
@@ -63,6 +63,7 @@ class TestGetFlavor(unittest.TestCase):
self.assertFlavor('solaris', 'sunos' , {});
self.assertFlavor('linux' , 'linux2' , {});
self.assertFlavor('linux' , 'linux3' , {});
self.assertFlavor('linux' , 'linux' , {});
def test_param(self):
self.assertFlavor('foobar', 'linux2' , {'flavor': 'foobar'})
@@ -4,8 +4,14 @@
import re
import os
from functools import reduce
import locale
import sys
try:
# reduce moved to functools in python3.
reduce
except NameError:
from functools import reduce
def XmlToString(content, encoding='utf-8', pretty=False):
""" Writes the XML content to disk, touching the file only if it has changed.
@@ -116,6 +122,12 @@ def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
xml_string = XmlToString(content, encoding, pretty)
if win32 and os.linesep != '\r\n':
xml_string = xml_string.replace('\n', '\r\n')
default_encoding = locale.getdefaultlocale()[1]
if default_encoding and default_encoding.upper() != encoding.upper():
try:
xml_string = xml_string.decode(default_encoding).encode(encoding)
except AttributeError:
pass
# Get the old content
try:
@@ -144,7 +156,7 @@ _xml_escape_map = {
_xml_escape_re = re.compile(
"(%s)" % "|".join(map(re.escape, list(_xml_escape_map.keys()))))
"(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
def _XmlEscape(value, attr=False):
@@ -8,13 +8,16 @@
import gyp.easy_xml as easy_xml
import unittest
import io
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.stderr = io.StringIO()
self.stderr = StringIO()
def test_EasyXml_simple(self):
self.assertEqual(
@@ -78,6 +81,7 @@ class TestSequenceFunctions(unittest.TestCase):
'\'Debug|Win32\'" Label="Configuration">'
'<ConfigurationType>Application</ConfigurationType>'
'<CharacterSet>Unicode</CharacterSet>'
'<SpectreMitigation>SpectreLoadCF</SpectreMitigation>'
'</PropertyGroup>'
'</Project>')
@@ -93,7 +97,8 @@ class TestSequenceFunctions(unittest.TestCase):
{'Condition': "'$(Configuration)|$(Platform)'=='Debug|Win32'",
'Label': 'Configuration'},
['ConfigurationType', 'Application'],
['CharacterSet', 'Unicode']
['CharacterSet', 'Unicode'],
['SpectreMitigation', 'SpectreLoadCF']
]
])
self.assertEqual(xml, target)
@@ -62,6 +62,8 @@ directly supplied to gyp. OTOH if both "a.gyp" and "b.gyp" are supplied to gyp
then the "all" target includes "b1" and "b2".
"""
from __future__ import print_function
import gyp.common
import gyp.ninja_syntax as ninja_syntax
import json
@@ -410,7 +412,7 @@ def _GetUnqualifiedToTargetMapping(all_targets, to_find):
if not to_find:
return {}, []
to_find = set(to_find)
for target_name in list(all_targets.keys()):
for target_name in all_targets.keys():
extracted = gyp.common.ParseQualifiedTarget(target_name)
if len(extracted) > 1 and extracted[1] in to_find:
to_find.remove(extracted[1])
@@ -484,12 +486,13 @@ def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
(add_if_no_ancestor or target.requires_build)) or
(target.is_static_library and add_if_no_ancestor and
not target.is_or_has_linked_ancestor)):
print('\t\tadding to compile targets', target.name, 'executable', \
target.is_executable, 'added_to_compile_targets', \
target.added_to_compile_targets, 'add_if_no_ancestor', \
add_if_no_ancestor, 'requires_build', target.requires_build, \
'is_static_library', target.is_static_library, \
'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor)
print('\t\tadding to compile targets', target.name, 'executable',
target.is_executable, 'added_to_compile_targets',
target.added_to_compile_targets, 'add_if_no_ancestor',
add_if_no_ancestor, 'requires_build', target.requires_build,
'is_static_library', target.is_static_library,
'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
)
result.add(target)
target.added_to_compile_targets = True
@@ -28,6 +28,8 @@ not be able to find the header file directories described in the generated
CMakeLists.txt file.
"""
from __future__ import print_function
import multiprocessing
import os
import signal
@@ -36,6 +38,12 @@ import subprocess
import gyp.common
import gyp.xcode_emulation
try:
# maketrans moved to str in python3.
_maketrans = string.maketrans
except NameError:
_maketrans = str.maketrans
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '',
@@ -238,7 +246,7 @@ def StringToCMakeTargetName(a):
Invalid for make: ':'
Invalid for unknown reasons but cause failures: '.'
"""
return a.translate(string.maketrans(' /():."', '_______'))
return a.translate(_maketrans(' /():."', '_______'))
def WriteActions(target_name, actions, extra_sources, extra_deps,
@@ -273,7 +281,7 @@ def WriteActions(target_name, actions, extra_sources, extra_deps,
dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
if int(action.get('process_outputs_as_sources', False)):
extra_sources.extend(list(zip(cmake_outputs, outputs)))
extra_sources.extend(zip(cmake_outputs, outputs))
# add_custom_command
output.write('add_custom_command(OUTPUT ')
@@ -644,8 +652,8 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
if cmake_target_type is None:
print(('Target %s has unknown target type %s, skipping.' %
( target_name, target_type ) ))
print('Target %s has unknown target type %s, skipping.' %
( target_name, target_type ))
return
SetVariable(output, 'TARGET', target_name)
@@ -979,7 +987,7 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
# XCode settings
xcode_settings = config.get('xcode_settings', {})
for xcode_setting, xcode_value in xcode_settings.items():
for xcode_setting, xcode_value in xcode_settings.viewitems():
SetTargetProperty(output, cmake_target_name,
"XCODE_ATTRIBUTE_%s" % xcode_setting, xcode_value,
'' if isinstance(xcode_value, str) else ' ')
@@ -1230,7 +1238,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
GenerateOutputForConfig(target_list, target_dicts, data,
params, user_config)
else:
config_names = list(target_dicts[target_list[0]]['configurations'].keys())
config_names = target_dicts[target_list[0]]['configurations']
if params['parallel']:
try:
pool = multiprocessing.Pool(len(config_names))
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
import collections
import os
import gyp
@@ -34,7 +36,7 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
def CalculateVariables(default_variables, params):
generator_flags = params.get('generator_flags', {})
for key, val in list(generator_flags.items()):
for key, val in generator_flags.items():
default_variables.setdefault(key, val)
default_variables.setdefault('OS', gyp.common.GetFlavor(params))
@@ -52,7 +52,7 @@ generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \
def CalculateVariables(default_variables, params):
generator_flags = params.get('generator_flags', {})
for key, val in list(generator_flags.items()):
for key, val in generator_flags.items():
default_variables.setdefault(key, val)
flavor = gyp.common.GetFlavor(params)
default_variables.setdefault('OS', flavor)
@@ -418,7 +418,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
GenerateOutputForConfig(target_list, target_dicts, data, params,
user_config)
else:
config_names = list(target_dicts[target_list[0]]['configurations'].keys())
config_names = target_dicts[target_list[0]]['configurations']
for config_name in config_names:
GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name)
@@ -21,6 +21,8 @@
# toplevel Makefile. It may make sense to generate some .mk files on
# the side to keep the the files readable.
from __future__ import print_function
import os
import re
import sys
@@ -31,6 +33,8 @@ import gyp.xcode_emulation
from gyp.common import GetEnvironFallback
from gyp.common import GypError
import hashlib
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '',
@@ -90,7 +94,10 @@ def CalculateVariables(default_variables, params):
if flavor == 'android':
operating_system = 'linux' # Keep this legacy behavior for now.
default_variables.setdefault('OS', operating_system)
default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
if flavor == 'aix':
default_variables.setdefault('SHARED_LIB_SUFFIX', '.a')
else:
default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)')
default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)')
@@ -227,6 +234,24 @@ cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSE
"""
LINK_COMMANDS_OS390 = """\
quiet_cmd_alink = AR($(TOOLSET)) $@
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) -Wl,DLL
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -Wl,DLL
"""
# Header of toplevel Makefile.
# This should go into the build tree, but it's easier to keep it here for now.
SHARED_HEADER = ("""\
@@ -290,7 +315,7 @@ CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
CXX.host ?= %(CXX.host)s
CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
LINK.host ?= %(LINK.host)s
LDFLAGS.host ?=
LDFLAGS.host ?= $(LDFLAGS_host)
AR.host ?= %(AR.host)s
# Define a dir function that can handle spaces.
@@ -310,7 +335,7 @@ dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
# We write to a dep file on the side first and then rename at the end
# so we can't end up with a broken dep file.
depfile = $(depsdir)/$(call replace_spaces,$@).d
DEPFLAGS = -MMD -MF $(depfile).raw
DEPFLAGS = %(makedep_args)s -MF $(depfile).raw
# We have to fixup the deps output in a few ways.
# (1) the file output should mention the proper .o file.
@@ -499,7 +524,7 @@ cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES)
def WriteRootHeaderSuffixRules(writer):
extensions = sorted(list(COMPILABLE_EXTENSIONS.keys()), key=str.lower)
extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
writer.write('# Suffix rules, putting all outputs into $(obj).\n')
for ext in extensions:
@@ -650,9 +675,9 @@ def _ValidateSourcesForOSX(spec, all_sources):
error += ' %s: %s\n' % (basename, ' '.join(files))
if error:
print(('static library %s has several files with the same basename:\n' %
print('static library %s has several files with the same basename:\n' %
spec['target_name'] + error + 'libtool on OS X will generate' +
' warnings for them.'))
' warnings for them.')
raise GypError('Duplicate basenames in sources section, see list above')
@@ -680,7 +705,7 @@ class MakefileWriter(object):
self.suffix_rules_objdir2 = {}
# Generate suffix rules for all compilable extensions.
for ext in list(COMPILABLE_EXTENSIONS.keys()):
for ext in COMPILABLE_EXTENSIONS.keys():
# Suffix rules for source folder.
self.suffix_rules_srcdir.update({ext: ("""\
$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD
@@ -793,7 +818,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
gyp.xcode_emulation.MacPrefixHeader(
self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)),
self.Pchify))
sources = list(filter(Compilable, all_sources))
sources = [x for x in all_sources if Compilable(x)]
if sources:
self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
extensions = set([os.path.splitext(s)[1] for s in sources])
@@ -922,7 +947,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
'%s%s'
% (name, cd_action, command))
self.WriteLn()
outputs = list(map(self.Absolutify, outputs))
outputs = [self.Absolutify(o) for o in outputs]
# The makefile rules are all relative to the top dir, but the gyp actions
# are defined relative to their containing dir. This replaces the obj
# variable for the action rule with an absolute version so that the output
@@ -946,7 +971,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
self.WriteDoCmd(outputs, list(map(Sourceify, list(map(self.Absolutify, inputs)))),
self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
part_of_all=part_of_all, command=name)
# Stuff the outputs in a variable so we can refer to them later.
@@ -995,8 +1020,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
extra_sources += outputs
if int(rule.get('process_outputs_as_mac_bundle_resources', False)):
extra_mac_bundle_resources += outputs
inputs = list(map(Sourceify, list(map(self.Absolutify, [rule_source] +
rule.get('inputs', [])))))
inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
rule.get('inputs', [])))
actions = ['$(call do_cmd,%s_%d)' % (name, count)]
if name == 'resources_grit':
@@ -1012,7 +1037,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
outputs = list(map(self.Absolutify, outputs))
outputs = [self.Absolutify(o) for o in outputs]
all_outputs += outputs
# Only write the 'obj' and 'builddir' rules for the "primary" output
# (:1); it's superfluous for the "extra outputs", and this avoids
@@ -1130,7 +1155,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
for output, res in gyp.xcode_emulation.GetMacBundleResources(
generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
list(map(Sourceify, list(map(self.Absolutify, resources))))):
map(Sourceify, map(self.Absolutify, resources))):
_, ext = os.path.splitext(output)
if ext != '.xcassets':
# Make does not supports '.xcassets' emulation.
@@ -1210,11 +1235,11 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname)
includes = config.get('include_dirs')
if includes:
includes = list(map(Sourceify, list(map(self.Absolutify, includes))))
includes = [Sourceify(self.Absolutify(include)) for include in includes]
self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
compilable = list(filter(Compilable, sources))
objs = list(map(self.Objectify, list(map(self.Absolutify, list(map(Target, compilable))))))
compilable = filter(Compilable, sources)
objs = [self.Objectify(self.Absolutify(Target(x))) for x in compilable]
self.WriteList(objs, 'OBJS')
for obj in objs:
@@ -1286,7 +1311,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
# If there are any object files in our input file list, link them into our
# output.
extra_link_deps += list(filter(Linkable, sources))
extra_link_deps += [source for source in sources if Linkable(source)]
self.WriteLn()
@@ -1347,7 +1372,10 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
if target[:3] == 'lib':
target = target[3:]
target_prefix = 'lib'
target_ext = '.so'
if self.flavor == 'aix':
target_ext = '.a'
else:
target_ext = '.so'
elif self.type == 'none':
target = '%s.stamp' % target
elif self.type != 'executable':
@@ -1516,9 +1544,9 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
# Postbuilds expect to be run in the gyp file's directory, so insert an
# implicit postbuild to cd to there.
postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path]))
for i in range(len(postbuilds)):
if not postbuilds[i].startswith('$'):
postbuilds[i] = EscapeShellArgument(postbuilds[i])
for i, postbuild in enumerate(postbuilds):
if not postbuild.startswith('$'):
postbuilds[i] = EscapeShellArgument(postbuild)
self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output))
self.WriteLn('%s: POSTBUILDS := %s' % (
QuoteSpaces(self.output), ' '.join(postbuilds)))
@@ -1533,7 +1561,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
# Bundle dependencies. Note that the code below adds actions to this
# target, so if you move these two lines, move the lines below as well.
self.WriteList(list(map(QuoteSpaces, bundle_deps)), 'BUNDLE_DEPS')
self.WriteList(map(QuoteSpaces, bundle_deps), 'BUNDLE_DEPS')
self.WriteLn('%s: $(BUNDLE_DEPS)' % QuoteSpaces(self.output))
# After the framework is built, package it. Needs to happen before
@@ -1608,7 +1636,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all,
postbuilds=postbuilds)
else:
print("WARNING: no output for", self.type, target)
print("WARNING: no output for", self.type, self.target)
# Add an alias for each target (if there are any outputs).
# Installable target aliases are created below.
@@ -1715,8 +1743,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
output is just a name to run the rule
command: (optional) command name to generate unambiguous labels
"""
outputs = list(map(QuoteSpaces, outputs))
inputs = list(map(QuoteSpaces, inputs))
outputs = [QuoteSpaces(o) for o in outputs]
inputs = map(QuoteSpaces, inputs)
if comment:
self.WriteLn('# ' + comment)
@@ -1743,7 +1771,11 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
# actual command.
# - The intermediate recipe will 'touch' the intermediate file.
# - The multi-output rule will have an do-nothing recipe.
intermediate = "%s.intermediate" % (command if command else self.target)
# Hash the target name to avoid generating overlong filenames.
cmdstring = (command if command else self.target).encode('utf-8')
cmddigest = hashlib.sha1(cmdstring).hexdigest()
intermediate = "%s.intermediate" % (cmddigest)
self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
self.WriteLn('\t%s' % '@:');
self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
@@ -1802,7 +1834,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
default_cpp_ext = ext
self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext)
self.WriteList(list(map(self.Absolutify, list(filter(Compilable, all_sources)))),
self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)),
'LOCAL_SRC_FILES')
# Filter out those which do not match prefix and suffix and produce
@@ -2011,6 +2043,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
flock_command= 'flock'
copy_archive_arguments = '-af'
makedep_arguments = '-MMD'
header_params = {
'default_target': default_target,
'builddir': builddir_name,
@@ -2021,6 +2054,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
'extra_commands': '',
'srcdir': srcdir,
'copy_archive_args': copy_archive_arguments,
'makedep_args': makedep_arguments,
}
if flavor == 'mac':
flock_command = './gyp-mac-tool flock'
@@ -2034,6 +2068,14 @@ def GenerateOutput(target_list, target_dicts, data, params):
header_params.update({
'link_commands': LINK_COMMANDS_ANDROID,
})
elif flavor == 'zos':
copy_archive_arguments = '-fPR'
makedep_arguments = '-qmakedep=gcc'
header_params.update({
'copy_archive_args': copy_archive_arguments,
'makedep_args': makedep_arguments,
'link_commands': LINK_COMMANDS_OS390,
})
elif flavor == 'solaris':
header_params.update({
'flock': './gyp-flock-tool flock',
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
import copy
import ntpath
import os
@@ -9,6 +11,7 @@ import posixpath
import re
import subprocess
import sys
import collections
import gyp.common
import gyp.easy_xml as easy_xml
@@ -23,16 +26,6 @@ import gyp.MSVSVersion as MSVSVersion
from gyp.common import GypError
from gyp.common import OrderedSet
# TODO: Remove once bots are on 2.7, http://crbug.com/241769
def _import_OrderedDict():
import collections
try:
return collections.OrderedDict
except AttributeError:
import gyp.ordered_dict
return gyp.ordered_dict.OrderedDict
OrderedDict = _import_OrderedDict()
# Regular expression for validating Visual Studio GUIDs. If the GUID
# contains lowercase hex letters, MSVS will be fine. However,
@@ -202,7 +195,7 @@ def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None,
if not prefix: prefix = []
result = []
excluded_result = []
folders = OrderedDict()
folders = collections.OrderedDict()
# Gather files into the final result, excluded, or folders.
for s in sources:
if len(s) == 1:
@@ -294,19 +287,29 @@ def _ConfigFullName(config_name, config_data):
return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
def _ConfigWindowsTargetPlatformVersion(config_data):
ver = config_data.get('msvs_windows_sdk_version')
for key in [r'HKLM\Software\Microsoft\Microsoft SDKs\Windows\%s',
r'HKLM\Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows\%s']:
sdk_dir = MSVSVersion._RegistryGetValue(key % ver, 'InstallationFolder')
if not sdk_dir:
continue
version = MSVSVersion._RegistryGetValue(key % ver, 'ProductVersion') or ''
# Find a matching entry in sdk_dir\include.
names = sorted([x for x in os.listdir(r'%s\include' % sdk_dir)
if x.startswith(version)], reverse=True)
return names[0]
def _ConfigWindowsTargetPlatformVersion(config_data, version):
config_ver = config_data.get('msvs_windows_sdk_version')
vers = [config_ver] if config_ver else version.compatible_sdks
for ver in vers:
for key in [
r'HKLM\Software\Microsoft\Microsoft SDKs\Windows\%s',
r'HKLM\Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows\%s']:
sdk_dir = MSVSVersion._RegistryGetValue(key % ver, 'InstallationFolder')
if not sdk_dir:
continue
version = MSVSVersion._RegistryGetValue(key % ver, 'ProductVersion') or ''
# Find a matching entry in sdk_dir\include.
expected_sdk_dir=r'%s\include' % sdk_dir
names = sorted([x for x in (os.listdir(expected_sdk_dir)
if os.path.isdir(expected_sdk_dir)
else []
)
if x.startswith(version)], reverse=True)
if names:
return names[0]
else:
print('Warning: No include files found for '
'detected Windows SDK version %s' % (version))
def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
@@ -878,7 +881,7 @@ def _FilterActionsFromExcluded(excluded_sources, actions_to_add):
Returns:
excluded_sources with files that have actions attached removed.
"""
must_keep = OrderedSet(_FixPaths(list(actions_to_add.keys())))
must_keep = OrderedSet(_FixPaths(actions_to_add.keys()))
return [s for s in excluded_sources if s not in must_keep]
@@ -984,8 +987,8 @@ def _ValidateSourcesForMSVSProject(spec, version):
error += ' %s: %s\n' % (basename, ' '.join(files))
if error:
print(('static library %s has several files with the same basename:\n' %
spec['target_name'] + error + 'MSVC08 cannot handle that.'))
print('static library %s has several files with the same basename:\n' %
spec['target_name'] + error + 'MSVC08 cannot handle that.')
raise GypError('Duplicate basenames in sources section, see list above')
@@ -1715,14 +1718,17 @@ def _GetCopies(spec):
src_bare = src[:-1]
base_dir = posixpath.split(src_bare)[0]
outer_dir = posixpath.split(src_bare)[1]
cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % (
_FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir)
fixed_dst = _FixPath(dst)
full_dst = '"%s\\%s\\"' % (fixed_dst, outer_dir)
cmd = 'mkdir %s 2>nul & cd "%s" && xcopy /e /f /y "%s" %s' % (
full_dst, _FixPath(base_dir), outer_dir, full_dst)
copies.append(([src], ['dummy_copies', dst], cmd,
'Copying %s to %s' % (src, dst)))
'Copying %s to %s' % (src, fixed_dst)))
else:
fix_dst = _FixPath(cpy['destination'])
cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % (
_FixPath(cpy['destination']), _FixPath(src), _FixPath(dst))
copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst)))
fix_dst, _FixPath(src), _FixPath(dst))
copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, fix_dst)))
return copies
@@ -1763,8 +1769,8 @@ def _CollapseSingles(parent, node):
# such projects up one level.
if (type(node) == dict and
len(node) == 1 and
list(node.keys())[0] == parent + '.vcproj'):
return node[list(node.keys())[0]]
next(iter(node)) == parent + '.vcproj'):
return node[next(iter(node))]
if type(node) != dict:
return node
for child in node:
@@ -1783,8 +1789,8 @@ def _GatherSolutionFolders(sln_projects, project_objects, flat):
# Walk down from the top until we hit a folder that has more than one entry.
# In practice, this strips the top-level "src/" dir from the hierarchy in
# the solution.
while len(root) == 1 and type(root[list(root.keys())[0]]) == dict:
root = root[list(root.keys())[0]]
while len(root) == 1 and type(root[next(iter(root))]) == dict:
root = root[next(iter(root))]
# Collapse singles.
root = _CollapseSingles('', root)
# Merge buckets until everything is a root entry.
@@ -1863,7 +1869,7 @@ def _CreateProjectObjects(target_list, target_dicts, options, msvs_version):
projects[qualified_target] = obj
# Set all the dependencies, but not if we are using an external builder like
# ninja
for project in list(projects.values()):
for project in projects.values():
if not project.spec.get('msvs_external_builder'):
deps = project.spec.get('dependencies', [])
deps = [projects[d] for d in deps]
@@ -2024,7 +2030,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
# Generate each project.
missing_sources = []
for project in list(project_objects.values()):
for project in project_objects.values():
fixpath_prefix = project.fixpath_prefix
missing_sources.extend(_GenerateProject(project, options, msvs_version,
generator_flags))
@@ -2057,7 +2063,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
if generator_flags.get('msvs_error_on_missing_sources', False):
raise GypError(error_message)
else:
print("Warning: " + error_message, file=sys.stdout)
print("Warning: " + error_message)
def _GenerateMSBuildFiltersFile(filters_path, source_files,
@@ -2664,7 +2670,7 @@ def _GetMSBuildProjectConfigurations(configurations):
return [group]
def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
def _GetMSBuildGlobalProperties(spec, version, guid, gyp_file_name):
namespace = os.path.splitext(gyp_file_name)[0]
properties = [
['PropertyGroup', {'Label': 'Globals'},
@@ -2679,6 +2685,18 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64':
properties[0].append(['PreferredToolArchitecture', 'x64'])
if spec.get('msvs_target_platform_version'):
target_platform_version = spec.get('msvs_target_platform_version')
properties[0].append(['WindowsTargetPlatformVersion',
target_platform_version])
if spec.get('msvs_target_platform_minversion'):
target_platform_minversion = spec.get('msvs_target_platform_minversion')
properties[0].append(['WindowsTargetPlatformMinVersion',
target_platform_minversion])
else:
properties[0].append(['WindowsTargetPlatformMinVersion',
target_platform_version])
if spec.get('msvs_enable_winrt'):
properties[0].append(['DefaultLanguage', 'en-US'])
properties[0].append(['AppContainerApplication', 'true'])
@@ -2687,18 +2705,6 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
properties[0].append(['ApplicationTypeRevision', app_type_revision])
else:
properties[0].append(['ApplicationTypeRevision', '8.1'])
if spec.get('msvs_target_platform_version'):
target_platform_version = spec.get('msvs_target_platform_version')
properties[0].append(['WindowsTargetPlatformVersion',
target_platform_version])
if spec.get('msvs_target_platform_minversion'):
target_platform_minversion = spec.get('msvs_target_platform_minversion')
properties[0].append(['WindowsTargetPlatformMinVersion',
target_platform_minversion])
else:
properties[0].append(['WindowsTargetPlatformMinVersion',
target_platform_version])
if spec.get('msvs_enable_winphone'):
properties[0].append(['ApplicationType', 'Windows Phone'])
else:
@@ -2709,15 +2715,18 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
for configuration in spec['configurations'].values():
platform_name = platform_name or _ConfigPlatform(configuration)
msvs_windows_sdk_version = (msvs_windows_sdk_version or
_ConfigWindowsTargetPlatformVersion(configuration))
_ConfigWindowsTargetPlatformVersion(configuration, version))
if platform_name and msvs_windows_sdk_version:
break
if platform_name == 'ARM':
properties[0].append(['WindowsSDKDesktopARMSupport', 'true'])
if msvs_windows_sdk_version:
properties[0].append(['WindowsTargetPlatformVersion',
str(msvs_windows_sdk_version)])
elif version.compatible_sdks:
raise GypError('%s requires any SDK of %s version, but none were found' %
(version.description, version.compatible_sdks))
if platform_name == 'ARM':
properties[0].append(['WindowsSDKDesktopARMSupport', 'true'])
return properties
@@ -2731,6 +2740,10 @@ def _GetMSBuildConfigurationDetails(spec, build_file):
config_type = msbuild_attributes.get('ConfigurationType')
_AddConditionalProperty(properties, condition, 'ConfigurationType',
config_type)
spectre_mitigation = msbuild_attributes.get('SpectreMitigation')
if spectre_mitigation:
_AddConditionalProperty(properties, condition, 'SpectreMitigation',
spectre_mitigation)
if config_type == 'Driver':
_AddConditionalProperty(properties, condition, 'DriverType', 'WDM')
_AddConditionalProperty(properties, condition, 'TargetVersion',
@@ -2812,6 +2825,8 @@ def _ConvertMSVSBuildAttributes(spec, config, build_file):
msbuild_attributes[a] = _ConvertMSVSCharacterSet(msvs_attributes[a])
elif a == 'ConfigurationType':
msbuild_attributes[a] = _ConvertMSVSConfigurationType(msvs_attributes[a])
elif a == 'SpectreMitigation':
msbuild_attributes[a] = msvs_attributes[a]
else:
print('Warning: Do not know how to convert MSVS attribute ' + a)
return msbuild_attributes
@@ -2862,6 +2877,9 @@ def _GetMSBuildAttributes(spec, config, build_file):
product_name = spec.get('product_name', '$(ProjectName)')
target_name = prefix + product_name
msbuild_attributes['TargetName'] = target_name
if 'TargetExt' not in msbuild_attributes and 'product_extension' in spec:
ext = spec.get('product_extension')
msbuild_attributes['TargetExt'] = '.' + ext
if spec.get('msvs_external_builder'):
external_out_dir = spec.get('msvs_external_builder_out_dir', '.')
@@ -2916,6 +2934,9 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
attributes['OutputDirectory'])
_AddConditionalProperty(properties, condition, 'TargetName',
attributes['TargetName'])
if 'TargetExt' in attributes:
_AddConditionalProperty(properties, condition, 'TargetExt',
attributes['TargetExt'])
if attributes.get('TargetPath'):
_AddConditionalProperty(properties, condition, 'TargetPath',
@@ -2990,7 +3011,7 @@ def _GetMSBuildPropertyGroup(spec, label, properties):
if v in properties and v != node]))
return edges
properties_ordered = gyp.common.TopologicallySorted(
list(properties.keys()), GetEdges)
properties.keys(), GetEdges)
# Walk properties in the reverse of a topological sort on
# user_of_variable -> used_variable as this ensures variables are
# defined before they are used.
@@ -3054,8 +3075,8 @@ def _FinalizeMSBuildSettings(spec, configuration):
for ignored_setting in ignored_settings:
value = configuration.get(ignored_setting)
if value:
print(('Warning: The automatic conversion to MSBuild does not handle '
'%s. Ignoring setting of %s' % (ignored_setting, str(value))))
print('Warning: The automatic conversion to MSBuild does not handle '
'%s. Ignoring setting of %s' % (ignored_setting, str(value)))
defines = [_EscapeCppDefineForMSBuild(d) for d in defines]
disabled_warnings = _GetDisabledWarnings(configuration)
@@ -3268,6 +3289,9 @@ def _GetMSBuildProjectReferences(project):
['ReferenceOutputAssembly', 'false']
]
for config in dependency.spec.get('configurations', {}).values():
if config.get('msvs_use_library_dependency_inputs', 0):
project_ref.append(['UseLibraryDependencyInputs', 'true'])
break
# If it's disabled in any config, turn it off in the reference.
if config.get('msvs_2010_disable_uldi_when_referenced', 0):
project_ref.append(['UseLibraryDependencyInputs', 'false'])
@@ -3360,7 +3384,8 @@ def _GenerateMSBuildProject(project, options, version, generator_flags):
}]
content += _GetMSBuildProjectConfigurations(configurations)
content += _GetMSBuildGlobalProperties(spec, project.guid, project_file_name)
content += _GetMSBuildGlobalProperties(spec, version, project.guid,
project_file_name)
content += import_default_section
content += _GetMSBuildConfigurationDetails(spec, project.build_file)
if spec.get('msvs_enable_winphone'):
@@ -7,13 +7,16 @@
import gyp.generator.msvs as msvs
import unittest
import io
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.stderr = io.StringIO()
self.stderr = StringIO()
def test_GetLibraries(self):
self.assertEqual(
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
import collections
import copy
import hashlib
@@ -12,13 +14,17 @@ import re
import signal
import subprocess
import sys
import six
import gyp
import gyp.common
from gyp.common import OrderedSet
import gyp.msvs_emulation
import gyp.MSVSUtil as MSVSUtil
import gyp.xcode_emulation
from io import StringIO
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
from gyp.common import GetEnvironFallback
import gyp.ninja_syntax as ninja_syntax
@@ -350,7 +356,7 @@ class NinjaWriter(object):
Uses a stamp file if necessary."""
assert targets == [_f for _f in targets if _f], targets
assert targets == [t for t in targets if t], targets
if len(targets) == 0:
assert not order_only
return None
@@ -427,8 +433,8 @@ class NinjaWriter(object):
compile_depends.append(target.PreCompileInput())
if target.uses_cpp:
self.target.uses_cpp = True
actions_depends = [_f for _f in actions_depends if _f]
compile_depends = [_f for _f in compile_depends if _f]
actions_depends = [d for d in actions_depends if d]
compile_depends = [d for d in compile_depends if d]
actions_depends = self.WriteCollapsedDependencies('actions_depends',
actions_depends)
compile_depends = self.WriteCollapsedDependencies('compile_depends',
@@ -486,7 +492,8 @@ class NinjaWriter(object):
link_deps += [self.GypPathToNinja(o) for o in obj_outputs]
else:
print("Warning: Actions/rules writing object files don't work with " \
"multiarch targets, dropping. (target %s)" % spec['target_name'])
"multiarch targets, dropping. (target %s)" %
spec['target_name'])
elif self.flavor == 'mac' and len(self.archs) > 1:
link_deps = collections.defaultdict(list)
@@ -544,7 +551,7 @@ class NinjaWriter(object):
if self.msvs_settings.HasExplicitIdlRulesOrActions(spec):
return []
outputs = []
for source in [x for x in spec['sources'] if x.endswith('.idl')]:
for source in filter(lambda x: x.endswith('.idl'), spec['sources']):
self._WinIdlRule(source, prebuild, outputs)
return outputs
@@ -615,7 +622,7 @@ class NinjaWriter(object):
args = action['action']
depfile = action.get('depfile', None)
if depfile:
depfile = self.ExpandSpecial(depfile, self.base_to_build)
depfile = self.ExpandSpecial(depfile)
pool = 'console' if int(action.get('ninja_use_console', 0)) else None
rule_name, _ = self.WriteNewNinjaRule(name, args, description,
is_cygwin, env, pool,
@@ -745,7 +752,7 @@ class NinjaWriter(object):
if self.flavor == 'win':
# WriteNewNinjaRule uses unique_name for creating an rsp file on win.
extra_bindings.append(('unique_name',
hashlib.md5(outputs[0]).hexdigest()))
hashlib.md5(six.ensure_binary(outputs[0])).hexdigest()))
self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
implicit=inputs,
@@ -791,10 +798,10 @@ class NinjaWriter(object):
copy_headers = spec['mac_framework_headers']
output = self.GypPathToUniqueOutput('headers.hmap')
self.xcode_settings.header_map_path = output
all_headers = list(map(self.GypPathToNinja,
[x for x in all_sources if x.endswith(('.h'))]))
all_headers = map(self.GypPathToNinja,
filter(lambda x:x.endswith(('.h')), all_sources))
variables = [('framework', framework),
('copy_headers', list(map(self.GypPathToNinja, copy_headers)))]
('copy_headers', map(self.GypPathToNinja, copy_headers))]
outputs.extend(self.ninja.build(
output, 'compile_ios_framework_headers', all_headers,
variables=variables, order_only=prebuild))
@@ -810,7 +817,7 @@ class NinjaWriter(object):
for output, res in gyp.xcode_emulation.GetMacBundleResources(
generator_default_variables['PRODUCT_DIR'],
self.xcode_settings, list(map(self.GypPathToNinja, resources))):
self.xcode_settings, map(self.GypPathToNinja, resources)):
output = self.ExpandSpecial(output)
if os.path.splitext(output)[-1] != '.xcassets':
self.ninja.build(output, 'mac_tool', res,
@@ -978,7 +985,7 @@ class NinjaWriter(object):
[Define(d, self.flavor) for d in defines])
if self.flavor == 'win':
self.WriteVariableList(ninja_file, 'asmflags',
list(map(self.ExpandSpecial, asmflags)))
map(self.ExpandSpecial, asmflags))
self.WriteVariableList(ninja_file, 'rcflags',
[QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
for f in self.msvs_settings.GetRcflags(config_name,
@@ -1013,18 +1020,18 @@ class NinjaWriter(object):
arflags = config.get('arflags', [])
self.WriteVariableList(ninja_file, 'cflags',
list(map(self.ExpandSpecial, cflags)))
map(self.ExpandSpecial, cflags))
self.WriteVariableList(ninja_file, 'cflags_c',
list(map(self.ExpandSpecial, cflags_c)))
map(self.ExpandSpecial, cflags_c))
self.WriteVariableList(ninja_file, 'cflags_cc',
list(map(self.ExpandSpecial, cflags_cc)))
map(self.ExpandSpecial, cflags_cc))
if self.flavor == 'mac':
self.WriteVariableList(ninja_file, 'cflags_objc',
list(map(self.ExpandSpecial, cflags_objc)))
map(self.ExpandSpecial, cflags_objc))
self.WriteVariableList(ninja_file, 'cflags_objcc',
list(map(self.ExpandSpecial, cflags_objcc)))
map(self.ExpandSpecial, cflags_objcc))
self.WriteVariableList(ninja_file, 'arflags',
list(map(self.ExpandSpecial, arflags)))
map(self.ExpandSpecial, arflags))
ninja_file.newline()
outputs = []
has_rc_source = False
@@ -1195,7 +1202,10 @@ class NinjaWriter(object):
is_executable = spec['type'] == 'executable'
# The ldflags config key is not used on mac or win. On those platforms
# linker flags are set via xcode_settings and msvs_settings, respectively.
env_ldflags = os.environ.get('LDFLAGS', '').split()
if self.toolset == 'target':
env_ldflags = os.environ.get('LDFLAGS', '').split()
elif self.toolset == 'host':
env_ldflags = os.environ.get('LDFLAGS_host', '').split()
if self.flavor == 'mac':
ldflags = self.xcode_settings.GetLdflags(config_name,
self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
@@ -1233,7 +1243,7 @@ class NinjaWriter(object):
ldflags.append('-Wl,-rpath=%s' % self.target_rpath)
ldflags.append('-Wl,-rpath-link=%s' % rpath)
self.WriteVariableList(ninja_file, 'ldflags',
list(map(self.ExpandSpecial, ldflags)))
map(self.ExpandSpecial, ldflags))
library_dirs = config.get('library_dirs', [])
if self.flavor == 'win':
@@ -1247,8 +1257,8 @@ class NinjaWriter(object):
self.flavor)
for l in library_dirs]
libraries = gyp.common.uniquer(list(map(self.ExpandSpecial,
spec.get('libraries', []))))
libraries = gyp.common.uniquer(map(self.ExpandSpecial,
spec.get('libraries', [])))
if self.flavor == 'mac':
libraries = self.xcode_settings.AdjustLibraries(libraries, config_name)
elif self.flavor == 'win':
@@ -1769,7 +1779,7 @@ def GetDefaultConcurrentLinks():
# VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
# on a 64 GB machine.
mem_limit = max(1, stat.ullTotalPhys / (5 * (2 ** 30))) # total / 5GB
mem_limit = max(1, stat.ullTotalPhys // (5 * (2 ** 30))) # total / 5GB
hard_cap = max(1, int(os.environ.get('GYP_LINK_CONCURRENCY_MAX', 2**32)))
return min(mem_limit, hard_cap)
elif sys.platform.startswith('linux'):
@@ -1781,14 +1791,14 @@ def GetDefaultConcurrentLinks():
if not match:
continue
# Allow 8Gb per link on Linux because Gold is quite memory hungry
return max(1, int(match.group(1)) / (8 * (2 ** 20)))
return max(1, int(match.group(1)) // (8 * (2 ** 20)))
return 1
elif sys.platform == 'darwin':
try:
avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
# A static library debug build of Chromium's unit_tests takes ~2.7GB, so
# 4GB per ld process allows for some more bloat.
return max(1, avail_bytes / (4 * (2 ** 30))) # total / 4GB
return max(1, avail_bytes // (4 * (2 ** 30))) # total / 4GB
except:
return 1
else:
@@ -2311,15 +2321,22 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'stamp',
description='STAMP $out',
command='%s gyp-win-tool stamp $out' % sys.executable)
master_ninja.rule(
'copy',
description='COPY $in $out',
command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable)
else:
master_ninja.rule(
'stamp',
description='STAMP $out',
command='${postbuilds}touch $out')
if flavor == 'win':
master_ninja.rule(
'copy',
description='COPY $in $out',
command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable)
elif flavor == 'zos':
master_ninja.rule(
'copy',
description='COPY $in $out',
command='rm -rf $out && cp -fRP $in $out')
else:
master_ninja.rule(
'copy',
description='COPY $in $out',
@@ -2371,6 +2388,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
qualified_target_for_hash = gyp.common.QualifiedTarget(build_file, name,
toolset)
qualified_target_for_hash = qualified_target_for_hash.encode('utf-8')
hash_for_rules = hashlib.md5(qualified_target_for_hash).hexdigest()
base_path = os.path.dirname(build_file)
@@ -2465,7 +2483,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
GenerateOutputForConfig(target_list, target_dicts, data, params,
user_config)
else:
config_names = list(target_dicts[target_list[0]]['configurations'].keys())
config_names = target_dicts[target_list[0]]['configurations']
if params['parallel']:
try:
pool = multiprocessing.Pool(len(config_names))
@@ -8,7 +8,6 @@
import gyp.generator.ninja as ninja
import unittest
import io
import sys
import TestCommon
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
import filecmp
import gyp.common
import gyp.xcodeproj_file
@@ -408,7 +410,7 @@ sys.exit(subprocess.call(sys.argv[1:]))" """
# it opens the project file, which will result in unnecessary diffs.
# TODO(mark): This is evil because it relies on internal knowledge of
# PBXProject._other_pbxprojects.
for other_pbxproject in list(self.project._other_pbxprojects.keys()):
for other_pbxproject in self.project._other_pbxprojects.keys():
self.project.AddOrGetProjectReference(other_pbxproject)
self.project.SortRemoteProductReferences()
@@ -444,7 +446,7 @@ sys.exit(subprocess.call(sys.argv[1:]))" """
dir=self.path)
try:
output_file = os.fdopen(output_fd, 'wb')
output_file = os.fdopen(output_fd, 'w')
self.project_file.Print(output_file)
output_file.close()
@@ -497,7 +499,7 @@ def AddSourceToTarget(source, type, pbxp, xct):
# of "sources" as things to compile and "libraries" (or "frameworks") as
# things to link with. Adding an object file to an Xcode target's frameworks
# phase works properly.
library_extensions = ['a', 'dylib', 'framework', 'o']
library_extensions = ['a', 'dylib', 'framework', 'xcframework', 'o']
basename = posixpath.basename(source)
(root, ext) = posixpath.splitext(basename)
@@ -710,7 +712,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
type = spec['type']
is_xctest = int(spec.get('mac_xctest_bundle', 0))
is_xcuitest = int(spec.get('mac_xcuitest_bundle', 0))
is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest
is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest or is_xcuitest
is_app_extension = int(spec.get('ios_app_extension', 0))
is_watchkit_extension = int(spec.get('ios_watchkit_extension', 0))
is_watch_app = int(spec.get('ios_watch_app', 0))
@@ -1016,22 +1018,21 @@ def GenerateOutput(target_list, target_dicts, data, params):
makefile_name)
# TODO(mark): try/close? Write to a temporary file and swap it only
# if it's got changes?
makefile = open(makefile_path, 'wb')
makefile = open(makefile_path, 'w')
# make will build the first target in the makefile by default. By
# convention, it's called "all". List all (or at least one)
# concrete output for each rule source as a prerequisite of the "all"
# target.
makefile.write('all: \\\n')
for concrete_output_index in \
range(0, len(concrete_outputs_by_rule_source)):
for concrete_output_index, concrete_output_by_rule_source in \
enumerate(concrete_outputs_by_rule_source):
# Only list the first (index [0]) concrete output of each input
# in the "all" target. Otherwise, a parallel make (-j > 1) would
# attempt to process each input multiple times simultaneously.
# Otherwise, "all" could just contain the entire list of
# concrete_outputs_all.
concrete_output = \
concrete_outputs_by_rule_source[concrete_output_index][0]
concrete_output = concrete_output_by_rule_source[0]
if concrete_output_index == len(concrete_outputs_by_rule_source) - 1:
eol = ''
else:
@@ -1047,8 +1048,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
# rule source. Collect the names of the directories that are
# required.
concrete_output_dirs = []
for concrete_output_index in range(0, len(concrete_outputs)):
concrete_output = concrete_outputs[concrete_output_index]
for concrete_output_index, concrete_output in \
enumerate(concrete_outputs):
if concrete_output_index == 0:
bol = ''
else:
@@ -1066,8 +1067,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
# the set of additional rule inputs, if any.
prerequisites = [rule_source]
prerequisites.extend(rule.get('inputs', []))
for prerequisite_index in range(0, len(prerequisites)):
prerequisite = prerequisites[prerequisite_index]
for prerequisite_index, prerequisite in enumerate(prerequisites):
if prerequisite_index == len(prerequisites) - 1:
eol = ''
else:
@@ -1094,17 +1094,6 @@ def GenerateOutput(target_list, target_dicts, data, params):
# work if there ever was a concrete output that had an input-dependent
# variable anywhere other than in the leaf position.
# Don't declare any inputPaths or outputPaths. If they're present,
# Xcode will provide a slight optimization by only running the script
# phase if any output is missing or outdated relative to any input.
# Unfortunately, it will also assume that all outputs are touched by
# the script, and if the outputs serve as files in a compilation
# phase, they will be unconditionally rebuilt. Since make might not
# rebuild everything that could be declared here as an output, this
# extra compilation activity is unnecessary. With inputPaths and
# outputPaths not supplied, make will always be called, but it knows
# enough to not do anything when everything is up-to-date.
# To help speed things up, pass -j COUNT to make so it does some work
# in parallel. Don't use ncpus because Xcode will build ncpus targets
# in parallel and if each target happens to have a rules step, there
@@ -1120,7 +1109,9 @@ exec xcrun make -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}"
exit 1
""" % makefile_name
ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
'inputPaths': rule['rule_sources'],
'name': 'Rule "' + rule['rule_name'] + '"',
'outputPaths': concrete_outputs_all,
'shellScript': script,
'showEnvVarsInLog': 0,
})
+89 -78
View File
@@ -2,14 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from compiler.ast import Const
from compiler.ast import Dict
from compiler.ast import Discard
from compiler.ast import List
from compiler.ast import Module
from compiler.ast import Node
from compiler.ast import Stmt
import compiler
from __future__ import print_function
import ast
import gyp.common
import gyp.simple_copy
import multiprocessing
@@ -59,6 +54,23 @@ path_sections = set()
per_process_data = {}
per_process_aux_data = {}
try:
_str_types = (basestring,)
# There's no basestring in python3.
except NameError:
_str_types = (str,)
try:
_int_types = (int, long)
# There's no long in python3.
except NameError:
_int_types = (int,)
# Shortcuts as we use these combos a lot.
_str_int_types = _str_types + _int_types
_str_int_list_types = _str_int_types + (list,)
def IsPathSection(section):
# If section ends in one of the '=+?!' characters, it's applied to a section
# without the trailing characters. '/' is notably absent from this list,
@@ -90,11 +102,13 @@ def IsPathSection(section):
base_non_configuration_keys = [
# Sections that must exist inside targets and not configurations.
'actions',
'all_dependent_settings',
'configurations',
'copies',
'default_configuration',
'dependencies',
'dependencies_original',
'direct_dependent_settings',
'libraries',
'postbuilds',
'product_dir',
@@ -183,43 +197,38 @@ def CheckedEval(file_contents):
Note that this is slower than eval() is.
"""
ast = compiler.parse(file_contents)
assert isinstance(ast, Module)
c1 = ast.getChildren()
assert c1[0] is None
assert isinstance(c1[1], Stmt)
c2 = c1[1].getChildren()
assert isinstance(c2[0], Discard)
c3 = c2[0].getChildren()
assert len(c3) == 1
return CheckNode(c3[0], [])
syntax_tree = ast.parse(file_contents)
assert isinstance(syntax_tree, ast.Module)
c1 = syntax_tree.body
assert len(c1) == 1
c2 = c1[0]
assert isinstance(c2, ast.Expr)
return CheckNode(c2.value, [])
def CheckNode(node, keypath):
if isinstance(node, Dict):
c = node.getChildren()
if isinstance(node, ast.Dict):
dict = {}
for n in range(0, len(c), 2):
assert isinstance(c[n], Const)
key = c[n].getChildren()[0]
for key, value in zip(node.keys, node.values):
assert isinstance(key, ast.Str)
key = key.s
if key in dict:
raise GypError("Key '" + key + "' repeated at level " +
repr(len(keypath) + 1) + " with key path '" +
'.'.join(keypath) + "'")
kp = list(keypath) # Make a copy of the list for descending this node.
kp.append(key)
dict[key] = CheckNode(c[n + 1], kp)
dict[key] = CheckNode(value, kp)
return dict
elif isinstance(node, List):
c = node.getChildren()
elif isinstance(node, ast.List):
children = []
for index, child in enumerate(c):
for index, child in enumerate(node.elts):
kp = list(keypath) # Copy list.
kp.append(repr(index))
children.append(CheckNode(child, kp))
return children
elif isinstance(node, Const):
return node.getChildren()[0]
elif isinstance(node, ast.Str):
return node.s
else:
raise TypeError("Unknown AST node at key path '" + '.'.join(keypath) +
"': " + repr(node))
@@ -231,7 +240,7 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
return data[build_file_path]
if os.path.exists(build_file_path):
build_file_contents = open(build_file_path).read()
build_file_contents = open(build_file_path, 'rb').read().decode('utf-8')
else:
raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
@@ -648,7 +657,7 @@ def IsStrCanonicalInt(string):
The canonical form is such that str(int(string)) == string.
"""
if type(string) is str:
if isinstance(string, _str_types):
# This function is called a lot so for maximum performance, avoid
# involving regexps which would otherwise make the code much
# shorter. Regexps would need twice the time of this function.
@@ -909,15 +918,20 @@ def ExpandVariables(input, phase, variables, build_file):
raise GypError("%s while executing command '%s' in %s" %
(e, contents, build_file))
p_stdout, p_stderr = p.communicate('')
p_stdout, p_stderr = p.communicate(b'')
if p.wait() != 0 or p_stderr:
if isinstance(p_stderr, bytes):
p_stderr = p_stderr.decode('utf-8', 'replace')
sys.stderr.write(p_stderr)
# Simulate check_call behavior, since check_call only exists
# in python 2.5 and later.
raise GypError("Call to '%s' returned exit status %d while in %s." %
(contents, p.returncode, build_file))
replacement = p_stdout.rstrip()
if isinstance(p_stdout, bytes):
replacement = p_stdout.decode('utf-8').rstrip()
else:
replacement = p_stdout.rstrip()
cached_command_results[cache_key] = replacement
else:
@@ -947,7 +961,7 @@ def ExpandVariables(input, phase, variables, build_file):
if type(replacement) is list:
for item in replacement:
if not contents[-1] == '/' and type(item) not in (str, int):
if not contents[-1] == '/' and not isinstance(item, _str_int_types):
raise GypError('Variable ' + contents +
' must expand to a string or list of strings; ' +
'list contains a ' +
@@ -957,8 +971,8 @@ def ExpandVariables(input, phase, variables, build_file):
# with conditions sections.
ProcessVariablesAndConditionsInList(replacement, phase, variables,
build_file)
elif type(replacement) not in (str, int):
raise GypError('Variable ' + contents +
elif not isinstance(replacement, _str_int_types):
raise GypError('Variable ' + str(contents) +
' must expand to a string or list of strings; ' +
'found a ' + replacement.__class__.__name__)
@@ -1019,9 +1033,9 @@ def ExpandVariables(input, phase, variables, build_file):
# Convert all strings that are canonically-represented integers into integers.
if type(output) is list:
for index in range(0, len(output)):
if IsStrCanonicalInt(output[index]):
output[index] = int(output[index])
for index, outstr in enumerate(output):
if IsStrCanonicalInt(outstr):
output[index] = int(outstr)
elif IsStrCanonicalInt(output):
output = int(output)
@@ -1076,7 +1090,7 @@ def EvalSingleCondition(
# use a command expansion directly inside a condition.
cond_expr_expanded = ExpandVariables(cond_expr, phase, variables,
build_file)
if type(cond_expr_expanded) not in (str, int):
if not isinstance(cond_expr_expanded, _str_int_types):
raise ValueError(
'Variable expansion in this context permits str and int ' + \
'only, found ' + cond_expr_expanded.__class__.__name__)
@@ -1152,7 +1166,7 @@ def LoadAutomaticVariablesFromDict(variables, the_dict):
# Any keys with plain string values in the_dict become automatic variables.
# The variable name is the key name with a "_" character prepended.
for key, value in the_dict.items():
if type(value) in (str, int, list):
if isinstance(value, _str_int_list_types):
variables['_' + key] = value
@@ -1165,7 +1179,7 @@ def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
# (it could be a list or it could be parentless because it is a root dict),
# the_dict_key will be None.
for key, value in the_dict.get('variables', {}).items():
if type(value) not in (str, int, list):
if not isinstance(value, _str_int_list_types):
continue
if key.endswith('%'):
@@ -1218,9 +1232,9 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
for key, value in the_dict.items():
# Skip "variables", which was already processed if present.
if key != 'variables' and type(value) is str:
if key != 'variables' and isinstance(value, _str_types):
expanded = ExpandVariables(value, phase, variables, build_file)
if type(expanded) not in (str, int):
if not isinstance(expanded, _str_int_types):
raise ValueError(
'Variable expansion in this context permits str and int ' + \
'only, found ' + expanded.__class__.__name__ + ' for ' + key)
@@ -1277,7 +1291,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
for key, value in the_dict.items():
# Skip "variables" and string values, which were already processed if
# present.
if key == 'variables' or type(value) is str:
if key == 'variables' or isinstance(value, _str_types):
continue
if type(value) is dict:
# Pass a copy of the variables dict so that subdicts can't influence
@@ -1291,7 +1305,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
# copy is necessary here.
ProcessVariablesAndConditionsInList(value, phase, variables,
build_file)
elif type(value) is not int:
elif not isinstance(value, _int_types):
raise TypeError('Unknown type ' + value.__class__.__name__ + \
' for ' + key)
@@ -1308,9 +1322,9 @@ def ProcessVariablesAndConditionsInList(the_list, phase, variables,
ProcessVariablesAndConditionsInDict(item, phase, variables, build_file)
elif type(item) is list:
ProcessVariablesAndConditionsInList(item, phase, variables, build_file)
elif type(item) is str:
elif isinstance(item, _str_types):
expanded = ExpandVariables(item, phase, variables, build_file)
if type(expanded) in (str, int):
if isinstance(expanded, _str_int_types):
the_list[index] = expanded
elif type(expanded) is list:
the_list[index:index+1] = expanded
@@ -1324,7 +1338,7 @@ def ProcessVariablesAndConditionsInList(the_list, phase, variables,
'Variable expansion in this context permits strings and ' + \
'lists only, found ' + expanded.__class__.__name__ + ' at ' + \
index)
elif type(item) is not int:
elif not isinstance(item, _int_types):
raise TypeError('Unknown type ' + item.__class__.__name__ + \
' at index ' + index)
index = index + 1
@@ -1376,9 +1390,9 @@ def QualifyDependencies(targets):
toolset = target_dict['toolset']
for dependency_key in all_dependency_sections:
dependencies = target_dict.get(dependency_key, [])
for index in range(0, len(dependencies)):
for index, dep in enumerate(dependencies):
dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
target_build_file, dependencies[index], toolset)
target_build_file, dep, toolset)
if not multiple_toolsets:
# Ignore toolset specification in the dependency if it is specified.
dep_toolset = toolset
@@ -1825,7 +1839,7 @@ def BuildDependencyList(targets):
if not root_node.dependents:
# If all targets have dependencies, add the first target as a dependent
# of root_node so that the cycle can be discovered from root_node.
target = list(targets.keys())[0]
target = next(iter(targets))
target_node = dependency_nodes[target]
target_node.dependencies.append(root_node)
root_node.dependents.append(target_node)
@@ -1888,7 +1902,7 @@ def VerifyNoGYPFileCircularDependencies(targets):
if not root_node.dependents:
# If all files have dependencies, add the first file as a dependent
# of root_node so that the cycle can be discovered from root_node.
file_node = list(dependency_nodes.values())[0]
file_node = next(iter(dependency_nodes.values()))
file_node.dependencies.append(root_node)
root_node.dependents.append(file_node)
cycles = []
@@ -2059,14 +2073,14 @@ def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
hashable_to_set = set(x for x in to if is_hashable(x))
for item in fro:
singleton = False
if type(item) in (str, int):
if isinstance(item, _str_int_types):
# The cheap and easy case.
if is_paths:
to_item = MakePathRelative(to_file, fro_file, item)
else:
to_item = item
if not (type(item) is str and item.startswith('-')):
if not (isinstance(item, _str_types) and item.startswith('-')):
# Any string that doesn't begin with a "-" is a singleton - it can
# only appear once in a list, to be enforced by the list merge append
# or prepend.
@@ -2123,8 +2137,8 @@ def MergeDicts(to, fro, to_file, fro_file):
# modified.
if k in to:
bad_merge = False
if type(v) in (str, int):
if type(to[k]) not in (str, int):
if isinstance(v, _str_int_types):
if not isinstance(to[k], _str_int_types):
bad_merge = True
elif type(v) is not type(to[k]):
bad_merge = True
@@ -2134,7 +2148,7 @@ def MergeDicts(to, fro, to_file, fro_file):
'Attempt to merge dict value of type ' + v.__class__.__name__ + \
' into incompatible type ' + to[k].__class__.__name__ + \
' for key ' + k)
if type(v) in (str, int):
if isinstance(v, _str_int_types):
# Overwrite the existing value, if any. Cheap and easy.
is_path = IsPathSection(k)
if is_path:
@@ -2280,15 +2294,14 @@ def SetUpConfigurations(target, target_dict):
merged_configurations[configuration] = new_configuration_dict
# Put the new configurations back into the target dict as a configuration.
for configuration in list(merged_configurations.keys()):
for configuration in merged_configurations.keys():
target_dict['configurations'][configuration] = (
merged_configurations[configuration])
# Now drop all the abstract ones.
for configuration in list(target_dict['configurations'].keys()):
old_configuration_dict = target_dict['configurations'][configuration]
if old_configuration_dict.get('abstract'):
del target_dict['configurations'][configuration]
configs = target_dict['configurations']
target_dict['configurations'] = \
{k: v for k, v in configs.items() if not v.get('abstract')}
# Now that all of the target's configurations have been built, go through
# the target dict's keys and remove everything that's been moved into a
@@ -2306,9 +2319,9 @@ def SetUpConfigurations(target, target_dict):
del target_dict[key]
# Check the configurations to see if they contain invalid keys.
for configuration in list(target_dict['configurations'].keys()):
for configuration in target_dict['configurations'].keys():
configuration_dict = target_dict['configurations'][configuration]
for key in list(configuration_dict.keys()):
for key in configuration_dict.keys():
if key in invalid_configuration_keys:
raise GypError('%s not allowed in the %s configuration, found in '
'target %s' % (key, configuration, target))
@@ -2396,8 +2409,8 @@ def ProcessListFiltersInDict(name, the_dict):
exclude_key = list_key + '!'
if exclude_key in the_dict:
for exclude_item in the_dict[exclude_key]:
for index in range(0, len(the_list)):
if exclude_item == the_list[index]:
for index, list_item in enumerate(the_list):
if exclude_item == list_item:
# This item matches the exclude_item, so set its action to 0
# (exclude).
list_actions[index] = 0
@@ -2422,8 +2435,7 @@ def ProcessListFiltersInDict(name, the_dict):
raise ValueError('Unrecognized action ' + action + ' in ' + name + \
' key ' + regex_key)
for index in range(0, len(the_list)):
list_item = the_list[index]
for index, list_item in enumerate(the_list):
if list_actions[index] == action_value:
# Even if the regex matches, nothing will change so continue (regex
# searches are expensive).
@@ -2528,9 +2540,9 @@ def ValidateSourcesInTarget(target, target_dict, build_file,
error += ' %s: %s\n' % (basename, ' '.join(files))
if error:
print(('static library %s has several files with the same basename:\n' %
print('static library %s has several files with the same basename:\n' %
target + error + 'libtool on Mac cannot handle that. Use '
'--no-duplicate-basename-check to disable this validation.'))
'--no-duplicate-basename-check to disable this validation.')
raise GypError('Duplicate basenames in sources section, see list above')
@@ -2611,7 +2623,7 @@ def ValidateRunAsInTarget(target, target_dict, build_file):
"must be a list." %
(target_name, build_file))
working_directory = run_as.get('working_directory')
if working_directory and type(working_directory) is not str:
if working_directory and not isinstance(working_directory, _str_types):
raise GypError("The 'working_directory' for 'run_as' in target %s "
"in file %s should be a string." %
(target_name, build_file))
@@ -2645,8 +2657,8 @@ def TurnIntIntoStrInDict(the_dict):
"""
# Use items instead of iteritems because there's no need to try to look at
# reinserted keys and their associated values.
for k, v in list(the_dict.items()):
if type(v) is int:
for k, v in the_dict.items():
if isinstance(v, _int_types):
v = str(v)
the_dict[k] = v
elif type(v) is dict:
@@ -2654,7 +2666,7 @@ def TurnIntIntoStrInDict(the_dict):
elif type(v) is list:
TurnIntIntoStrInList(v)
if type(k) is int:
if isinstance(k, _int_types):
del the_dict[k]
the_dict[str(k)] = v
@@ -2662,9 +2674,8 @@ def TurnIntIntoStrInDict(the_dict):
def TurnIntIntoStrInList(the_list):
"""Given list the_list, recursively converts all integers into strings.
"""
for index in range(0, len(the_list)):
item = the_list[index]
if type(item) is int:
for index, item in enumerate(the_list):
if isinstance(item, _int_types):
the_list[index] = str(item)
elif type(item) is dict:
TurnIntIntoStrInDict(item)
@@ -23,7 +23,7 @@ class TestFindCycles(unittest.TestCase):
def test_no_cycle_empty_graph(self):
for label, node in self.nodes.items():
self.assertEqual([], node.FindCycles())
self.assertEquals([], node.FindCycles())
def test_no_cycle_line(self):
self._create_dependency(self.nodes['a'], self.nodes['b'])
@@ -31,7 +31,7 @@ class TestFindCycles(unittest.TestCase):
self._create_dependency(self.nodes['c'], self.nodes['d'])
for label, node in self.nodes.items():
self.assertEqual([], node.FindCycles())
self.assertEquals([], node.FindCycles())
def test_no_cycle_dag(self):
self._create_dependency(self.nodes['a'], self.nodes['b'])
@@ -39,21 +39,21 @@ class TestFindCycles(unittest.TestCase):
self._create_dependency(self.nodes['b'], self.nodes['c'])
for label, node in self.nodes.items():
self.assertEqual([], node.FindCycles())
self.assertEquals([], node.FindCycles())
def test_cycle_self_reference(self):
self._create_dependency(self.nodes['a'], self.nodes['a'])
self.assertEqual([[self.nodes['a'], self.nodes['a']]],
self.assertEquals([[self.nodes['a'], self.nodes['a']]],
self.nodes['a'].FindCycles())
def test_cycle_two_nodes(self):
self._create_dependency(self.nodes['a'], self.nodes['b'])
self._create_dependency(self.nodes['b'], self.nodes['a'])
self.assertEqual([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
self.assertEquals([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
self.nodes['a'].FindCycles())
self.assertEqual([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
self.assertEquals([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
self.nodes['b'].FindCycles())
def test_two_cycles(self):
@@ -68,7 +68,7 @@ class TestFindCycles(unittest.TestCase):
[self.nodes['a'], self.nodes['b'], self.nodes['a']] in cycles)
self.assertTrue(
[self.nodes['b'], self.nodes['c'], self.nodes['b']] in cycles)
self.assertEqual(2, len(cycles))
self.assertEquals(2, len(cycles))
def test_big_cycle(self):
self._create_dependency(self.nodes['a'], self.nodes['b'])
@@ -77,7 +77,7 @@ class TestFindCycles(unittest.TestCase):
self._create_dependency(self.nodes['d'], self.nodes['e'])
self._create_dependency(self.nodes['e'], self.nodes['a'])
self.assertEqual([[self.nodes['a'],
self.assertEquals([[self.nodes['a'],
self.nodes['b'],
self.nodes['c'],
self.nodes['d'],
@@ -8,6 +8,8 @@
These functions are executed via gyp-mac-tool when using the Makefile generator.
"""
from __future__ import print_function
import fcntl
import fnmatch
import glob
@@ -16,7 +18,6 @@ import os
import plistlib
import re
import shutil
import string
import struct
import subprocess
import sys
@@ -105,17 +106,22 @@ class MacTool(object):
ibtool_section_re = re.compile(r'/\*.*\*/')
ibtool_re = re.compile(r'.*note:.*is clipping its content')
ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
try:
stdout = subprocess.check_output(args)
except subprocess.CalledProcessError as e:
print(e.output)
raise
current_section_header = None
for line in ibtoolout.stdout:
if ibtool_section_re.match(line):
current_section_header = line
elif not ibtool_re.match(line):
for line in stdout.splitlines():
line_decoded = line.decode('utf-8')
if ibtool_section_re.match(line_decoded):
current_section_header = line_decoded
elif not ibtool_re.match(line_decoded):
if current_section_header:
sys.stdout.write(current_section_header)
print(current_section_header)
current_section_header = None
sys.stdout.write(line)
return ibtoolout.returncode
print(line_decoded)
return 0
def _ConvertToBinary(self, dest):
subprocess.check_call([
@@ -147,15 +153,15 @@ class MacTool(object):
fp = open(file_name, 'rb')
try:
header = fp.read(3)
except e:
except:
fp.close()
return None
fp.close()
if header.startswith("\xFE\xFF"):
if header.startswith(b"\xFE\xFF"):
return "UTF-16"
elif header.startswith("\xFF\xFE"):
elif header.startswith(b"\xFF\xFE"):
return "UTF-16"
elif header.startswith("\xEF\xBB\xBF"):
elif header.startswith(b"\xEF\xBB\xBF"):
return "UTF-8"
else:
return None
@@ -170,7 +176,7 @@ class MacTool(object):
# Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
plist = plistlib.readPlistFromString(lines)
if keys:
plist = dict(list(plist.items()) + list(json.loads(keys[0]).items()))
plist.update(json.loads(keys[0]))
lines = plistlib.writePlistToString(plist)
# Go through all the environment variables and replace them as variables in
@@ -181,7 +187,7 @@ class MacTool(object):
continue
evar = '${%s}' % key
evalue = os.environ[key]
lines = string.replace(lines, evar, evalue)
lines = lines.replace(evar, evalue)
# Xcode supports various suffices on environment variables, which are
# all undocumented. :rfc1034identifier is used in the standard project
@@ -191,11 +197,11 @@ class MacTool(object):
# in a URL either -- oops, hence :rfc1034identifier was born.
evar = '${%s:identifier}' % key
evalue = IDENT_RE.sub('_', os.environ[key])
lines = string.replace(lines, evar, evalue)
lines = lines.replace(evar, evalue)
evar = '${%s:rfc1034identifier}' % key
evalue = IDENT_RE.sub('-', os.environ[key])
lines = string.replace(lines, evar, evalue)
lines = lines.replace(evar, evalue)
# Remove any keys with values that haven't been replaced.
lines = lines.split('\n')
@@ -203,7 +209,7 @@ class MacTool(object):
if lines[i].strip().startswith("<string>${"):
lines[i] = None
lines[i - 1] = None
lines = '\n'.join([x for x in lines if x is not None])
lines = '\n'.join(filter(lambda x: x is not None, lines))
# Write out the file with variables replaced.
fd = open(dest, 'w')
@@ -265,8 +271,9 @@ class MacTool(object):
libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
_, err = libtoolout.communicate()
for line in err.splitlines():
if not libtool_re.match(line) and not libtool_re5.match(line):
print(line, file=sys.stderr)
line_decoded = line.decode('utf-8')
if not libtool_re.match(line_decoded) and not libtool_re5.match(line_decoded):
print(line_decoded, file=sys.stderr)
# Unconditionally touch the output .a file on the command line if present
# and the command succeeded. A bit hacky.
if not libtoolout.returncode:
@@ -331,7 +338,7 @@ class MacTool(object):
def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers):
framework_name = os.path.basename(framework).split('.')[0]
all_headers = list(map(os.path.abspath, all_headers))
all_headers = map(os.path.abspath, all_headers)
filelist = {}
for header in all_headers:
filename = os.path.basename(header)
@@ -395,7 +402,7 @@ class MacTool(object):
command_line.append(str(value))
# Note: actool crashes if inputs path are relative, so use os.path.abspath
# to get absolute path name for inputs.
command_line.extend(list(map(os.path.abspath, inputs)))
command_line.extend(map(os.path.abspath, inputs))
subprocess.check_call(command_line)
def ExecMergeInfoPlist(self, output, *inputs):
@@ -477,7 +484,8 @@ class MacTool(object):
os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
if not os.path.isdir(profiles_dir):
print((
'cannot find mobile provisioning for %s' % bundle_identifier), file=sys.stderr)
'cannot find mobile provisioning for %s' % bundle_identifier),
file=sys.stderr)
sys.exit(1)
provisioning_profiles = None
if profile:
@@ -499,7 +507,8 @@ class MacTool(object):
profile_path, profile_data, team_identifier)
if not valid_provisioning_profiles:
print((
'cannot find mobile provisioning for %s' % bundle_identifier), file=sys.stderr)
'cannot find mobile provisioning for %s' % bundle_identifier),
file=sys.stderr)
sys.exit(1)
# If the user has multiple provisioning profiles installed that can be
# used for ${bundle_identifier}, pick the most specific one (ie. the
@@ -663,7 +672,7 @@ def WriteHmap(output_name, filelist):
count = len(filelist)
capacity = NextGreaterPowerOf2(count)
strings_offset = 24 + (12 * capacity)
max_value_length = len(max(list(filelist.items()), key=lambda k_v:len(k_v[1]))[1])
max_value_length = len(max(filelist.items(), key=lambda t: len(t[1]))[1])
out = open(output_name, "wb")
out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
@@ -671,7 +680,7 @@ def WriteHmap(output_name, filelist):
# Create empty hashmap buckets.
buckets = [None] * capacity
for file, path in list(filelist.items()):
for file, path in filelist.items():
key = 0
for c in file:
key += ord(c.lower()) * 13
@@ -12,9 +12,18 @@ import re
import subprocess
import sys
from six.moves import collections_abc
from gyp.common import OrderedSet
import gyp.MSVSUtil
import gyp.MSVSVersion
from gyp.MSVSVersion import version_to_tuple
try:
# basestring was removed in python3.
basestring
except NameError:
basestring = str
windows_quoter_regex = re.compile(r'(\\*)"')
@@ -30,6 +39,11 @@ def QuoteForRspFile(arg):
# works more or less because most programs (including the compiler, etc.)
# use that function to handle command line arguments.
if not os.getenv('GYP_MSVS_DISABLE_PATH_NORMALIZATION'):
# Use a heuristic to try to find args that are paths, and normalize them
if arg.find('/') > 0 or arg.count('/') > 1:
arg = os.path.normpath(arg)
# For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
# preceding it, and results in n backslashes + the quote. So we substitute
# in 2* what we match, +1 more, plus the quote.
@@ -80,8 +94,8 @@ def _AddPrefix(element, prefix):
"""Add |prefix| to |element| or each subelement if element is iterable."""
if element is None:
return element
# Note, not Iterable because we don't want to handle strings like that.
if isinstance(element, list) or isinstance(element, tuple):
if (isinstance(element, collections_abc.Iterable) and
not isinstance(element, basestring)):
return [prefix + e for e in element]
else:
return prefix + element
@@ -93,10 +107,11 @@ def _DoRemapping(element, map):
if map is not None and element is not None:
if not callable(map):
map = map.get # Assume it's a dict, otherwise a callable to do the remap.
if isinstance(element, list) or isinstance(element, tuple):
element = [_f for _f in [list(map(elem)) for elem in element] if _f]
if (isinstance(element, collections_abc.Iterable) and
not isinstance(element, basestring)):
element = filter(None, [map(elem) for elem in element])
else:
element = list(map(element))
element = map(element)
return element
@@ -105,7 +120,8 @@ def _AppendOrReturn(append, element):
then add |element| to it, adding each item in |element| if it's a list or
tuple."""
if append is not None and element is not None:
if isinstance(element, list) or isinstance(element, tuple):
if (isinstance(element, collections_abc.Iterable) and
not isinstance(element, basestring)):
append.extend(element)
else:
append.append(element)
@@ -125,7 +141,8 @@ def _FindDirectXInstallation():
if not dxsdk_dir:
# Setup params to pass to and attempt to launch reg.exe.
cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
for line in p.communicate()[0].splitlines():
if 'InstallPath' in line:
dxsdk_dir = line.split(' ')[3] + "\\"
@@ -216,7 +233,7 @@ class MsvsSettings(object):
]
unsupported = []
for field in unsupported_fields:
for config in list(configs.values()):
for config in configs.values():
if field in config:
unsupported += ["%s not supported (target %s)." %
(field, spec['target_name'])]
@@ -269,7 +286,8 @@ class MsvsSettings(object):
def AdjustLibraries(self, libraries):
"""Strip -l from library if it's specified with that."""
libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs]
return [lib + '.lib' if not lib.lower().endswith('.lib') else lib
for lib in libs]
def _GetAndMunge(self, field, path, default, prefix, append, map):
"""Retrieve a value from |field| at |path| or return |default|. If
@@ -306,7 +324,10 @@ class MsvsSettings(object):
# There's two levels of architecture/platform specification in VS. The
# first level is globally for the configuration (this is what we consider
# "the" config at the gyp level, which will be something like 'Debug' or
# 'Release_x64'), and a second target-specific configuration, which is an
# 'Release'), VS2015 and later only use this level
if int(self.vs_version.short_name) >= 2015:
return config
# and a second target-specific configuration, which is an
# override for the global one. |config| is remapped here to take into
# account the local target-specific overrides to the global configuration.
arch = self.GetArch(config)
@@ -468,8 +489,10 @@ class MsvsSettings(object):
prefix='/arch:')
cflags.extend(['/FI' + f for f in self._Setting(
('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
if self.vs_version.short_name in ('2013', '2013e', '2015'):
# New flag required in 2013 to maintain previous PDB behavior.
if version_to_tuple(self.vs_version.project_version) >= (12, 0):
# New flag introduced in VS2013 (project version 12.0) Forces writes to
# the program database (PDB) to be serialized through MSPDBSRV.EXE.
# https://msdn.microsoft.com/en-us/library/dn502518.aspx
cflags.append('/FS')
# ninja handles parallelism by itself, don't have the compiler do it too.
cflags = [x for x in cflags if not x.startswith('/MP')]
@@ -529,7 +552,8 @@ class MsvsSettings(object):
"""Returns the .def file from sources, if any. Otherwise returns None."""
spec = self.spec
if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
def_files = [s for s in spec.get('sources', [])
if s.lower().endswith('.def')]
if len(def_files) == 1:
return gyp_to_build_path(def_files[0])
elif len(def_files) > 1:
@@ -638,18 +662,17 @@ class MsvsSettings(object):
# If the base address is not specifically controlled, DYNAMICBASE should
# be on by default.
base_flags = [x for x in ldflags if 'DYNAMICBASE' in x or x == '/FIXED']
if not base_flags:
if not any('DYNAMICBASE' in flag or flag == '/FIXED' for flag in ldflags):
ldflags.append('/DYNAMICBASE')
# If the NXCOMPAT flag has not been specified, default to on. Despite the
# documentation that says this only defaults to on when the subsystem is
# Vista or greater (which applies to the linker), the IDE defaults it on
# unless it's explicitly off.
if not [x for x in ldflags if 'NXCOMPAT' in x]:
if not any('NXCOMPAT' in flag for flag in ldflags):
ldflags.append('/NXCOMPAT')
have_def_file = [x for x in ldflags if x.startswith('/DEF:')]
have_def_file = any(flag.startswith('/DEF:') for flag in ldflags)
manifest_flags, intermediate_manifest, manifest_files = \
self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
is_executable and not have_def_file, build_dir)
@@ -916,10 +939,10 @@ class PrecompiledHeader(object):
if input == self.pch_source:
pch_output = ['/Yc' + self._PchHeader()]
if command == 'cxx':
return ([('cflags_cc', list(map(expand_special, cflags_cc + pch_output)))],
return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
self.output_obj, [])
elif command == 'cc':
return ([('cflags_c', list(map(expand_special, cflags_c + pch_output)))],
return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
self.output_obj, [])
return [], output, implicit
@@ -1031,7 +1054,8 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
args = vs.SetupScript(arch)
args.extend(('&&', 'set'))
popen = subprocess.Popen(
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
variables, _ = popen.communicate()
if popen.returncode != 0:
raise Exception('"%s" failed with error %d' % (args, popen.returncode))
@@ -1044,7 +1068,7 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
env['INCLUDE'] = ';'.join(system_includes)
env_block = _FormatAsEnvironmentBlock(env)
f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'w')
f.write(env_block)
f.close()
@@ -1052,7 +1076,8 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
args = vs.SetupScript(arch)
args.extend(('&&',
'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE,
universal_newlines=True)
output, _ = popen.communicate()
cl_paths[arch] = _ExtractCLPath(output)
return cl_paths
@@ -1064,7 +1089,7 @@ def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
VS, and we want this check to match for people/bots that build using ninja,
so they're not surprised when the VS build fails."""
if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
no_specials = [x for x in sources if '$' not in x]
no_specials = filter(lambda x: '$' not in x, sources)
relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
missing = [x for x in relative if not os.path.exists(x)]
if missing:
@@ -31,7 +31,7 @@ class Writer(object):
if value is None:
return
if isinstance(value, list):
value = ' '.join([_f for _f in value if _f]) # Filter out empty strings.
value = ' '.join(filter(None, value)) # Filter out empty strings.
self._line('%s = %s' % (key, value), indent)
def pool(self, name, depth):
@@ -68,11 +68,11 @@ class Writer(object):
all_inputs = list(map(escape_path, all_inputs))
if implicit:
implicit = list(map(escape_path, self._as_list(implicit)))
implicit = map(escape_path, self._as_list(implicit))
all_inputs.append('|')
all_inputs.extend(implicit)
if order_only:
order_only = list(map(escape_path, self._as_list(order_only)))
order_only = map(escape_path, self._as_list(order_only))
all_inputs.append('||')
all_inputs.extend(order_only)
@@ -81,7 +81,7 @@ class Writer(object):
if variables:
if isinstance(variables, dict):
iterator = iter(list(variables.items()))
iterator = iter(variables.items())
else:
iterator = iter(variables)
@@ -149,6 +149,14 @@ class Writer(object):
return []
if isinstance(input, list):
return input
# map is not a class in Python 2
try:
if isinstance(input, map):
return list(input)
except TypeError:
pass
return [input]
@@ -1,289 +0,0 @@
# Unmodified from http://code.activestate.com/recipes/576693/
# other than to add MIT license header (as specified on page, but not in code).
# Linked from Python documentation here:
# http://docs.python.org/2/library/collections.html#collections.OrderedDict
#
# This should be deleted once Py2.7 is available on all bots, see
# http://crbug.com/241769.
#
# Copyright (c) 2009 Raymond Hettinger.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
# Passes Python2.7's test suite and incorporates all the latest updates.
try:
from _thread import get_ident as _get_ident
except ImportError:
from _dummy_thread import get_ident as _get_ident
try:
from _abcoll import KeysView, ValuesView, ItemsView
except ImportError:
pass
class OrderedDict(dict):
'Dictionary that remembers insertion order'
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as for regular dictionaries.
# The internal self.__map dictionary maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. Signature is the same as for
regular dictionaries, but keyword arguments are not recommended
because their insertion order is arbitrary.
'''
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds)
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link which goes at the end of the linked
# list, and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[0]
last[1] = root[0] = self.__map[key] = [last, root, key]
dict_setitem(self, key, value)
def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which is
# then removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link_prev, link_next, key = self.__map.pop(key)
link_prev[1] = link_next
link_next[0] = link_prev
def __iter__(self):
'od.__iter__() <==> iter(od)'
root = self.__root
curr = root[1]
while curr is not root:
yield curr[2]
curr = curr[1]
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
root = self.__root
curr = root[0]
while curr is not root:
yield curr[2]
curr = curr[0]
def clear(self):
'od.clear() -> None. Remove all items from od.'
try:
for node in self.__map.values():
del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
except AttributeError:
pass
dict.clear(self)
def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false.
'''
if not self:
raise KeyError('dictionary is empty')
root = self.__root
if last:
link = root[0]
link_prev = link[0]
link_prev[1] = root
root[0] = link_prev
else:
link = root[1]
link_next = link[1]
root[1] = link_next
link_next[0] = root
key = link[2]
del self.__map[key]
value = dict.pop(self, key)
return key, value
# -- the following methods do not depend on the internal structure --
def keys(self):
'od.keys() -> list of keys in od'
return list(self)
def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self]
def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self]
def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self)
def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k]
def iteritems(self):
'od.iteritems -> an iterator over the (key, value) items in od'
for k in self:
yield (k, self[k])
# Suppress 'OrderedDict.update: Method has no argument':
# pylint: disable=E0211
def update(*args, **kwds):
'''od.update(E, **F) -> None. Update od from dict/iterable E and F.
If E is a dict instance, does: for k in E: od[k] = E[k]
If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
Or if E is an iterable of items, does: for k, v in E: od[k] = v
In either case, this is followed by: for k, v in F.items(): od[k] = v
'''
if len(args) > 2:
raise TypeError('update() takes at most 2 positional '
'arguments (%d given)' % (len(args),))
elif not args:
raise TypeError('update() takes at least 1 argument (0 given)')
self = args[0]
# Make progressively weaker assumptions about "other"
other = ()
if len(args) == 2:
other = args[1]
if isinstance(other, dict):
for key in other:
self[key] = other[key]
elif hasattr(other, 'keys'):
for key in list(other.keys()):
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in list(kwds.items()):
self[key] = value
__update = update # let subclasses override update without breaking __init__
__marker = object()
def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
'''
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default
def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self.items()))
finally:
del _repr_running[call_key]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def copy(self):
'od.copy() -> a shallow copy of od'
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
and values equal to v (which defaults to None).
'''
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
while comparison to a regular mapping is order-insensitive.
'''
if isinstance(other, OrderedDict):
return len(self)==len(other) and list(self.items()) == list(other.items())
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
# -- the following methods are only used in Python 2.7 --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
@@ -28,8 +28,19 @@ _deepcopy_dispatch = d = {}
def _deepcopy_atomic(x):
return x
for x in (type(None), int, int, float,
bool, str, str, type):
try:
_string_types = (str, unicode)
# There's no unicode in python3
except NameError:
_string_types = (str, )
try:
_integer_types = (int, long)
# There's no long in python3
except NameError:
_integer_types = (int, )
for x in (type(None), float, bool, type) + _integer_types + _string_types:
d[x] = _deepcopy_atomic
def _deepcopy_list(x):
@@ -9,6 +9,8 @@
These functions are executed via gyp-win-tool when using the ninja generator.
"""
from __future__ import print_function
import os
import re
import shutil
@@ -128,7 +130,8 @@ class WinTool(object):
# For that reason, since going through the shell doesn't seem necessary on
# non-Windows don't do that there.
link = subprocess.Popen(args, shell=sys.platform == 'win32', env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
out, _ = link.communicate()
for line in out.splitlines():
if (not line.startswith(' Creating library ') and
@@ -193,16 +196,18 @@ class WinTool(object):
our_manifest = '%(out)s.manifest' % variables
# Load and normalize the manifests. mt.exe sometimes removes whitespace,
# and sometimes doesn't unfortunately.
with open(our_manifest, 'rb') as our_f:
with open(assert_manifest, 'rb') as assert_f:
our_data = our_f.read().translate(None, string.whitespace)
assert_data = assert_f.read().translate(None, string.whitespace)
with open(our_manifest, 'r') as our_f:
with open(assert_manifest, 'r') as assert_f:
our_data = re.sub(r'\s+', '', our_f.read())
assert_data = re.sub(r'\s+', '', assert_f.read())
if our_data != assert_data:
os.unlink(out)
def dump(filename):
sys.stderr.write('%s\n-----\n' % filename)
with open(filename, 'rb') as f:
sys.stderr.write(f.read() + '\n-----\n')
print(filename, file=sys.stderr)
print('-----', file=sys.stderr)
with open(filename, 'r') as f:
print(f.read(), file=sys.stderr)
print('-----', file=sys.stderr)
dump(intermediate_manifest)
dump(our_manifest)
dump(assert_manifest)
@@ -219,7 +224,8 @@ class WinTool(object):
tool)."""
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
out, _ = popen.communicate()
for line in out.splitlines():
if line and 'manifest authoring warning 81010002' not in line:
@@ -231,7 +237,7 @@ class WinTool(object):
|args| is tuple containing path to resource file, path to manifest file
and resource name which can be "1" (for executables) or "2" (for DLLs)."""
manifest_path, resource_path, resource_name = args
with open(resource_path, 'wb') as output:
with open(resource_path, 'w') as output:
output.write('#include <windows.h>\n%s RT_MANIFEST "%s"' % (
resource_name,
os.path.abspath(manifest_path).replace('\\', '/')))
@@ -251,7 +257,8 @@ class WinTool(object):
idl]
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
out, _ = popen.communicate()
# Filter junk out of stdout, and write filtered versions. Output we want
# to filter is pairs of lines that look like this:
@@ -270,7 +277,8 @@ class WinTool(object):
"""Filter logo banner from invocations of asm.exe."""
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
out, _ = popen.communicate()
for line in out.splitlines():
if (not line.startswith('Copyright (C) Microsoft Corporation') and
@@ -285,7 +293,8 @@ class WinTool(object):
don't support the /nologo flag."""
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
out, _ = popen.communicate()
for line in out.splitlines():
if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
@@ -7,6 +7,8 @@ This module contains classes that help to emulate xcodebuild behavior on top of
other build systems, such as make and ninja.
"""
from __future__ import print_function
import copy
import gyp.common
import os
@@ -724,6 +726,8 @@ class XcodeSettings(object):
def _AddObjectiveCARCFlags(self, flags):
if self._Test('CLANG_ENABLE_OBJC_ARC', 'YES', default='NO'):
flags.append('-fobjc-arc')
if self._Test('CLANG_ENABLE_OBJC_WEAK', 'YES', default='NO'):
flags.append('-fobjc-weak')
def _AddObjectiveCMissingPropertySynthesisFlags(self, flags):
if self._Test('CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS',
@@ -924,7 +928,7 @@ class XcodeSettings(object):
# extensions and provide loader and main function.
# These flags reflect the compilation options used by xcode to compile
# extensions.
if XcodeVersion() < '0900':
if XcodeVersion()[0] < '0900':
ldflags.append('-lpkstart')
ldflags.append(sdk_root +
'/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
@@ -1131,8 +1135,9 @@ class XcodeSettings(object):
output = subprocess.check_output(
['security', 'find-identity', '-p', 'codesigning', '-v'])
for line in output.splitlines():
if identity in line:
fingerprint = line.split()[1]
line_decoded = line.decode('utf-8')
if identity in line_decoded:
fingerprint = line_decoded.split()[1]
cache = XcodeSettings._codesigning_key_cache
assert identity not in cache or fingerprint == cache[identity], (
"Multiple codesigning fingerprints for identity: %s" % identity)
@@ -1149,7 +1154,7 @@ class XcodeSettings(object):
return pre + postbuilds + post
def _AdjustLibrary(self, library, config_name=None):
if library.endswith('.framework'):
if library.endswith('.framework') or library.endswith('.xcframework'):
l = '-framework ' + os.path.splitext(os.path.basename(library))[0]
else:
m = self.library_re.match(library)
@@ -1448,9 +1453,9 @@ def GetStdout(cmdlist):
job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
out = job.communicate()[0]
if job.returncode != 0:
sys.stderr.write(out + '\n')
sys.stderr.write(out + b'\n')
raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
return out.rstrip('\n')
return out.rstrip(b'\n').decode('utf-8')
def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
@@ -1462,7 +1467,7 @@ def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
# that amounts to merging in the global xcode_settings into each local
# xcode_settings dict.
global_xcode_settings = global_dict.get('xcode_settings', {})
for config in list(spec['configurations'].values()):
for config in spec['configurations'].values():
if 'xcode_settings' in config:
new_settings = global_xcode_settings.copy()
new_settings.update(config['xcode_settings'])
@@ -1658,7 +1663,7 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
install_name_base = xcode_settings.GetInstallNameBase()
if install_name_base:
env['DYLIB_INSTALL_NAME_BASE'] = install_name_base
if XcodeVersion() >= '0500' and not env.get('SDKROOT'):
if XcodeVersion()[0] >= '0500' and not env.get('SDKROOT'):
sdk_root = xcode_settings._SdkRoot(configuration)
if not sdk_root:
sdk_root = xcode_settings._XcodeSdkPath('')
@@ -1734,7 +1739,7 @@ def _TopologicallySortedEnvVarKeys(env):
# Topologically sort, and then reverse, because we used an edge definition
# that's inverted from the expected result of this function (see comment
# above).
order = gyp.common.TopologicallySorted(list(env.keys()), GetEdges)
order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
order.reverse()
return order
except gyp.common.CycleError as e:
@@ -1764,8 +1769,8 @@ def GetSpecPostbuildCommands(spec, quiet=False):
def _HasIOSTarget(targets):
"""Returns true if any target contains the iOS specific key
IPHONEOS_DEPLOYMENT_TARGET."""
for target_dict in list(targets.values()):
for config in list(target_dict['configurations'].values()):
for target_dict in targets.values():
for config in target_dict['configurations'].values():
if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'):
return True
return False
@@ -1777,6 +1782,7 @@ def _AddIOSDeviceConfigurations(targets):
for target_dict in targets.values():
toolset = target_dict['toolset']
configs = target_dict['configurations']
for config_name, simulator_config_dict in dict(configs).items():
iphoneos_config_dict = copy.deepcopy(simulator_config_dict)
configs[config_name + '-iphoneos'] = iphoneos_config_dict
@@ -137,6 +137,7 @@ Strings of class unicode are handled properly and encoded in UTF-8 when
a project file is output.
"""
import functools
import gyp.common
import posixpath
import re
@@ -154,6 +155,18 @@ except ImportError:
import sha
_new_sha1 = sha.new
try:
# basestring was removed in python3.
basestring
except NameError:
basestring = str
try:
# cmp was removed in python3.
cmp
except NameError:
def cmp(a, b):
return (a > b) - (a < b)
# See XCObject._EncodeString. This pattern is used to determine when a string
# can be printed unquoted. Strings that match this pattern may be printed
@@ -324,8 +337,7 @@ class XCObject(object):
that._properties[key] = new_value
else:
that._properties[key] = value
elif isinstance(value, str) or isinstance(value, str) or \
isinstance(value, int):
elif isinstance(value, basestring) or isinstance(value, int):
that._properties[key] = value
elif isinstance(value, list):
if is_strong:
@@ -419,7 +431,7 @@ class XCObject(object):
"""
hash.update(struct.pack('>i', len(data)))
hash.update(data)
hash.update(data.encode('utf-8'))
if seed_hash is None:
seed_hash = _new_sha1()
@@ -449,7 +461,7 @@ class XCObject(object):
# is 160 bits. Instead of throwing out 64 bits of the digest, xor them
# into the portion that gets used.
assert hash.digest_size % 4 == 0
digest_int_count = hash.digest_size / 4
digest_int_count = hash.digest_size // 4
digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest())
id_ints = [0, 0, 0]
for index in range(0, digest_int_count):
@@ -603,7 +615,12 @@ class XCObject(object):
comment = value.Comment()
elif isinstance(value, str):
printable += self._EncodeString(value)
elif isinstance(value, str):
# A python3 compatible way of saying isinstance(value, unicode).
# basestring is str in python3 so this is equivalent to the above
# isinstance. Thus if it failed above it will fail here.
# In python2 we test against str and unicode at this point. str has already
# failed in the above isinstance so we test against unicode.
elif isinstance(value, basestring):
printable += self._EncodeString(value.encode('utf-8'))
elif isinstance(value, int):
printable += str(value)
@@ -766,7 +783,7 @@ class XCObject(object):
' must be list, not ' + value.__class__.__name__)
for item in value:
if not isinstance(item, property_type) and \
not (item.__class__ == str and property_type == str):
not (isinstance(item, basestring) and property_type == str):
# Accept unicode where str is specified. str is treated as
# UTF-8-encoded.
raise TypeError(
@@ -774,7 +791,7 @@ class XCObject(object):
' must be ' + property_type.__name__ + ', not ' + \
item.__class__.__name__)
elif not isinstance(value, property_type) and \
not (value.__class__ == str and property_type == str):
not (isinstance(value, basestring) and property_type == str):
# Accept unicode where str is specified. str is treated as
# UTF-8-encoded.
raise TypeError(
@@ -788,8 +805,7 @@ class XCObject(object):
self._properties[property] = value.Copy()
else:
self._properties[property] = value
elif isinstance(value, str) or isinstance(value, str) or \
isinstance(value, int):
elif isinstance(value, basestring) or isinstance(value, int):
self._properties[property] = value
elif isinstance(value, list):
if is_strong:
@@ -1402,7 +1418,8 @@ class PBXGroup(XCHierarchicalElement):
def SortGroup(self):
self._properties['children'] = \
sorted(self._properties['children'], cmp=lambda x,y: x.Compare(y))
sorted(self._properties['children'],
key=functools.cmp_to_key(XCHierarchicalElement.Compare))
# Recurse.
for child in self._properties['children']:
@@ -1426,8 +1443,8 @@ class XCFileLikeElement(XCHierarchicalElement):
xche = self
while xche != None and isinstance(xche, XCHierarchicalElement):
xche_hashables = xche.Hashables()
for index in range(0, len(xche_hashables)):
hashables.insert(index, xche_hashables[index])
for index, xche_hashable in enumerate(xche_hashables):
hashables.insert(index, xche_hashable)
xche = xche.parent
return hashables
@@ -1514,8 +1531,10 @@ class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject):
'xcconfig': 'text.xcconfig',
'xcdatamodel': 'wrapper.xcdatamodel',
'xcdatamodeld':'wrapper.xcdatamodeld',
'xcframework': 'wrapper.xcframework',
'xib': 'file.xib',
'y': 'sourcecode.yacc',
'tbd': 'sourcecode.text-based-dylib-definition',
}
prop_map = {
@@ -2468,8 +2487,7 @@ class PBXNativeTarget(XCTarget):
# The headers phase should come before the resources, sources, and
# frameworks phases, if any.
insert_at = len(self._properties['buildPhases'])
for index in range(0, len(self._properties['buildPhases'])):
phase = self._properties['buildPhases'][index]
for index, phase in enumerate(self._properties['buildPhases']):
if isinstance(phase, PBXResourcesBuildPhase) or \
isinstance(phase, PBXSourcesBuildPhase) or \
isinstance(phase, PBXFrameworksBuildPhase):
@@ -2489,8 +2507,7 @@ class PBXNativeTarget(XCTarget):
# The resources phase should come before the sources and frameworks
# phases, if any.
insert_at = len(self._properties['buildPhases'])
for index in range(0, len(self._properties['buildPhases'])):
phase = self._properties['buildPhases'][index]
for index, phase in enumerate(self._properties['buildPhases']):
if isinstance(phase, PBXSourcesBuildPhase) or \
isinstance(phase, PBXFrameworksBuildPhase):
insert_at = index
@@ -2708,7 +2725,7 @@ class PBXProject(XCContainerPortal):
# according to their defined order.
self._properties['mainGroup']._properties['children'] = \
sorted(self._properties['mainGroup']._properties['children'],
cmp=lambda x,y: x.CompareRootGroup(y))
key=functools.cmp_to_key(XCHierarchicalElement.CompareRootGroup))
# Sort everything else by putting group before files, and going
# alphabetically by name within sections of groups and files. SortGroup
@@ -2799,9 +2816,8 @@ class PBXProject(XCContainerPortal):
# Xcode seems to sort this list case-insensitively
self._properties['projectReferences'] = \
sorted(self._properties['projectReferences'], cmp=lambda x,y:
cmp(x['ProjectRef'].Name().lower(),
y['ProjectRef'].Name().lower()))
sorted(self._properties['projectReferences'],
key=lambda x: x['ProjectRef'].Name().lower())
else:
# The link already exists. Pull out the relevnt data.
project_ref_dict = self._other_pbxprojects[other_pbxproject]
@@ -2898,19 +2914,6 @@ class PBXProject(XCContainerPortal):
# same order that the targets are sorted in the remote project file. This
# is the sort order used by Xcode.
def CompareProducts(x, y, remote_products):
# x and y are PBXReferenceProxy objects. Go through their associated
# PBXContainerItem to get the remote PBXFileReference, which will be
# present in the remote_products list.
x_remote = x._properties['remoteRef']._properties['remoteGlobalIDString']
y_remote = y._properties['remoteRef']._properties['remoteGlobalIDString']
x_index = remote_products.index(x_remote)
y_index = remote_products.index(y_remote)
# Use the order of each remote PBXFileReference in remote_products to
# determine the sort order.
return cmp(x_index, y_index)
for other_pbxproject, ref_dict in self._other_pbxprojects.items():
# Build up a list of products in the remote project file, ordered the
# same as the targets that produce them.
@@ -2925,7 +2928,7 @@ class PBXProject(XCContainerPortal):
product_group = ref_dict['ProductGroup']
product_group._properties['children'] = sorted(
product_group._properties['children'],
cmp=lambda x, y, rp=remote_products: CompareProducts(x, y, rp))
key=lambda x: remote_products.index(x._properties['remoteRef']._properties['remoteGlobalIDString']))
class XCProjectFile(XCObject):
@@ -2956,8 +2959,7 @@ class XCProjectFile(XCObject):
self._XCPrint(file, 0, '{ ')
else:
self._XCPrint(file, 0, '{\n')
for property, value in sorted(iter(self._properties.items()),
cmp=lambda x, y: cmp(x, y)):
for property, value in sorted(self._properties.items()):
if property == 'objects':
self._PrintObjects(file)
else:
@@ -2984,7 +2986,7 @@ class XCProjectFile(XCObject):
self._XCPrint(file, 0, '\n')
self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n')
for object in sorted(objects_by_class[class_name],
cmp=lambda x, y: cmp(x.id, y.id)):
key=lambda x: x.id):
object.Print(file)
self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n')
@@ -32,8 +32,7 @@ def _Replacement_writexml(self, writer, indent="", addindent="", newl=""):
writer.write(indent+"<" + self.tagName)
attrs = self._get_attributes()
a_names = list(attrs.keys())
a_names.sort()
a_names = sorted(attrs.keys())
for a_name in a_names:
writer.write(" %s=\"" % a_name)
+22 -22
View File
@@ -41,19 +41,19 @@ chrome_src = mozpath.abspath(mozpath.join(mozpath.dirname(gyp.__file__),
script_dir = mozpath.join(chrome_src, 'build')
def encode(value):
if isinstance(value, str):
return value.encode('utf-8')
def decode(value):
if isinstance(value, bytes):
return value.decode('utf-8')
return value
# Default variables gyp uses when evaluating gyp files.
generator_default_variables = {
}
for dirname in [b'INTERMEDIATE_DIR', b'SHARED_INTERMEDIATE_DIR', b'PRODUCT_DIR',
b'LIB_DIR', b'SHARED_LIB_DIR']:
for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
'LIB_DIR', 'SHARED_LIB_DIR']:
# Some gyp steps fail if these are empty(!).
generator_default_variables[dirname] = b'$' + dirname
generator_default_variables[dirname] = '$' + dirname
for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
@@ -61,7 +61,7 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
'LINKER_SUPPORTS_ICF']:
generator_default_variables[unused] = b''
generator_default_variables[unused] = ''
class GypContext(TemplateContext):
@@ -116,13 +116,13 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
dependencies will be, and vars a dict of variables to pass to the gyp
processor.
"""
is_win = config.substs['OS_TARGET'] == 'WINNT'
is_msvc = bool(config.substs['_MSC_VER'])
# gyp expects plain str instead of unicode. The frontend code gives us
# unicode strings, so convert them.
path = encode(path)
str_vars = dict((name, encode(value)) for name, value in list(vars.items()))
path = decode(path)
str_vars = dict((name, decode(value)) for name, value in vars.items())
str_vars['PYTHON'] = decode(config.substs['PYTHON'])
if is_msvc:
# This isn't actually used anywhere in this generator, but it's needed
# to override the registry detection of VC++ in gyp.
@@ -130,10 +130,10 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
os.environ['GYP_MSVS_VERSION'] = config.substs['MSVS_VERSION']
params = {
b'parallel': False,
b'generator_flags': {},
b'build_files': [path],
b'root_targets': None,
'parallel': False,
'generator_flags': {},
'build_files': [path],
'root_targets': None,
}
if no_chromium:
@@ -142,23 +142,23 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
else:
depth = chrome_src
# Files that gyp_chromium always includes
includes = [encode(mozpath.join(script_dir, 'common.gypi'))]
includes = [decode(mozpath.join(script_dir, 'common.gypi'))]
finder = FileFinder(chrome_src, find_executables=False)
includes.extend(encode(mozpath.join(chrome_src, name))
includes.extend(decode(mozpath.join(chrome_src, name))
for name, _ in finder.find('*/supplement.gypi'))
# Read the given gyp file and its dependencies.
generator, flat_list, targets, data = \
gyp.Load([path], format=b'mozbuild',
gyp.Load([path], format='mozbuild',
default_variables=str_vars,
includes=includes,
depth=encode(depth),
depth=decode(depth),
params=params)
# Process all targets from the given gyp files and its dependencies.
# The path given to AllTargets needs to use os.sep, while the frontend code
# gives us paths normalized with forward slash separator.
for target in gyp.common.AllTargets(flat_list, targets, path.replace(b'/', os.sep)):
for target in gyp.common.AllTargets(flat_list, targets, path.replace('/', os.sep)):
build_file, target_name, toolset = gyp.common.ParseQualifiedTarget(target)
# Each target is given its own objdir. The base of that objdir
@@ -235,9 +235,9 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
if name.startswith('lib'):
name = name[3:]
# The context expects an unicode string.
context['LIBRARY_NAME'] = name.decode('utf-8')
context['LIBRARY_NAME'] = name
else:
context['PROGRAM'] = name.decode('utf-8')
context['PROGRAM'] = name
if spec['type'] == 'shared_library':
context['FORCE_SHARED_LIB'] = True
elif spec['type'] == 'static_library' and spec.get('variables', {}).get('no_expand_libs', '0') == '1':
@@ -343,7 +343,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
if not f:
continue
# the result may be a string or a list.
if isinstance(f, (str,)):
if isinstance(f, str):
context[var].append(f)
else:
context[var].extend(f)
@@ -1,259 +0,0 @@
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
# Passes Python2.7's test suite and incorporates all the latest updates.
# Copyright 2009 Raymond Hettinger, released under the MIT License.
# http://code.activestate.com/recipes/576693/
try:
from _thread import get_ident as _get_ident
except ImportError:
from _dummy_thread import get_ident as _get_ident
try:
from _abcoll import KeysView, ValuesView, ItemsView
except ImportError:
pass
class OrderedDict(dict):
'Dictionary that remembers insertion order'
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as for regular dictionaries.
# The internal self.__map dictionary maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. Signature is the same as for
regular dictionaries, but keyword arguments are not recommended
because their insertion order is arbitrary.
'''
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds)
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link which goes at the end of the linked
# list, and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[0]
last[1] = root[0] = self.__map[key] = [last, root, key]
dict_setitem(self, key, value)
def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which is
# then removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link_prev, link_next, key = self.__map.pop(key)
link_prev[1] = link_next
link_next[0] = link_prev
def __iter__(self):
'od.__iter__() <==> iter(od)'
root = self.__root
curr = root[1]
while curr is not root:
yield curr[2]
curr = curr[1]
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
root = self.__root
curr = root[0]
while curr is not root:
yield curr[2]
curr = curr[0]
def clear(self):
'od.clear() -> None. Remove all items from od.'
try:
for node in self.__map.values():
del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
except AttributeError:
pass
dict.clear(self)
def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false.
'''
if not self:
raise KeyError('dictionary is empty')
root = self.__root
if last:
link = root[0]
link_prev = link[0]
link_prev[1] = root
root[0] = link_prev
else:
link = root[1]
link_next = link[1]
root[1] = link_next
link_next[0] = root
key = link[2]
del self.__map[key]
value = dict.pop(self, key)
return key, value
# -- the following methods do not depend on the internal structure --
def keys(self):
'od.keys() -> list of keys in od'
return list(self)
def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self]
def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self]
def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self)
def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k]
def iteritems(self):
'od.iteritems -> an iterator over the (key, value) items in od'
for k in self:
yield (k, self[k])
def update(*args, **kwds):
'''od.update(E, **F) -> None. Update od from dict/iterable E and F.
If E is a dict instance, does: for k in E: od[k] = E[k]
If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
Or if E is an iterable of items, does: for k, v in E: od[k] = v
In either case, this is followed by: for k, v in F.items(): od[k] = v
'''
if len(args) > 2:
raise TypeError('update() takes at most 2 positional '
'arguments (%d given)' % (len(args),))
elif not args:
raise TypeError('update() takes at least 1 argument (0 given)')
self = args[0]
# Make progressively weaker assumptions about "other"
other = ()
if len(args) == 2:
other = args[1]
if isinstance(other, dict):
for key in other:
self[key] = other[key]
elif hasattr(other, 'keys'):
for key in list(other.keys()):
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in list(kwds.items()):
self[key] = value
__update = update # let subclasses override update without breaking __init__
__marker = object()
def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
'''
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default
def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self.items()))
finally:
del _repr_running[call_key]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def copy(self):
'od.copy() -> a shallow copy of od'
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
and values equal to v (which defaults to None).
'''
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
while comparison to a regular mapping is order-insensitive.
'''
if isinstance(other, OrderedDict):
return len(self)==len(other) and list(self.items()) == list(other.items())
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
# -- the following methods are only used in Python 2.7 --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
File diff suppressed because it is too large. Load diff