Index: pylib/gyp/msvs_emulation.py |
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py |
index 7d10b94132af5c77cf2f4c370fbe8ef8ad81a39e..b3a0114812da8ccc75014016fbb9bbc05e57f2be 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,199 @@ 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') |
Nico
2012/03/13 14:55:27
style nit: i believe our style guide wants spaces
scottmg
2012/03/14 00:57:56
Done.
|
+ 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') |
Nico
2012/03/13 14:55:27
nit: indent 4
scottmg
2012/03/14 00:57:56
i was going for ( aligned? not sure how those rule
|
+ ld('DataExecutionPrevention', |
+ map={'1':':NO', '2':''}, prefix='/NXCOMPAT') |
Nico
2012/03/13 14:55:27
nit indent 2 more here too
scottmg
2012/03/14 00:57:56
Done.
|
+ 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 |