redsnow 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +20 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +62 -0
  9. data/Rakefile +36 -0
  10. data/Vagrantfile +20 -0
  11. data/ext/snowcrash/Makefile +64 -0
  12. data/ext/snowcrash/Vagrantfile +20 -0
  13. data/ext/snowcrash/bin/snowcrash +0 -0
  14. data/ext/snowcrash/common.gypi +163 -0
  15. data/ext/snowcrash/config.gypi +10 -0
  16. data/ext/snowcrash/config.mk +5 -0
  17. data/ext/snowcrash/configure +213 -0
  18. data/ext/snowcrash/provisioning.sh +15 -0
  19. data/ext/snowcrash/snowcrash.gyp +141 -0
  20. data/ext/snowcrash/src/ActionParser.h +503 -0
  21. data/ext/snowcrash/src/AssetParser.h +215 -0
  22. data/ext/snowcrash/src/BlockUtility.h +186 -0
  23. data/ext/snowcrash/src/Blueprint.h +283 -0
  24. data/ext/snowcrash/src/BlueprintParser.h +347 -0
  25. data/ext/snowcrash/src/BlueprintParserCore.h +190 -0
  26. data/ext/snowcrash/src/BlueprintSection.h +140 -0
  27. data/ext/snowcrash/src/BlueprintUtility.h +126 -0
  28. data/ext/snowcrash/src/CBlueprint.cc +600 -0
  29. data/ext/snowcrash/src/CBlueprint.h +354 -0
  30. data/ext/snowcrash/src/CSourceAnnotation.cc +140 -0
  31. data/ext/snowcrash/src/CSourceAnnotation.h +106 -0
  32. data/ext/snowcrash/src/CodeBlockUtility.h +189 -0
  33. data/ext/snowcrash/src/DescriptionSectionUtility.h +156 -0
  34. data/ext/snowcrash/src/HTTP.cc +46 -0
  35. data/ext/snowcrash/src/HTTP.h +105 -0
  36. data/ext/snowcrash/src/HeaderParser.h +289 -0
  37. data/ext/snowcrash/src/ListBlockUtility.h +273 -0
  38. data/ext/snowcrash/src/ListUtility.h +95 -0
  39. data/ext/snowcrash/src/MarkdownBlock.cc +176 -0
  40. data/ext/snowcrash/src/MarkdownBlock.h +93 -0
  41. data/ext/snowcrash/src/MarkdownParser.cc +266 -0
  42. data/ext/snowcrash/src/MarkdownParser.h +88 -0
  43. data/ext/snowcrash/src/ParameterDefinitonParser.h +570 -0
  44. data/ext/snowcrash/src/ParametersParser.h +252 -0
  45. data/ext/snowcrash/src/Parser.cc +71 -0
  46. data/ext/snowcrash/src/Parser.h +29 -0
  47. data/ext/snowcrash/src/ParserCore.cc +120 -0
  48. data/ext/snowcrash/src/ParserCore.h +82 -0
  49. data/ext/snowcrash/src/PayloadParser.h +672 -0
  50. data/ext/snowcrash/src/Platform.h +54 -0
  51. data/ext/snowcrash/src/RegexMatch.h +32 -0
  52. data/ext/snowcrash/src/ResourceGroupParser.h +195 -0
  53. data/ext/snowcrash/src/ResourceParser.h +584 -0
  54. data/ext/snowcrash/src/SectionUtility.h +142 -0
  55. data/ext/snowcrash/src/Serialize.cc +52 -0
  56. data/ext/snowcrash/src/Serialize.h +69 -0
  57. data/ext/snowcrash/src/SerializeJSON.cc +601 -0
  58. data/ext/snowcrash/src/SerializeJSON.h +21 -0
  59. data/ext/snowcrash/src/SerializeYAML.cc +336 -0
  60. data/ext/snowcrash/src/SerializeYAML.h +21 -0
  61. data/ext/snowcrash/src/SourceAnnotation.h +177 -0
  62. data/ext/snowcrash/src/StringUtility.h +109 -0
  63. data/ext/snowcrash/src/SymbolTable.h +83 -0
  64. data/ext/snowcrash/src/UriTemplateParser.cc +195 -0
  65. data/ext/snowcrash/src/UriTemplateParser.h +243 -0
  66. data/ext/snowcrash/src/Version.h +39 -0
  67. data/ext/snowcrash/src/csnowcrash.cc +23 -0
  68. data/ext/snowcrash/src/csnowcrash.h +38 -0
  69. data/ext/snowcrash/src/posix/RegexMatch.cc +99 -0
  70. data/ext/snowcrash/src/snowcrash.cc +18 -0
  71. data/ext/snowcrash/src/snowcrash.h +41 -0
  72. data/ext/snowcrash/src/snowcrash/snowcrash.cc +170 -0
  73. data/ext/snowcrash/src/win/RegexMatch.cc +78 -0
  74. data/ext/snowcrash/sundown/CONTRIBUTING.md +10 -0
  75. data/ext/snowcrash/sundown/Makefile +83 -0
  76. data/ext/snowcrash/sundown/Makefile.win +33 -0
  77. data/ext/snowcrash/sundown/examples/smartypants.c +72 -0
  78. data/ext/snowcrash/sundown/examples/sundown.c +80 -0
  79. data/ext/snowcrash/sundown/html/houdini.h +37 -0
  80. data/ext/snowcrash/sundown/html/houdini_href_e.c +108 -0
  81. data/ext/snowcrash/sundown/html/houdini_html_e.c +84 -0
  82. data/ext/snowcrash/sundown/html/html.c +647 -0
  83. data/ext/snowcrash/sundown/html/html.h +77 -0
  84. data/ext/snowcrash/sundown/html/html_smartypants.c +389 -0
  85. data/ext/snowcrash/sundown/html_block_names.txt +25 -0
  86. data/ext/snowcrash/sundown/src/autolink.c +297 -0
  87. data/ext/snowcrash/sundown/src/autolink.h +51 -0
  88. data/ext/snowcrash/sundown/src/buffer.c +225 -0
  89. data/ext/snowcrash/sundown/src/buffer.h +96 -0
  90. data/ext/snowcrash/sundown/src/html_blocks.h +206 -0
  91. data/ext/snowcrash/sundown/src/markdown.c +2701 -0
  92. data/ext/snowcrash/sundown/src/markdown.h +147 -0
  93. data/ext/snowcrash/sundown/src/src_map.c +200 -0
  94. data/ext/snowcrash/sundown/src/src_map.h +58 -0
  95. data/ext/snowcrash/sundown/src/stack.c +81 -0
  96. data/ext/snowcrash/sundown/src/stack.h +29 -0
  97. data/ext/snowcrash/sundown/sundown.def +20 -0
  98. data/ext/snowcrash/tools/gyp/AUTHORS +11 -0
  99. data/ext/snowcrash/tools/gyp/DEPS +24 -0
  100. data/ext/snowcrash/tools/gyp/OWNERS +1 -0
  101. data/ext/snowcrash/tools/gyp/PRESUBMIT.py +120 -0
  102. data/ext/snowcrash/tools/gyp/buildbot/buildbot_run.py +190 -0
  103. data/ext/snowcrash/tools/gyp/codereview.settings +10 -0
  104. data/ext/snowcrash/tools/gyp/data/win/large-pdb-shim.cc +12 -0
  105. data/ext/snowcrash/tools/gyp/gyp +8 -0
  106. data/ext/snowcrash/tools/gyp/gyp.bat +5 -0
  107. data/ext/snowcrash/tools/gyp/gyp_main.py +18 -0
  108. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSNew.py +340 -0
  109. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSProject.py +208 -0
  110. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSSettings.py +1063 -0
  111. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSToolFile.py +58 -0
  112. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUserFile.py +147 -0
  113. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUtil.py +267 -0
  114. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSVersion.py +409 -0
  115. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.py +537 -0
  116. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
  117. data/ext/snowcrash/tools/gyp/pylib/gyp/common.py +521 -0
  118. data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
  119. data/ext/snowcrash/tools/gyp/pylib/gyp/easy_xml.py +157 -0
  120. data/ext/snowcrash/tools/gyp/pylib/gyp/flock_tool.py +49 -0
  121. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.py +0 -0
  122. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
  123. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/android.py +1069 -0
  124. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/cmake.py +1143 -0
  125. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +81 -0
  126. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/eclipse.py +335 -0
  127. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypd.py +87 -0
  128. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypsh.py +56 -0
  129. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.py +2181 -0
  130. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
  131. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/msvs.py +3335 -0
  132. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/ninja.py +2156 -0
  133. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.py +1224 -0
  134. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
  135. data/ext/snowcrash/tools/gyp/pylib/gyp/input.py +2809 -0
  136. data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
  137. data/ext/snowcrash/tools/gyp/pylib/gyp/mac_tool.py +510 -0
  138. data/ext/snowcrash/tools/gyp/pylib/gyp/msvs_emulation.py +972 -0
  139. data/ext/snowcrash/tools/gyp/pylib/gyp/ninja_syntax.py +160 -0
  140. data/ext/snowcrash/tools/gyp/pylib/gyp/ordered_dict.py +289 -0
  141. data/ext/snowcrash/tools/gyp/pylib/gyp/win_tool.py +292 -0
  142. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.py +1440 -0
  143. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
  144. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.py +2889 -0
  145. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
  146. data/ext/snowcrash/tools/gyp/pylib/gyp/xml_fix.py +69 -0
  147. data/ext/snowcrash/tools/gyp/pylintrc +307 -0
  148. data/ext/snowcrash/tools/gyp/samples/samples +81 -0
  149. data/ext/snowcrash/tools/gyp/samples/samples.bat +5 -0
  150. data/ext/snowcrash/tools/gyp/setup.py +19 -0
  151. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec +27 -0
  152. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec +226 -0
  153. data/ext/snowcrash/tools/gyp/tools/emacs/gyp.el +252 -0
  154. data/ext/snowcrash/tools/gyp/tools/graphviz.py +100 -0
  155. data/ext/snowcrash/tools/gyp/tools/pretty_gyp.py +155 -0
  156. data/ext/snowcrash/tools/gyp/tools/pretty_sln.py +168 -0
  157. data/ext/snowcrash/tools/gyp/tools/pretty_vcproj.py +329 -0
  158. data/ext/snowcrash/tools/homebrew/snowcrash.rb +11 -0
  159. data/ext/snowcrash/vcbuild.bat +184 -0
  160. data/lib/redsnow.rb +31 -0
  161. data/lib/redsnow/binding.rb +132 -0
  162. data/lib/redsnow/blueprint.rb +365 -0
  163. data/lib/redsnow/object.rb +18 -0
  164. data/lib/redsnow/parseresult.rb +107 -0
  165. data/lib/redsnow/version.rb +4 -0
  166. data/provisioning.sh +20 -0
  167. data/redsnow.gemspec +35 -0
  168. data/test/_helper.rb +15 -0
  169. data/test/fixtures/sample-api-ast.json +97 -0
  170. data/test/fixtures/sample-api.apib +20 -0
  171. data/test/redsnow_binding_test.rb +35 -0
  172. data/test/redsnow_parseresult_test.rb +50 -0
  173. data/test/redsnow_test.rb +285 -0
  174. metadata +358 -0
