| Index: pylib/gyp/msvs_emulation.py
|
| diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
|
| index 7d10b94132af5c77cf2f4c370fbe8ef8ad81a39e..7c652159322f124300ea258e390714d9c44d86ba 100644
|
| --- a/pylib/gyp/msvs_emulation.py
|
| +++ b/pylib/gyp/msvs_emulation.py
|
| @@ -8,6 +8,7 @@ build systems, primarily ninja.
|
| """
|
|
|
| import re
|
| +import sys
|
|
|
| windows_quoter_regex = re.compile(r'(\\*)"')
|
|
|
| @@ -41,6 +42,200 @@ def QuoteCmdExeArgument(arg):
|
| # applies and whitespace isn't a word break.
|
| return '"' + tmp + '"'
|
|
|
| +
|
| def EncodeCmdExeList(args):
|
| """Process a list of arguments using QuoteCmdExeArgument."""
|
| return ' '.join(QuoteCmdExeArgument(arg) for arg in args)
|
| +
|
| +
|
| +def _GenericRetrieve(root, default, path):
|
| + """Given a list of dictionary keys |path| and a tree of dicts |root|, find
|
| + value at path, or return |default| if any of the path doesn't exist."""
|
| + if not root:
|
| + return default
|
| + if not path:
|
| + return root
|
| + return _GenericRetrieve(root.get(path[0]), default, path[1:])
|
| +
|
| +
|
| +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):
|
| + return [prefix + e for e in element]
|
| + else:
|
| + return prefix + element
|
| +
|
| +
|
| +def _DoRemapping(element, map):
|
| + """If |element| then remap it through |map|. If |element| is iterable then
|
| + each item will be remapped. Any elements not found will be removed."""
|
| + if map is not None and element is not None:
|
| + if isinstance(element, list) or isinstance(element, tuple):
|
| + element = filter(None, [map.get(elem) for elem in element])
|
| + else:
|
| + element = map.get(element)
|
| + return element
|
| +
|
| +
|
| +def _AppendOrReturn(append, element):
|
| + """If |append| is None, simply return |element|. If |append| is not None,
|
| + 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):
|
| + append.extend(element)
|
| + else:
|
| + append.append(element)
|
| + else:
|
| + return element
|
| +
|
| +
|
| +class MsvsSettings(object):
|
| + """A class that understands the gyp 'msvs_...' values (especially the
|
| + msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
|
| + class helps map those settings to command line options."""
|
| +
|
| + def __init__(self, spec):
|
| + self.spec = spec
|
| + self.configname = None
|
| +
|
| + supported_fields = [
|
| + 'msvs_configuration_attributes',
|
| + 'msvs_settings',
|
| + 'msvs_system_include_dirs',
|
| + 'msvs_disabled_warnings',
|
| + ]
|
| + configs = spec['configurations']
|
| + for field in supported_fields:
|
| + setattr(self, field, {})
|
| + for configname, config in configs.iteritems():
|
| + getattr(self, field)[configname] = config.get(field, {})
|
| +
|
| + def _ConvertVSMacros(self, s):
|
| + """Convert from VS macro names to something equivalent."""
|
| + if '$' in s:
|
| + replacements = {
|
| + # TODO(scottmg): obviously
|
| + '$(VSInstallDir)':
|
| + r'C:\Program Files (x86)\Microsoft Visual Studio 9.0\\',
|
| + }
|
| + for old, new in replacements.iteritems():
|
| + s = s.replace(old, new)
|
| + return s
|
| +
|
| + def _GetAndMunge(self, field, path, default, prefix, append, map):
|
| + """Retrieve a value from |field| at |path| or return |default|. If
|
| + |append| is specified, and the item is found, it will be appended to that
|
| + object instead of returned. If |map| is specified, results will be
|
| + remapped through |map| before being returned or appended."""
|
| + result = _GenericRetrieve(field, default, path)
|
| + result = _DoRemapping(result, map)
|
| + result = _AddPrefix(result, prefix)
|
| + return _AppendOrReturn(append, result)
|
| +
|
| + class _GetWrapper(object):
|
| + def __init__(self, parent, field, base_path, append=None):
|
| + self.parent = parent
|
| + self.field = field
|
| + self.base_path = [base_path]
|
| + self.append = append
|
| + def __call__(self, name, map=None, prefix=''):
|
| + return self.parent._GetAndMunge(self.field, self.base_path + [name],
|
| + default=None, prefix=prefix, append=self.append, map=map)
|
| +
|
| + def Setting(self, path, default=None, prefix='', append=None, map=None):
|
| + """_GetAndMunge for msvs_settings."""
|
| + return self._GetAndMunge(
|
| + self.msvs_settings[self.configname], path, default, prefix, append, map)
|
| +
|
| + def ConfigAttrib(self, path, default=None, prefix='', append=None, map=None):
|
| + """_GetAndMunge for msvs_configuration_attributes."""
|
| + return self._GetAndMunge(
|
| + self.msvs_configuration_attributes[self.configname],
|
| + path, default, prefix, append, map)
|
| +
|
| + def GetSystemIncludes(self, config):
|
| + """Returns the extra set of include paths that are used for the Windows
|
| + SDK and similar."""
|
| + return [self._ConvertVSMacros(p)
|
| + for p in self.msvs_system_include_dirs[config]]
|
| +
|
| + def GetComputedDefines(self, config):
|
| + """Returns the set of defines that are injected to the defines list based
|
| + on other VS settings."""
|
| + self.configname = config
|
| + defines = []
|
| + if self.ConfigAttrib(['CharacterSet']) == '1':
|
| + defines.extend(('_UNICODE', 'UNICODE'))
|
| + if self.ConfigAttrib(['CharacterSet']) == '2':
|
| + defines.append('_MBCS')
|
| + defines.extend(self.Setting(('VCCLCompilerTool', 'PreprocessorDefinitions'),
|
| + default=[]))
|
| + self.configname = None
|
| + return defines
|
| +
|
| + def GetCflags(self, config):
|
| + """Returns the flags that need to be added to .c and .cc compilations."""
|
| + cflags = []
|
| + cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
|
| + cl = self._GetWrapper(self, self.msvs_settings[config],
|
| + 'VCCLCompilerTool', append=cflags)
|
| + cl('Optimization', map={'0': 'd', '2': 's'}, prefix='/O')
|
| + cl('InlineFunctionExpansion', prefix='/Ob')
|
| + cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
|
| + cl('FavorSizeOrSpeed', map={'1': 's', '2': 't'}, prefix='/O')
|
| + cl('WholeProgramOptimization', map={'true': '/GL'})
|
| + cl('WarningLevel', prefix='/W')
|
| + cl('WarnAsError', map={'true': '/WX'})
|
| + cl('DebugInformationFormat',
|
| + map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z')
|
| + cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
|
| + cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
|
| + cl('MinimalRebuild', map={'true': '/Gm'})
|
| + cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
|
| + cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
|
| + cl('RuntimeLibrary',
|
| + map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
|
| + cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
|
| + cl('AdditionalOptions', prefix='')
|
| + return cflags
|
| +
|
| + def GetCflagsC(self, config):
|
| + """Returns the flags that need to be added to .c compilations."""
|
| + return []
|
| +
|
| + def GetCflagsCC(self, config):
|
| + """Returns the flags that need to be added to .cc compilations."""
|
| + return ['/TP']
|
| +
|
| + def GetLdflags(self, config, product_dir, gyp_to_build_path):
|
| + """Returns the flags that need to be added to link and lib commands."""
|
| + ldflags = []
|
| + ld = self._GetWrapper(self, self.msvs_settings[config],
|
| + 'VCLinkerTool', append=ldflags)
|
| + ld('GenerateDebugInformation', map={'true': '/DEBUG'})
|
| + ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
|
| + ld('AdditionalLibraryDirectories', prefix='/LIBPATH:')
|
| + ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
|
| + ld('AdditionalOptions', prefix='')
|
| + ld('SubSystem', map={'1': 'CONSOLE', '2': 'WINDOWS'}, prefix='/SUBSYSTEM:')
|
| + ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
|
| + ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
|
| + ld('RandomizedBaseAddress',
|
| + map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE')
|
| + ld('DataExecutionPrevention',
|
| + map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
|
| + ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
|
| + ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
|
| + ld('LinkTimeCodeGeneration', map={'1': '/LTCG'})
|
| + # TODO(scottmg): This should sort of be somewhere else (not really a flag).
|
| + ld('AdditionalDependencies', prefix='')
|
| + # TODO(scottmg): These too.
|
| + ldflags.extend(('kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib',
|
| + 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib',
|
| + 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'odbccp32.lib',
|
| + 'DelayImp.lib'))
|
| + return ldflags
|
|
|