@@ -0,0 +1,972 @@
1
+ # Copyright (c) 2012 Google Inc. All rights reserved.
2
+ # Use of this source code is governed by a BSD-style license that can be
3
+ # found in the LICENSE file.
4
+
5
+ """
6
+ This module helps emulate Visual Studio 2008 behavior on top of other
7
+ build systems, primarily ninja.
8
+ """
9
+
10
+ import os
11
+ import re
12
+ import subprocess
13
+ import sys
14
+
15
+ import gyp.MSVSVersion
16
+
17
+ windows_quoter_regex = re.compile(r'(\\*)"')
18
+
19
+ def QuoteForRspFile(arg):
20
+ """Quote a command line argument so that it appears as one argument when
21
+ processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
22
+ Windows programs)."""
23
+ # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
24
+ # threads. This is actually the quoting rules for CommandLineToArgvW, not
25
+ # for the shell, because the shell doesn't do anything in Windows. This
26
+ # works more or less because most programs (including the compiler, etc.)
27
+ # use that function to handle command line arguments.
28
+
29
+ # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
30
+ # preceding it, and results in n backslashes + the quote. So we substitute
31
+ # in 2* what we match, +1 more, plus the quote.
32
+ arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
33
+
34
+ # %'s also need to be doubled otherwise they're interpreted as batch
35
+ # positional arguments. Also make sure to escape the % so that they're
36
+ # passed literally through escaping so they can be singled to just the
37
+ # original %. Otherwise, trying to pass the literal representation that
38
+ # looks like an environment variable to the shell (e.g. %PATH%) would fail.
39
+ arg = arg.replace('%', '%%')
40
+
41
+ # These commands are used in rsp files, so no escaping for the shell (via ^)
42
+ # is necessary.
43
+
44
+ # Finally, wrap the whole thing in quotes so that the above quote rule
45
+ # applies and whitespace isn't a word break.
46
+ return '"' + arg + '"'
47
+
48
+
49
+ def EncodeRspFileList(args):
50
+ """Process a list of arguments using QuoteCmdExeArgument."""
51
+ # Note that the first argument is assumed to be the command. Don't add
52
+ # quotes around it because then built-ins like 'echo', etc. won't work.
53
+ # Take care to normpath only the path in the case of 'call ../x.bat' because
54
+ # otherwise the whole thing is incorrectly interpreted as a path and not
55
+ # normalized correctly.
56
+ if not args: return ''
57
+ if args[0].startswith('call '):
58
+ call, program = args[0].split(' ', 1)
59
+ program = call + ' ' + os.path.normpath(program)
60
+ else:
61
+ program = os.path.normpath(args[0])
62
+ return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:])
63
+
64
+
65
+ def _GenericRetrieve(root, default, path):
66
+ """Given a list of dictionary keys |path| and a tree of dicts |root|, find
67
+ value at path, or return |default| if any of the path doesn't exist."""
68
+ if not root:
69
+ return default
70
+ if not path:
71
+ return root
72
+ return _GenericRetrieve(root.get(path[0]), default, path[1:])
73
+
74
+
75
+ def _AddPrefix(element, prefix):
76
+ """Add |prefix| to |element| or each subelement if element is iterable."""
77
+ if element is None:
78
+ return element
79
+ # Note, not Iterable because we don't want to handle strings like that.
80
+ if isinstance(element, list) or isinstance(element, tuple):
81
+ return [prefix + e for e in element]
82
+ else:
83
+ return prefix + element
84
+
85
+
86
+ def _DoRemapping(element, map):
87
+ """If |element| then remap it through |map|. If |element| is iterable then
88
+ each item will be remapped. Any elements not found will be removed."""
89
+ if map is not None and element is not None:
90
+ if not callable(map):
91
+ map = map.get # Assume it's a dict, otherwise a callable to do the remap.
92
+ if isinstance(element, list) or isinstance(element, tuple):
93
+ element = filter(None, [map(elem) for elem in element])
94
+ else:
95
+ element = map(element)
96
+ return element
97
+
98
+
99
+ def _AppendOrReturn(append, element):
100
+ """If |append| is None, simply return |element|. If |append| is not None,
101
+ then add |element| to it, adding each item in |element| if it's a list or
102
+ tuple."""
103
+ if append is not None and element is not None:
104
+ if isinstance(element, list) or isinstance(element, tuple):
105
+ append.extend(element)
106
+ else:
107
+ append.append(element)
108
+ else:
109
+ return element
110
+
111
+
112
+ def _FindDirectXInstallation():
113
+ """Try to find an installation location for the DirectX SDK. Check for the
114
+ standard environment variable, and if that doesn't exist, try to find
115
+ via the registry. May return None if not found in either location."""
116
+ # Return previously calculated value, if there is one
117
+ if hasattr(_FindDirectXInstallation, 'dxsdk_dir'):
118
+ return _FindDirectXInstallation.dxsdk_dir
119
+
120
+ dxsdk_dir = os.environ.get('DXSDK_DIR')
121
+ if not dxsdk_dir:
122
+ # Setup params to pass to and attempt to launch reg.exe.
123
+ cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s']
124
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
125
+ for line in p.communicate()[0].splitlines():
126
+ if 'InstallPath' in line:
127
+ dxsdk_dir = line.split(' ')[3] + "\\"
128
+
129
+ # Cache return value
130
+ _FindDirectXInstallation.dxsdk_dir = dxsdk_dir
131
+ return dxsdk_dir
132
+
133
+
134
+ class MsvsSettings(object):
135
+ """A class that understands the gyp 'msvs_...' values (especially the
136
+ msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
137
+ class helps map those settings to command line options."""
138
+
139
+ def __init__(self, spec, generator_flags):
140
+ self.spec = spec
141
+ self.vs_version = GetVSVersion(generator_flags)
142
+ self.dxsdk_dir = _FindDirectXInstallation()
143
+
144
+ # Try to find an installation location for the Windows DDK by checking
145
+ # the WDK_DIR environment variable, may be None.
146
+ self.wdk_dir = os.environ.get('WDK_DIR')
147
+
148
+ supported_fields = [
149
+ ('msvs_configuration_attributes', dict),
150
+ ('msvs_settings', dict),
151
+ ('msvs_system_include_dirs', list),
152
+ ('msvs_disabled_warnings', list),
153
+ ('msvs_precompiled_header', str),
154
+ ('msvs_precompiled_source', str),
155
+ ('msvs_configuration_platform', str),
156
+ ('msvs_target_platform', str),
157
+ ]
158
+ configs = spec['configurations']
159
+ for field, default in supported_fields:
160
+ setattr(self, field, {})
161
+ for configname, config in configs.iteritems():
162
+ getattr(self, field)[configname] = config.get(field, default())
163
+
164
+ self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
165
+
166
+ unsupported_fields = [
167
+ 'msvs_prebuild',
168
+ 'msvs_postbuild',
169
+ ]
170
+ unsupported = []
171
+ for field in unsupported_fields:
172
+ for config in configs.values():
173
+ if field in config:
174
+ unsupported += ["%s not supported (target %s)." %
175
+ (field, spec['target_name'])]
176
+ if unsupported:
177
+ raise Exception('\n'.join(unsupported))
178
+
179
+ def GetVSMacroEnv(self, base_to_build=None, config=None):
180
+ """Get a dict of variables mapping internal VS macro names to their gyp
181
+ equivalents."""
182
+ target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
183
+ target_name = self.spec.get('product_prefix', '') + \
184
+ self.spec.get('product_name', self.spec['target_name'])
185
+ target_dir = base_to_build + '\\' if base_to_build else ''
186
+ replacements = {
187
+ '$(OutDir)\\': target_dir,
188
+ '$(TargetDir)\\': target_dir,
189
+ '$(IntDir)': '$!INTERMEDIATE_DIR',
190
+ '$(InputPath)': '${source}',
191
+ '$(InputName)': '${root}',
192
+ '$(ProjectName)': self.spec['target_name'],
193
+ '$(TargetName)': target_name,
194
+ '$(PlatformName)': target_platform,
195
+ '$(ProjectDir)\\': '',
196
+ }
197
+ # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
198
+ # Visual Studio is actually installed.
199
+ if self.vs_version.Path():
200
+ replacements['$(VSInstallDir)'] = self.vs_version.Path()
201
+ replacements['$(VCInstallDir)'] = os.path.join(self.vs_version.Path(),
202
+ 'VC') + '\\'
203
+ # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
204
+ # set. This happens when the SDK is sync'd via src-internal, rather than
205
+ # by typical end-user installation of the SDK. If it's not set, we don't
206
+ # want to leave the unexpanded variable in the path, so simply strip it.
207
+ replacements['$(DXSDK_DIR)'] = self.dxsdk_dir if self.dxsdk_dir else ''
208
+ replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else ''
209
+ return replacements
210
+
211
+ def ConvertVSMacros(self, s, base_to_build=None, config=None):
212
+ """Convert from VS macro names to something equivalent."""
213
+ env = self.GetVSMacroEnv(base_to_build, config=config)
214
+ return ExpandMacros(s, env)
215
+
216
+ def AdjustLibraries(self, libraries):
217
+ """Strip -l from library if it's specified with that."""
218
+ libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
219
+ return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs]
220
+
221
+ def _GetAndMunge(self, field, path, default, prefix, append, map):
222
+ """Retrieve a value from |field| at |path| or return |default|. If
223
+ |append| is specified, and the item is found, it will be appended to that
224
+ object instead of returned. If |map| is specified, results will be
225
+ remapped through |map| before being returned or appended."""
226
+ result = _GenericRetrieve(field, default, path)
227
+ result = _DoRemapping(result, map)
228
+ result = _AddPrefix(result, prefix)
229
+ return _AppendOrReturn(append, result)
230
+
231
+ class _GetWrapper(object):
232
+ def __init__(self, parent, field, base_path, append=None):
233
+ self.parent = parent
234
+ self.field = field
235
+ self.base_path = [base_path]
236
+ self.append = append
237
+ def __call__(self, name, map=None, prefix='', default=None):
238
+ return self.parent._GetAndMunge(self.field, self.base_path + [name],
239
+ default=default, prefix=prefix, append=self.append, map=map)
240
+
241
+ def GetArch(self, config):
242
+ """Get architecture based on msvs_configuration_platform and
243
+ msvs_target_platform. Returns either 'x86' or 'x64'."""
244
+ configuration_platform = self.msvs_configuration_platform.get(config, '')
245
+ platform = self.msvs_target_platform.get(config, '')
246
+ if not platform: # If no specific override, use the configuration's.
247
+ platform = configuration_platform
248
+ # Map from platform to architecture.
249
+ return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
250
+
251
+ def _TargetConfig(self, config):
252
+ """Returns the target-specific configuration."""
253
+ # There's two levels of architecture/platform specification in VS. The
254
+ # first level is globally for the configuration (this is what we consider
255
+ # "the" config at the gyp level, which will be something like 'Debug' or
256
+ # 'Release_x64'), and a second target-specific configuration, which is an
257
+ # override for the global one. |config| is remapped here to take into
258
+ # account the local target-specific overrides to the global configuration.
259
+ arch = self.GetArch(config)
260
+ if arch == 'x64' and not config.endswith('_x64'):
261
+ config += '_x64'
262
+ if arch == 'x86' and config.endswith('_x64'):
263
+ config = config.rsplit('_', 1)[0]
264
+ return config
265
+
266
+ def _Setting(self, path, config,
267
+ default=None, prefix='', append=None, map=None):
268
+ """_GetAndMunge for msvs_settings."""
269
+ return self._GetAndMunge(
270
+ self.msvs_settings[config], path, default, prefix, append, map)
271
+
272
+ def _ConfigAttrib(self, path, config,
273
+ default=None, prefix='', append=None, map=None):
274
+ """_GetAndMunge for msvs_configuration_attributes."""
275
+ return self._GetAndMunge(
276
+ self.msvs_configuration_attributes[config],
277
+ path, default, prefix, append, map)
278
+
279
+ def AdjustIncludeDirs(self, include_dirs, config):
280
+ """Updates include_dirs to expand VS specific paths, and adds the system
281
+ include dirs used for platform SDK and similar."""
282
+ config = self._TargetConfig(config)
283
+ includes = include_dirs + self.msvs_system_include_dirs[config]
284
+ includes.extend(self._Setting(
285
+ ('VCCLCompilerTool', 'AdditionalIncludeDirectories'), config, default=[]))
286
+ return [self.ConvertVSMacros(p, config=config) for p in includes]
287
+
288
+ def GetComputedDefines(self, config):
289
+ """Returns the set of defines that are injected to the defines list based
290
+ on other VS settings."""
291
+ config = self._TargetConfig(config)
292
+ defines = []
293
+ if self._ConfigAttrib(['CharacterSet'], config) == '1':
294
+ defines.extend(('_UNICODE', 'UNICODE'))
295
+ if self._ConfigAttrib(['CharacterSet'], config) == '2':
296
+ defines.append('_MBCS')
297
+ defines.extend(self._Setting(
298
+ ('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[]))
299
+ return defines
300
+
301
+ def GetCompilerPdbName(self, config, expand_special):
302
+ """Get the pdb file name that should be used for compiler invocations, or
303
+ None if there's no explicit name specified."""
304
+ config = self._TargetConfig(config)
305
+ pdbname = self._Setting(
306
+ ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config)
307
+ if pdbname:
308
+ pdbname = expand_special(self.ConvertVSMacros(pdbname))
309
+ return pdbname
310
+
311
+ def GetMapFileName(self, config, expand_special):
312
+ """Gets the explicitly overriden map file name for a target or returns None
313
+ if it's not set."""
314
+ config = self._TargetConfig(config)
315
+ map_file = self._Setting(('VCLinkerTool', 'MapFileName'), config)
316
+ if map_file:
317
+ map_file = expand_special(self.ConvertVSMacros(map_file, config=config))
318
+ return map_file
319
+
320
+ def GetOutputName(self, config, expand_special):
321
+ """Gets the explicitly overridden output name for a target or returns None
322
+ if it's not overridden."""
323
+ config = self._TargetConfig(config)
324
+ type = self.spec['type']
325
+ root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool'
326
+ # TODO(scottmg): Handle OutputDirectory without OutputFile.
327
+ output_file = self._Setting((root, 'OutputFile'), config)
328
+ if output_file:
329
+ output_file = expand_special(self.ConvertVSMacros(
330
+ output_file, config=config))
331
+ return output_file
332
+
333
+ def GetPDBName(self, config, expand_special, default):
334
+ """Gets the explicitly overridden pdb name for a target or returns
335
+ default if it's not overridden, or if no pdb will be generated."""
336
+ config = self._TargetConfig(config)
337
+ output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config)
338
+ generate_debug_info = self._Setting(
339
+ ('VCLinkerTool', 'GenerateDebugInformation'), config)
340
+ if generate_debug_info:
341
+ if output_file:
342
+ return expand_special(self.ConvertVSMacros(output_file, config=config))
343
+ else:
344
+ return default
345
+ else:
346
+ return None
347
+
348
+ def GetCflags(self, config):
349
+ """Returns the flags that need to be added to .c and .cc compilations."""
350
+ config = self._TargetConfig(config)
351
+ cflags = []
352
+ cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
353
+ cl = self._GetWrapper(self, self.msvs_settings[config],
354
+ 'VCCLCompilerTool', append=cflags)
355
+ cl('Optimization',
356
+ map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O', default='2')
357
+ cl('InlineFunctionExpansion', prefix='/Ob')
358
+ cl('DisableSpecificWarnings', prefix='/wd')
359
+ cl('StringPooling', map={'true': '/GF'})
360
+ cl('EnableFiberSafeOptimizations', map={'true': '/GT'})
361
+ cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
362
+ cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi')
363
+ cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
364
+ cl('WholeProgramOptimization', map={'true': '/GL'})
365
+ cl('WarningLevel', prefix='/W')
366
+ cl('WarnAsError', map={'true': '/WX'})
367
+ cl('DebugInformationFormat',
368
+ map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z')
369
+ cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
370
+ cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
371
+ cl('MinimalRebuild', map={'true': '/Gm'})
372
+ cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
373
+ cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
374
+ cl('RuntimeLibrary',
375
+ map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
376
+ cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
377
+ cl('DefaultCharIsUnsigned', map={'true': '/J'})
378
+ cl('TreatWChar_tAsBuiltInType',
379
+ map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t')
380
+ cl('EnablePREfast', map={'true': '/analyze'})
381
+ cl('AdditionalOptions', prefix='')
382
+ cflags.extend(['/FI' + f for f in self._Setting(
383
+ ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
384
+ if self.vs_version.short_name in ('2013', '2013e'):
385
+ # New flag required in 2013 to maintain previous PDB behavior.
386
+ cflags.append('/FS')
387
+ # ninja handles parallelism by itself, don't have the compiler do it too.
388
+ cflags = filter(lambda x: not x.startswith('/MP'), cflags)
389
+ return cflags
390
+
391
+ def GetPrecompiledHeader(self, config, gyp_to_build_path):
392
+ """Returns an object that handles the generation of precompiled header
393
+ build steps."""
394
+ config = self._TargetConfig(config)
395
+ return _PchHelper(self, config, gyp_to_build_path)
396
+
397
+ def _GetPchFlags(self, config, extension):
398
+ """Get the flags to be added to the cflags for precompiled header support.
399
+ """
400
+ config = self._TargetConfig(config)
401
+ # The PCH is only built once by a particular source file. Usage of PCH must
402
+ # only be for the same language (i.e. C vs. C++), so only include the pch
403
+ # flags when the language matches.
404
+ if self.msvs_precompiled_header[config]:
405
+ source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
406
+ if _LanguageMatchesForPch(source_ext, extension):
407
+ pch = os.path.split(self.msvs_precompiled_header[config])[1]
408
+ return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch']
409
+ return []
410
+
411
+ def GetCflagsC(self, config):
412
+ """Returns the flags that need to be added to .c compilations."""
413
+ config = self._TargetConfig(config)
414
+ return self._GetPchFlags(config, '.c')
415
+
416
+ def GetCflagsCC(self, config):
417
+ """Returns the flags that need to be added to .cc compilations."""
418
+ config = self._TargetConfig(config)
419
+ return ['/TP'] + self._GetPchFlags(config, '.cc')
420
+
421
+ def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path):
422
+ """Get and normalize the list of paths in AdditionalLibraryDirectories
423
+ setting."""
424
+ config = self._TargetConfig(config)
425
+ libpaths = self._Setting((root, 'AdditionalLibraryDirectories'),
426
+ config, default=[])
427
+ libpaths = [os.path.normpath(
428
+ gyp_to_build_path(self.ConvertVSMacros(p, config=config)))
429
+ for p in libpaths]
430
+ return ['/LIBPATH:"' + p + '"' for p in libpaths]
431
+
432
+ def GetLibFlags(self, config, gyp_to_build_path):
433
+ """Returns the flags that need to be added to lib commands."""
434
+ config = self._TargetConfig(config)
435
+ libflags = []
436
+ lib = self._GetWrapper(self, self.msvs_settings[config],
437
+ 'VCLibrarianTool', append=libflags)
438
+ libflags.extend(self._GetAdditionalLibraryDirectories(
439
+ 'VCLibrarianTool', config, gyp_to_build_path))
440
+ lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
441
+ lib('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
442
+ lib('AdditionalOptions')
443
+ return libflags
444
+
445
+ def GetDefFile(self, gyp_to_build_path):
446
+ """Returns the .def file from sources, if any. Otherwise returns None."""
447
+ spec = self.spec
448
+ if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
449
+ def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
450
+ if len(def_files) == 1:
451
+ return gyp_to_build_path(def_files[0])
452
+ elif len(def_files) > 1:
453
+ raise Exception("Multiple .def files")
454
+ return None
455
+
456
+ def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
457
+ """.def files get implicitly converted to a ModuleDefinitionFile for the
458
+ linker in the VS generator. Emulate that behaviour here."""
459
+ def_file = self.GetDefFile(gyp_to_build_path)
460
+ if def_file:
461
+ ldflags.append('/DEF:"%s"' % def_file)
462
+
463
+ def GetPGDName(self, config, expand_special):
464
+ """Gets the explicitly overridden pgd name for a target or returns None
465
+ if it's not overridden."""
466
+ config = self._TargetConfig(config)
467
+ output_file = self._Setting(
468
+ ('VCLinkerTool', 'ProfileGuidedDatabase'), config)
469
+ if output_file:
470
+ output_file = expand_special(self.ConvertVSMacros(
471
+ output_file, config=config))
472
+ return output_file
473
+
474
+ def GetLdflags(self, config, gyp_to_build_path, expand_special,
475
+ manifest_base_name, output_name, is_executable, build_dir):
476
+ """Returns the flags that need to be added to link commands, and the
477
+ manifest files."""
478
+ config = self._TargetConfig(config)
479
+ ldflags = []
480
+ ld = self._GetWrapper(self, self.msvs_settings[config],
481
+ 'VCLinkerTool', append=ldflags)
482
+ self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
483
+ ld('GenerateDebugInformation', map={'true': '/DEBUG'})
484
+ ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
485
+ ldflags.extend(self._GetAdditionalLibraryDirectories(
486
+ 'VCLinkerTool', config, gyp_to_build_path))
487
+ ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
488
+ ld('TreatLinkerWarningAsErrors', prefix='/WX',
489
+ map={'true': '', 'false': ':NO'})
490
+ out = self.GetOutputName(config, expand_special)
491
+ if out:
492
+ ldflags.append('/OUT:' + out)
493
+ pdb = self.GetPDBName(config, expand_special, output_name + '.pdb')
494
+ if pdb:
495
+ ldflags.append('/PDB:' + pdb)
496
+ pgd = self.GetPGDName(config, expand_special)
497
+ if pgd:
498
+ ldflags.append('/PGD:' + pgd)
499
+ map_file = self.GetMapFileName(config, expand_special)
500
+ ld('GenerateMapFile', map={'true': '/MAP:' + map_file if map_file
501
+ else '/MAP'})
502
+ ld('MapExports', map={'true': '/MAPINFO:EXPORTS'})
503
+ ld('AdditionalOptions', prefix='')
504
+
505
+ minimum_required_version = self._Setting(
506
+ ('VCLinkerTool', 'MinimumRequiredVersion'), config, default='')
507
+ if minimum_required_version:
508
+ minimum_required_version = ',' + minimum_required_version
509
+ ld('SubSystem',
510
+ map={'1': 'CONSOLE%s' % minimum_required_version,
511
+ '2': 'WINDOWS%s' % minimum_required_version},
512
+ prefix='/SUBSYSTEM:')
513
+
514
+ ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
515
+ ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
516
+ ld('BaseAddress', prefix='/BASE:')
517
+ ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
518
+ ld('RandomizedBaseAddress',
519
+ map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE')
520
+ ld('DataExecutionPrevention',
521
+ map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
522
+ ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
523
+ ld('ForceSymbolReferences', prefix='/INCLUDE:')
524
+ ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
525
+ ld('LinkTimeCodeGeneration',
526
+ map={'1': '', '2': ':PGINSTRUMENT', '3': ':PGOPTIMIZE',
527
+ '4': ':PGUPDATE'},
528
+ prefix='/LTCG')
529
+ ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
530
+ ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
531
+ ld('EntryPointSymbol', prefix='/ENTRY:')
532
+ ld('Profile', map={'true': '/PROFILE'})
533
+ ld('LargeAddressAware',
534
+ map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
535
+ # TODO(scottmg): This should sort of be somewhere else (not really a flag).
536
+ ld('AdditionalDependencies', prefix='')
537
+
538
+ # If the base address is not specifically controlled, DYNAMICBASE should
539
+ # be on by default.
540
+ base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
541
+ ldflags)
542
+ if not base_flags:
543
+ ldflags.append('/DYNAMICBASE')
544
+
545
+ # If the NXCOMPAT flag has not been specified, default to on. Despite the
546
+ # documentation that says this only defaults to on when the subsystem is
547
+ # Vista or greater (which applies to the linker), the IDE defaults it on
548
+ # unless it's explicitly off.
549
+ if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
550
+ ldflags.append('/NXCOMPAT')
551
+
552
+ have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
553
+ manifest_flags, intermediate_manifest, manifest_files = \
554
+ self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
555
+ is_executable and not have_def_file, build_dir)
556
+ ldflags.extend(manifest_flags)
557
+ return ldflags, intermediate_manifest, manifest_files
558
+
559
+ def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
560
+ allow_isolation, build_dir):
561
+ """Returns a 3-tuple:
562
+ - the set of flags that need to be added to the link to generate
563
+ a default manifest
564
+ - the intermediate manifest that the linker will generate that should be
565
+ used to assert it doesn't add anything to the merged one.
566
+ - the list of all the manifest files to be merged by the manifest tool and
567
+ included into the link."""
568
+ generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'),
569
+ config,
570
+ default='true')
571
+ if generate_manifest != 'true':
572
+ # This means not only that the linker should not generate the intermediate
573
+ # manifest but also that the manifest tool should do nothing even when
574
+ # additional manifests are specified.
575
+ return ['/MANIFEST:NO'], [], []
576
+
577
+ output_name = name + '.intermediate.manifest'
578
+ flags = [
579
+ '/MANIFEST',
580
+ '/ManifestFile:' + output_name,
581
+ ]
582
+
583
+ # Instead of using the MANIFESTUAC flags, we generate a .manifest to
584
+ # include into the list of manifests. This allows us to avoid the need to
585
+ # do two passes during linking. The /MANIFEST flag and /ManifestFile are
586
+ # still used, and the intermediate manifest is used to assert that the
587
+ # final manifest we get from merging all the additional manifest files
588
+ # (plus the one we generate here) isn't modified by merging the
589
+ # intermediate into it.
590
+
591
+ # Always NO, because we generate a manifest file that has what we want.
592
+ flags.append('/MANIFESTUAC:NO')
593
+
594
+ config = self._TargetConfig(config)
595
+ enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config,
596
+ default='true')
597
+ manifest_files = []
598
+ generated_manifest_outer = \
599
+ "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \
600
+ "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \
601
+ "</assembly>"
602
+ if enable_uac == 'true':
603
+ execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'),
604
+ config, default='0')
605
+ execution_level_map = {
606
+ '0': 'asInvoker',
607
+ '1': 'highestAvailable',
608
+ '2': 'requireAdministrator'
609
+ }
610
+
611
+ ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config,
612
+ default='false')
613
+
614
+ inner = '''
615
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
616
+ <security>
617
+ <requestedPrivileges>
618
+ <requestedExecutionLevel level='%s' uiAccess='%s' />
619
+ </requestedPrivileges>
620
+ </security>
621
+ </trustInfo>''' % (execution_level_map[execution_level], ui_access)
622
+ else:
623
+ inner = ''
624
+
625
+ generated_manifest_contents = generated_manifest_outer % inner
626
+ generated_name = name + '.generated.manifest'
627
+ # Need to join with the build_dir here as we're writing it during
628
+ # generation time, but we return the un-joined version because the build
629
+ # will occur in that directory. We only write the file if the contents
630
+ # have changed so that simply regenerating the project files doesn't
631
+ # cause a relink.
632
+ build_dir_generated_name = os.path.join(build_dir, generated_name)
633
+ gyp.common.EnsureDirExists(build_dir_generated_name)
634
+ f = gyp.common.WriteOnDiff(build_dir_generated_name)
635
+ f.write(generated_manifest_contents)
636
+ f.close()
637
+ manifest_files = [generated_name]
638
+
639
+ if allow_isolation:
640
+ flags.append('/ALLOWISOLATION')
641
+
642
+ manifest_files += self._GetAdditionalManifestFiles(config,
643
+ gyp_to_build_path)
644
+ return flags, output_name, manifest_files
645
+
646
+ def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
647
+ """Gets additional manifest files that are added to the default one
648
+ generated by the linker."""
649
+ files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config,
650
+ default=[])
651
+ if isinstance(files, str):
652
+ files = files.split(';')
653
+ return [os.path.normpath(
654
+ gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
655
+ for f in files]
656
+
657
+ def IsUseLibraryDependencyInputs(self, config):
658
+ """Returns whether the target should be linked via Use Library Dependency
659
+ Inputs (using component .objs of a given .lib)."""
660
+ config = self._TargetConfig(config)
661
+ uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config)
662
+ return uldi == 'true'
663
+
664
+ def IsEmbedManifest(self, config):
665
+ """Returns whether manifest should be linked into binary."""
666
+ config = self._TargetConfig(config)
667
+ embed = self._Setting(('VCManifestTool', 'EmbedManifest'), config,
668
+ default='true')
669
+ return embed == 'true'
670
+
671
+ def IsLinkIncremental(self, config):
672
+ """Returns whether the target should be linked incrementally."""
673
+ config = self._TargetConfig(config)
674
+ link_inc = self._Setting(('VCLinkerTool', 'LinkIncremental'), config)
675
+ return link_inc != '1'
676
+
677
+ def GetRcflags(self, config, gyp_to_ninja_path):
678
+ """Returns the flags that need to be added to invocations of the resource
679
+ compiler."""
680
+ config = self._TargetConfig(config)
681
+ rcflags = []
682
+ rc = self._GetWrapper(self, self.msvs_settings[config],
683
+ 'VCResourceCompilerTool', append=rcflags)
684
+ rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I')
685
+ rcflags.append('/I' + gyp_to_ninja_path('.'))
686
+ rc('PreprocessorDefinitions', prefix='/d')
687
+ # /l arg must be in hex without leading '0x'
688
+ rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:])
689
+ return rcflags
690
+
691
+ def BuildCygwinBashCommandLine(self, args, path_to_base):
692
+ """Build a command line that runs args via cygwin bash. We assume that all
693
+ incoming paths are in Windows normpath'd form, so they need to be
694
+ converted to posix style for the part of the command line that's passed to
695
+ bash. We also have to do some Visual Studio macro emulation here because
696
+ various rules use magic VS names for things. Also note that rules that
697
+ contain ninja variables cannot be fixed here (for example ${source}), so
698
+ the outer generator needs to make sure that the paths that are written out
699
+ are in posix style, if the command line will be used here."""
700
+ cygwin_dir = os.path.normpath(
701
+ os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
702
+ cd = ('cd %s' % path_to_base).replace('\\', '/')
703
+ args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
704
+ args = ["'%s'" % a.replace("'", "'\\''") for a in args]
705
+ bash_cmd = ' '.join(args)
706
+ cmd = (
707
+ 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
708
+ 'bash -c "%s ; %s"' % (cd, bash_cmd))
709
+ return cmd
710
+
711
+ def IsRuleRunUnderCygwin(self, rule):
712
+ """Determine if an action should be run under cygwin. If the variable is
713
+ unset, or set to 1 we use cygwin."""
714
+ return int(rule.get('msvs_cygwin_shell',
715
+ self.spec.get('msvs_cygwin_shell', 1))) != 0
716
+
717
+ def _HasExplicitRuleForExtension(self, spec, extension):
718
+ """Determine if there's an explicit rule for a particular extension."""
719
+ for rule in spec.get('rules', []):
720
+ if rule['extension'] == extension:
721
+ return True
722
+ return False
723
+
724
+ def HasExplicitIdlRules(self, spec):
725
+ """Determine if there's an explicit rule for idl files. When there isn't we
726
+ need to generate implicit rules to build MIDL .idl files."""
727
+ return self._HasExplicitRuleForExtension(spec, 'idl')
728
+
729
+ def HasExplicitAsmRules(self, spec):
730
+ """Determine if there's an explicit rule for asm files. When there isn't we
731
+ need to generate implicit rules to assemble .asm files."""
732
+ return self._HasExplicitRuleForExtension(spec, 'asm')
733
+
734
+ def GetIdlBuildData(self, source, config):
735
+ """Determine the implicit outputs for an idl file. Returns output
736
+ directory, outputs, and variables and flags that are required."""
737
+ config = self._TargetConfig(config)
738
+ midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool')
739
+ def midl(name, default=None):
740
+ return self.ConvertVSMacros(midl_get(name, default=default),
741
+ config=config)
742
+ tlb = midl('TypeLibraryName', default='${root}.tlb')
743
+ header = midl('HeaderFileName', default='${root}.h')
744
+ dlldata = midl('DLLDataFileName', default='dlldata.c')
745
+ iid = midl('InterfaceIdentifierFileName', default='${root}_i.c')
746
+ proxy = midl('ProxyFileName', default='${root}_p.c')
747
+ # Note that .tlb is not included in the outputs as it is not always
748
+ # generated depending on the content of the input idl file.
749
+ outdir = midl('OutputDirectory', default='')
750
+ output = [header, dlldata, iid, proxy]
751
+ variables = [('tlb', tlb),
752
+ ('h', header),
753
+ ('dlldata', dlldata),
754
+ ('iid', iid),
755
+ ('proxy', proxy)]
756
+ # TODO(scottmg): Are there configuration settings to set these flags?
757
+ target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
758
+ flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
759
+ return outdir, output, variables, flags
760
+
761
+
762
+ def _LanguageMatchesForPch(source_ext, pch_source_ext):
763
+ c_exts = ('.c',)
764
+ cc_exts = ('.cc', '.cxx', '.cpp')
765
+ return ((source_ext in c_exts and pch_source_ext in c_exts) or
766
+ (source_ext in cc_exts and pch_source_ext in cc_exts))
767
+
768
+
769
+ class PrecompiledHeader(object):
770
+ """Helper to generate dependencies and build rules to handle generation of
771
+ precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
772
+ """
773
+ def __init__(
774
+ self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext):
775
+ self.settings = settings
776
+ self.config = config
777
+ pch_source = self.settings.msvs_precompiled_source[self.config]
778
+ self.pch_source = gyp_to_build_path(pch_source)
779
+ filename, _ = os.path.splitext(pch_source)
780
+ self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
781
+
782
+ def _PchHeader(self):
783
+ """Get the header that will appear in an #include line for all source
784
+ files."""
785
+ return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
786
+
787
+ def GetObjDependencies(self, sources, objs, arch):
788
+ """Given a list of sources files and the corresponding object files,
789
+ returns a list of the pch files that should be depended upon. The
790
+ additional wrapping in the return value is for interface compatability
791
+ with make.py on Mac, and xcode_emulation.py."""
792
+ assert arch is None
793
+ if not self._PchHeader():
794
+ return []
795
+ pch_ext = os.path.splitext(self.pch_source)[1]
796
+ for source in sources:
797
+ if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
798
+ return [(None, None, self.output_obj)]
799
+ return []
800
+
801
+ def GetPchBuildCommands(self, arch):
802
+ """Not used on Windows as there are no additional build steps required
803
+ (instead, existing steps are modified in GetFlagsModifications below)."""
804
+ return []
805
+
806
+ def GetFlagsModifications(self, input, output, implicit, command,
807
+ cflags_c, cflags_cc, expand_special):
808
+ """Get the modified cflags and implicit dependencies that should be used
809
+ for the pch compilation step."""
810
+ if input == self.pch_source:
811
+ pch_output = ['/Yc' + self._PchHeader()]
812
+ if command == 'cxx':
813
+ return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
814
+ self.output_obj, [])
815
+ elif command == 'cc':
816
+ return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
817
+ self.output_obj, [])
818
+ return [], output, implicit
819
+
820
+
821
+ vs_version = None
822
+ def GetVSVersion(generator_flags):
823
+ global vs_version
824
+ if not vs_version:
825
+ vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
826
+ generator_flags.get('msvs_version', 'auto'))
827
+ return vs_version
828
+
829
+ def _GetVsvarsSetupArgs(generator_flags, arch):
830
+ vs = GetVSVersion(generator_flags)
831
+ return vs.SetupScript()
832
+
833
+ def ExpandMacros(string, expansions):
834
+ """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
835
+ for the canonical way to retrieve a suitable dict."""
836
+ if '$' in string:
837
+ for old, new in expansions.iteritems():
838
+ assert '$(' not in new, new
839
+ string = string.replace(old, new)
840
+ return string
841
+
842
+ def _ExtractImportantEnvironment(output_of_set):
843
+ """Extracts environment variables required for the toolchain to run from
844
+ a textual dump output by the cmd.exe 'set' command."""
845
+ envvars_to_save = (
846
+ 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
847
+ 'include',
848
+ 'lib',
849
+ 'libpath',
850
+ 'path',
851
+ 'pathext',
852
+ 'systemroot',
853
+ 'temp',
854
+ 'tmp',
855
+ )
856
+ env = {}
857
+ for line in output_of_set.splitlines():
858
+ for envvar in envvars_to_save:
859
+ if re.match(envvar + '=', line.lower()):
860
+ var, setting = line.split('=', 1)
861
+ if envvar == 'path':
862
+ # Our own rules (for running gyp-win-tool) and other actions in
863
+ # Chromium rely on python being in the path. Add the path to this
864
+ # python here so that if it's not in the path when ninja is run
865
+ # later, python will still be found.
866
+ setting = os.path.dirname(sys.executable) + os.pathsep + setting
867
+ env[var.upper()] = setting
868
+ break
869
+ for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
870
+ if required not in env:
871
+ raise Exception('Environment variable "%s" '
872
+ 'required to be set to valid path' % required)
873
+ return env
874
+
875
+ def _FormatAsEnvironmentBlock(envvar_dict):
876
+ """Format as an 'environment block' directly suitable for CreateProcess.
877
+ Briefly this is a list of key=value\0, terminated by an additional \0. See
878
+ CreateProcess documentation for more details."""
879
+ block = ''
880
+ nul = '\0'
881
+ for key, value in envvar_dict.iteritems():
882
+ block += key + '=' + value + nul
883
+ block += nul
884
+ return block
885
+
886
+ def _ExtractCLPath(output_of_where):
887
+ """Gets the path to cl.exe based on the output of calling the environment
888
+ setup batch file, followed by the equivalent of `where`."""
889
+ # Take the first line, as that's the first found in the PATH.
890
+ for line in output_of_where.strip().splitlines():
891
+ if line.startswith('LOC:'):
892
+ return line[len('LOC:'):].strip()
893
+
894
+ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out):
895
+ """It's not sufficient to have the absolute path to the compiler, linker,
896
+ etc. on Windows, as those tools rely on .dlls being in the PATH. We also
897
+ need to support both x86 and x64 compilers within the same build (to support
898
+ msvs_target_platform hackery). Different architectures require a different
899
+ compiler binary, and different supporting environment variables (INCLUDE,
900
+ LIB, LIBPATH). So, we extract the environment here, wrap all invocations
901
+ of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
902
+ sets up the environment, and then we do not prefix the compiler with
903
+ an absolute path, instead preferring something like "cl.exe" in the rule
904
+ which will then run whichever the environment setup has put in the path.
905
+ When the following procedure to generate environment files does not
906
+ meet your requirement (e.g. for custom toolchains), you can pass
907
+ "-G ninja_use_custom_environment_files" to the gyp to suppress file
908
+ generation and use custom environment files prepared by yourself."""
909
+ archs = ('x86', 'x64')
910
+ if generator_flags.get('ninja_use_custom_environment_files', 0):
911
+ cl_paths = {}
912
+ for arch in archs:
913
+ cl_paths[arch] = 'cl.exe'
914
+ return cl_paths
915
+ vs = GetVSVersion(generator_flags)
916
+ cl_paths = {}
917
+ for arch in archs:
918
+ # Extract environment variables for subprocesses.
919
+ args = vs.SetupScript(arch)
920
+ args.extend(('&&', 'set'))
921
+ popen = subprocess.Popen(
922
+ args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
923
+ variables, _ = popen.communicate()
924
+ env = _ExtractImportantEnvironment(variables)
925
+ env_block = _FormatAsEnvironmentBlock(env)
926
+ f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
927
+ f.write(env_block)
928
+ f.close()
929
+
930
+ # Find cl.exe location for this architecture.
931
+ args = vs.SetupScript(arch)
932
+ args.extend(('&&',
933
+ 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
934
+ popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
935
+ output, _ = popen.communicate()
936
+ cl_paths[arch] = _ExtractCLPath(output)
937
+ return cl_paths
938
+
939
+ def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
940
+ """Emulate behavior of msvs_error_on_missing_sources present in the msvs
941
+ generator: Check that all regular source files, i.e. not created at run time,
942
+ exist on disk. Missing files cause needless recompilation when building via
943
+ VS, and we want this check to match for people/bots that build using ninja,
944
+ so they're not surprised when the VS build fails."""
945
+ if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
946
+ no_specials = filter(lambda x: '$' not in x, sources)
947
+ relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
948
+ missing = filter(lambda x: not os.path.exists(x), relative)
949
+ if missing:
950
+ # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
951
+ # path for a slightly less crazy looking output.
952
+ cleaned_up = [os.path.normpath(x) for x in missing]
953
+ raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
954
+
955
+ # Sets some values in default_variables, which are required for many
956
+ # generators, run on Windows.
957
+ def CalculateCommonVariables(default_variables, params):
958
+ generator_flags = params.get('generator_flags', {})
959
+
960
+ # Set a variable so conditions can be based on msvs_version.
961
+ msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
962
+ default_variables['MSVS_VERSION'] = msvs_version.ShortName()
963
+
964
+ # To determine processor word size on Windows, in addition to checking
965
+ # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
966
+ # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
967
+ # contains the actual word size of the system when running thru WOW64).
968
+ if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
969
+ '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
970
+ default_variables['MSVS_OS_BITS'] = 64
971
+ else:
972
+ default_variables['MSVS_OS_BITS'] = 32