source: trip-planner-front/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py@ 84d0fbb

Last change on this file since 84d0fbb was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 52.0 KB
Line 
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"""
6This module helps emulate Visual Studio 2008 behavior on top of other
7build systems, primarily ninja.
8"""
9
10import os
11import re
12import subprocess
13import sys
14
15from gyp.common import OrderedSet
16import gyp.MSVSUtil
17import gyp.MSVSVersion
18
19PY3 = bytes != str
20
21windows_quoter_regex = re.compile(r'(\\*)"')
22
23
24def QuoteForRspFile(arg):
25 """Quote a command line argument so that it appears as one argument when
26 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
27 Windows programs)."""
28 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
29 # threads. This is actually the quoting rules for CommandLineToArgvW, not
30 # for the shell, because the shell doesn't do anything in Windows. This
31 # works more or less because most programs (including the compiler, etc.)
32 # use that function to handle command line arguments.
33
34 # Use a heuristic to try to find args that are paths, and normalize them
35 if arg.find("/") > 0 or arg.count("/") > 1:
36 arg = os.path.normpath(arg)
37
38 # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
39 # preceding it, and results in n backslashes + the quote. So we substitute
40 # in 2* what we match, +1 more, plus the quote.
41 arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
42
43 # %'s also need to be doubled otherwise they're interpreted as batch
44 # positional arguments. Also make sure to escape the % so that they're
45 # passed literally through escaping so they can be singled to just the
46 # original %. Otherwise, trying to pass the literal representation that
47 # looks like an environment variable to the shell (e.g. %PATH%) would fail.
48 arg = arg.replace("%", "%%")
49
50 # These commands are used in rsp files, so no escaping for the shell (via ^)
51 # is necessary.
52
53 # Finally, wrap the whole thing in quotes so that the above quote rule
54 # applies and whitespace isn't a word break.
55 return '"' + arg + '"'
56
57
58def EncodeRspFileList(args):
59 """Process a list of arguments using QuoteCmdExeArgument."""
60 # Note that the first argument is assumed to be the command. Don't add
61 # quotes around it because then built-ins like 'echo', etc. won't work.
62 # Take care to normpath only the path in the case of 'call ../x.bat' because
63 # otherwise the whole thing is incorrectly interpreted as a path and not
64 # normalized correctly.
65 if not args:
66 return ""
67 if args[0].startswith("call "):
68 call, program = args[0].split(" ", 1)
69 program = call + " " + os.path.normpath(program)
70 else:
71 program = os.path.normpath(args[0])
72 return program + " " + " ".join(QuoteForRspFile(arg) for arg in args[1:])
73
74
75def _GenericRetrieve(root, default, path):
76 """Given a list of dictionary keys |path| and a tree of dicts |root|, find
77 value at path, or return |default| if any of the path doesn't exist."""
78 if not root:
79 return default
80 if not path:
81 return root
82 return _GenericRetrieve(root.get(path[0]), default, path[1:])
83
84
85def _AddPrefix(element, prefix):
86 """Add |prefix| to |element| or each subelement if element is iterable."""
87 if element is None:
88 return element
89 # Note, not Iterable because we don't want to handle strings like that.
90 if isinstance(element, list) or isinstance(element, tuple):
91 return [prefix + e for e in element]
92 else:
93 return prefix + element
94
95
96def _DoRemapping(element, map):
97 """If |element| then remap it through |map|. If |element| is iterable then
98 each item will be remapped. Any elements not found will be removed."""
99 if map is not None and element is not None:
100 if not callable(map):
101 map = map.get # Assume it's a dict, otherwise a callable to do the remap.
102 if isinstance(element, list) or isinstance(element, tuple):
103 element = filter(None, [map(elem) for elem in element])
104 else:
105 element = map(element)
106 return element
107
108
109def _AppendOrReturn(append, element):
110 """If |append| is None, simply return |element|. If |append| is not None,
111 then add |element| to it, adding each item in |element| if it's a list or
112 tuple."""
113 if append is not None and element is not None:
114 if isinstance(element, list) or isinstance(element, tuple):
115 append.extend(element)
116 else:
117 append.append(element)
118 else:
119 return element
120
121
122def _FindDirectXInstallation():
123 """Try to find an installation location for the DirectX SDK. Check for the
124 standard environment variable, and if that doesn't exist, try to find
125 via the registry. May return None if not found in either location."""
126 # Return previously calculated value, if there is one
127 if hasattr(_FindDirectXInstallation, "dxsdk_dir"):
128 return _FindDirectXInstallation.dxsdk_dir
129
130 dxsdk_dir = os.environ.get("DXSDK_DIR")
131 if not dxsdk_dir:
132 # Setup params to pass to and attempt to launch reg.exe.
133 cmd = ["reg.exe", "query", r"HKLM\Software\Microsoft\DirectX", "/s"]
134 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
135 stdout = p.communicate()[0]
136 if PY3:
137 stdout = stdout.decode("utf-8")
138 for line in stdout.splitlines():
139 if "InstallPath" in line:
140 dxsdk_dir = line.split(" ")[3] + "\\"
141
142 # Cache return value
143 _FindDirectXInstallation.dxsdk_dir = dxsdk_dir
144 return dxsdk_dir
145
146
147def GetGlobalVSMacroEnv(vs_version):
148 """Get a dict of variables mapping internal VS macro names to their gyp
149 equivalents. Returns all variables that are independent of the target."""
150 env = {}
151 # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
152 # Visual Studio is actually installed.
153 if vs_version.Path():
154 env["$(VSInstallDir)"] = vs_version.Path()
155 env["$(VCInstallDir)"] = os.path.join(vs_version.Path(), "VC") + "\\"
156 # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
157 # set. This happens when the SDK is sync'd via src-internal, rather than
158 # by typical end-user installation of the SDK. If it's not set, we don't
159 # want to leave the unexpanded variable in the path, so simply strip it.
160 dxsdk_dir = _FindDirectXInstallation()
161 env["$(DXSDK_DIR)"] = dxsdk_dir if dxsdk_dir else ""
162 # Try to find an installation location for the Windows DDK by checking
163 # the WDK_DIR environment variable, may be None.
164 env["$(WDK_DIR)"] = os.environ.get("WDK_DIR", "")
165 return env
166
167
168def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
169 """Finds msvs_system_include_dirs that are common to all targets, removes
170 them from all targets, and returns an OrderedSet containing them."""
171 all_system_includes = OrderedSet(configs[0].get("msvs_system_include_dirs", []))
172 for config in configs[1:]:
173 system_includes = config.get("msvs_system_include_dirs", [])
174 all_system_includes = all_system_includes & OrderedSet(system_includes)
175 if not all_system_includes:
176 return None
177 # Expand macros in all_system_includes.
178 env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags))
179 expanded_system_includes = OrderedSet(
180 [ExpandMacros(include, env) for include in all_system_includes]
181 )
182 if any(["$" in include for include in expanded_system_includes]):
183 # Some path relies on target-specific variables, bail.
184 return None
185
186 # Remove system includes shared by all targets from the targets.
187 for config in configs:
188 includes = config.get("msvs_system_include_dirs", [])
189 if includes: # Don't insert a msvs_system_include_dirs key if not needed.
190 # This must check the unexpanded includes list:
191 new_includes = [i for i in includes if i not in all_system_includes]
192 config["msvs_system_include_dirs"] = new_includes
193 return expanded_system_includes
194
195
196class MsvsSettings(object):
197 """A class that understands the gyp 'msvs_...' values (especially the
198 msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
199 class helps map those settings to command line options."""
200
201 def __init__(self, spec, generator_flags):
202 self.spec = spec
203 self.vs_version = GetVSVersion(generator_flags)
204
205 supported_fields = [
206 ("msvs_configuration_attributes", dict),
207 ("msvs_settings", dict),
208 ("msvs_system_include_dirs", list),
209 ("msvs_disabled_warnings", list),
210 ("msvs_precompiled_header", str),
211 ("msvs_precompiled_source", str),
212 ("msvs_configuration_platform", str),
213 ("msvs_target_platform", str),
214 ]
215 configs = spec["configurations"]
216 for field, default in supported_fields:
217 setattr(self, field, {})
218 for configname, config in configs.items():
219 getattr(self, field)[configname] = config.get(field, default())
220
221 self.msvs_cygwin_dirs = spec.get("msvs_cygwin_dirs", ["."])
222
223 unsupported_fields = [
224 "msvs_prebuild",
225 "msvs_postbuild",
226 ]
227 unsupported = []
228 for field in unsupported_fields:
229 for config in configs.values():
230 if field in config:
231 unsupported += [
232 "%s not supported (target %s)." % (field, spec["target_name"])
233 ]
234 if unsupported:
235 raise Exception("\n".join(unsupported))
236
237 def GetExtension(self):
238 """Returns the extension for the target, with no leading dot.
239
240 Uses 'product_extension' if specified, otherwise uses MSVS defaults based on
241 the target type.
242 """
243 ext = self.spec.get("product_extension", None)
244 if ext:
245 return ext
246 return gyp.MSVSUtil.TARGET_TYPE_EXT.get(self.spec["type"], "")
247
248 def GetVSMacroEnv(self, base_to_build=None, config=None):
249 """Get a dict of variables mapping internal VS macro names to their gyp
250 equivalents."""
251 target_arch = self.GetArch(config)
252 if target_arch == "x86":
253 target_platform = "Win32"
254 else:
255 target_platform = target_arch
256 target_name = self.spec.get("product_prefix", "") + self.spec.get(
257 "product_name", self.spec["target_name"]
258 )
259 target_dir = base_to_build + "\\" if base_to_build else ""
260 target_ext = "." + self.GetExtension()
261 target_file_name = target_name + target_ext
262
263 replacements = {
264 "$(InputName)": "${root}",
265 "$(InputPath)": "${source}",
266 "$(IntDir)": "$!INTERMEDIATE_DIR",
267 "$(OutDir)\\": target_dir,
268 "$(PlatformName)": target_platform,
269 "$(ProjectDir)\\": "",
270 "$(ProjectName)": self.spec["target_name"],
271 "$(TargetDir)\\": target_dir,
272 "$(TargetExt)": target_ext,
273 "$(TargetFileName)": target_file_name,
274 "$(TargetName)": target_name,
275 "$(TargetPath)": os.path.join(target_dir, target_file_name),
276 }
277 replacements.update(GetGlobalVSMacroEnv(self.vs_version))
278 return replacements
279
280 def ConvertVSMacros(self, s, base_to_build=None, config=None):
281 """Convert from VS macro names to something equivalent."""
282 env = self.GetVSMacroEnv(base_to_build, config=config)
283 return ExpandMacros(s, env)
284
285 def AdjustLibraries(self, libraries):
286 """Strip -l from library if it's specified with that."""
287 libs = [lib[2:] if lib.startswith("-l") else lib for lib in libraries]
288 return [
289 lib + ".lib"
290 if not lib.lower().endswith(".lib") and not lib.lower().endswith(".obj")
291 else lib
292 for lib in libs
293 ]
294
295 def _GetAndMunge(self, field, path, default, prefix, append, map):
296 """Retrieve a value from |field| at |path| or return |default|. If
297 |append| is specified, and the item is found, it will be appended to that
298 object instead of returned. If |map| is specified, results will be
299 remapped through |map| before being returned or appended."""
300 result = _GenericRetrieve(field, default, path)
301 result = _DoRemapping(result, map)
302 result = _AddPrefix(result, prefix)
303 return _AppendOrReturn(append, result)
304
305 class _GetWrapper(object):
306 def __init__(self, parent, field, base_path, append=None):
307 self.parent = parent
308 self.field = field
309 self.base_path = [base_path]
310 self.append = append
311
312 def __call__(self, name, map=None, prefix="", default=None):
313 return self.parent._GetAndMunge(
314 self.field,
315 self.base_path + [name],
316 default=default,
317 prefix=prefix,
318 append=self.append,
319 map=map,
320 )
321
322 def GetArch(self, config):
323 """Get architecture based on msvs_configuration_platform and
324 msvs_target_platform. Returns either 'x86' or 'x64'."""
325 configuration_platform = self.msvs_configuration_platform.get(config, "")
326 platform = self.msvs_target_platform.get(config, "")
327 if not platform: # If no specific override, use the configuration's.
328 platform = configuration_platform
329 # Map from platform to architecture.
330 return {"Win32": "x86", "x64": "x64", "ARM64": "arm64"}.get(platform, "x86")
331
332 def _TargetConfig(self, config):
333 """Returns the target-specific configuration."""
334 # There's two levels of architecture/platform specification in VS. The
335 # first level is globally for the configuration (this is what we consider
336 # "the" config at the gyp level, which will be something like 'Debug' or
337 # 'Release'), VS2015 and later only use this level
338 if self.vs_version.short_name >= 2015:
339 return config
340 # and a second target-specific configuration, which is an
341 # override for the global one. |config| is remapped here to take into
342 # account the local target-specific overrides to the global configuration.
343 arch = self.GetArch(config)
344 if arch == "x64" and not config.endswith("_x64"):
345 config += "_x64"
346 if arch == "x86" and config.endswith("_x64"):
347 config = config.rsplit("_", 1)[0]
348 return config
349
350 def _Setting(self, path, config, default=None, prefix="", append=None, map=None):
351 """_GetAndMunge for msvs_settings."""
352 return self._GetAndMunge(
353 self.msvs_settings[config], path, default, prefix, append, map
354 )
355
356 def _ConfigAttrib(
357 self, path, config, default=None, prefix="", append=None, map=None
358 ):
359 """_GetAndMunge for msvs_configuration_attributes."""
360 return self._GetAndMunge(
361 self.msvs_configuration_attributes[config],
362 path,
363 default,
364 prefix,
365 append,
366 map,
367 )
368
369 def AdjustIncludeDirs(self, include_dirs, config):
370 """Updates include_dirs to expand VS specific paths, and adds the system
371 include dirs used for platform SDK and similar."""
372 config = self._TargetConfig(config)
373 includes = include_dirs + self.msvs_system_include_dirs[config]
374 includes.extend(
375 self._Setting(
376 ("VCCLCompilerTool", "AdditionalIncludeDirectories"), config, default=[]
377 )
378 )
379 return [self.ConvertVSMacros(p, config=config) for p in includes]
380
381 def AdjustMidlIncludeDirs(self, midl_include_dirs, config):
382 """Updates midl_include_dirs to expand VS specific paths, and adds the
383 system include dirs used for platform SDK and similar."""
384 config = self._TargetConfig(config)
385 includes = midl_include_dirs + self.msvs_system_include_dirs[config]
386 includes.extend(
387 self._Setting(
388 ("VCMIDLTool", "AdditionalIncludeDirectories"), config, default=[]
389 )
390 )
391 return [self.ConvertVSMacros(p, config=config) for p in includes]
392
393 def GetComputedDefines(self, config):
394 """Returns the set of defines that are injected to the defines list based
395 on other VS settings."""
396 config = self._TargetConfig(config)
397 defines = []
398 if self._ConfigAttrib(["CharacterSet"], config) == "1":
399 defines.extend(("_UNICODE", "UNICODE"))
400 if self._ConfigAttrib(["CharacterSet"], config) == "2":
401 defines.append("_MBCS")
402 defines.extend(
403 self._Setting(
404 ("VCCLCompilerTool", "PreprocessorDefinitions"), config, default=[]
405 )
406 )
407 return defines
408
409 def GetCompilerPdbName(self, config, expand_special):
410 """Get the pdb file name that should be used for compiler invocations, or
411 None if there's no explicit name specified."""
412 config = self._TargetConfig(config)
413 pdbname = self._Setting(("VCCLCompilerTool", "ProgramDataBaseFileName"), config)
414 if pdbname:
415 pdbname = expand_special(self.ConvertVSMacros(pdbname))
416 return pdbname
417
418 def GetMapFileName(self, config, expand_special):
419 """Gets the explicitly overridden map file name for a target or returns None
420 if it's not set."""
421 config = self._TargetConfig(config)
422 map_file = self._Setting(("VCLinkerTool", "MapFileName"), config)
423 if map_file:
424 map_file = expand_special(self.ConvertVSMacros(map_file, config=config))
425 return map_file
426
427 def GetOutputName(self, config, expand_special):
428 """Gets the explicitly overridden output name for a target or returns None
429 if it's not overridden."""
430 config = self._TargetConfig(config)
431 type = self.spec["type"]
432 root = "VCLibrarianTool" if type == "static_library" else "VCLinkerTool"
433 # TODO(scottmg): Handle OutputDirectory without OutputFile.
434 output_file = self._Setting((root, "OutputFile"), config)
435 if output_file:
436 output_file = expand_special(
437 self.ConvertVSMacros(output_file, config=config)
438 )
439 return output_file
440
441 def GetPDBName(self, config, expand_special, default):
442 """Gets the explicitly overridden pdb name for a target or returns
443 default if it's not overridden, or if no pdb will be generated."""
444 config = self._TargetConfig(config)
445 output_file = self._Setting(("VCLinkerTool", "ProgramDatabaseFile"), config)
446 generate_debug_info = self._Setting(
447 ("VCLinkerTool", "GenerateDebugInformation"), config
448 )
449 if generate_debug_info == "true":
450 if output_file:
451 return expand_special(self.ConvertVSMacros(output_file, config=config))
452 else:
453 return default
454 else:
455 return None
456
457 def GetNoImportLibrary(self, config):
458 """If NoImportLibrary: true, ninja will not expect the output to include
459 an import library."""
460 config = self._TargetConfig(config)
461 noimplib = self._Setting(("NoImportLibrary",), config)
462 return noimplib == "true"
463
464 def GetAsmflags(self, config):
465 """Returns the flags that need to be added to ml invocations."""
466 config = self._TargetConfig(config)
467 asmflags = []
468 safeseh = self._Setting(("MASM", "UseSafeExceptionHandlers"), config)
469 if safeseh == "true":
470 asmflags.append("/safeseh")
471 return asmflags
472
473 def GetCflags(self, config):
474 """Returns the flags that need to be added to .c and .cc compilations."""
475 config = self._TargetConfig(config)
476 cflags = []
477 cflags.extend(["/wd" + w for w in self.msvs_disabled_warnings[config]])
478 cl = self._GetWrapper(
479 self, self.msvs_settings[config], "VCCLCompilerTool", append=cflags
480 )
481 cl(
482 "Optimization",
483 map={"0": "d", "1": "1", "2": "2", "3": "x"},
484 prefix="/O",
485 default="2",
486 )
487 cl("InlineFunctionExpansion", prefix="/Ob")
488 cl("DisableSpecificWarnings", prefix="/wd")
489 cl("StringPooling", map={"true": "/GF"})
490 cl("EnableFiberSafeOptimizations", map={"true": "/GT"})
491 cl("OmitFramePointers", map={"false": "-", "true": ""}, prefix="/Oy")
492 cl("EnableIntrinsicFunctions", map={"false": "-", "true": ""}, prefix="/Oi")
493 cl("FavorSizeOrSpeed", map={"1": "t", "2": "s"}, prefix="/O")
494 cl(
495 "FloatingPointModel",
496 map={"0": "precise", "1": "strict", "2": "fast"},
497 prefix="/fp:",
498 default="0",
499 )
500 cl("CompileAsManaged", map={"false": "", "true": "/clr"})
501 cl("WholeProgramOptimization", map={"true": "/GL"})
502 cl("WarningLevel", prefix="/W")
503 cl("WarnAsError", map={"true": "/WX"})
504 cl(
505 "CallingConvention",
506 map={"0": "d", "1": "r", "2": "z", "3": "v"},
507 prefix="/G",
508 )
509 cl("DebugInformationFormat", map={"1": "7", "3": "i", "4": "I"}, prefix="/Z")
510 cl("RuntimeTypeInfo", map={"true": "/GR", "false": "/GR-"})
511 cl("EnableFunctionLevelLinking", map={"true": "/Gy", "false": "/Gy-"})
512 cl("MinimalRebuild", map={"true": "/Gm"})
513 cl("BufferSecurityCheck", map={"true": "/GS", "false": "/GS-"})
514 cl("BasicRuntimeChecks", map={"1": "s", "2": "u", "3": "1"}, prefix="/RTC")
515 cl(
516 "RuntimeLibrary",
517 map={"0": "T", "1": "Td", "2": "D", "3": "Dd"},
518 prefix="/M",
519 )
520 cl("ExceptionHandling", map={"1": "sc", "2": "a"}, prefix="/EH")
521 cl("DefaultCharIsUnsigned", map={"true": "/J"})
522 cl(
523 "TreatWChar_tAsBuiltInType",
524 map={"false": "-", "true": ""},
525 prefix="/Zc:wchar_t",
526 )
527 cl("EnablePREfast", map={"true": "/analyze"})
528 cl("AdditionalOptions", prefix="")
529 cl(
530 "EnableEnhancedInstructionSet",
531 map={"1": "SSE", "2": "SSE2", "3": "AVX", "4": "IA32", "5": "AVX2"},
532 prefix="/arch:",
533 )
534 cflags.extend(
535 [
536 "/FI" + f
537 for f in self._Setting(
538 ("VCCLCompilerTool", "ForcedIncludeFiles"), config, default=[]
539 )
540 ]
541 )
542 if self.vs_version.project_version >= 12.0:
543 # New flag introduced in VS2013 (project version 12.0) Forces writes to
544 # the program database (PDB) to be serialized through MSPDBSRV.EXE.
545 # https://msdn.microsoft.com/en-us/library/dn502518.aspx
546 cflags.append("/FS")
547 # ninja handles parallelism by itself, don't have the compiler do it too.
548 cflags = [x for x in cflags if not x.startswith("/MP")]
549 return cflags
550
551 def _GetPchFlags(self, config, extension):
552 """Get the flags to be added to the cflags for precompiled header support.
553 """
554 config = self._TargetConfig(config)
555 # The PCH is only built once by a particular source file. Usage of PCH must
556 # only be for the same language (i.e. C vs. C++), so only include the pch
557 # flags when the language matches.
558 if self.msvs_precompiled_header[config]:
559 source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
560 if _LanguageMatchesForPch(source_ext, extension):
561 pch = self.msvs_precompiled_header[config]
562 pchbase = os.path.split(pch)[1]
563 return ["/Yu" + pch, "/FI" + pch, "/Fp${pchprefix}." + pchbase + ".pch"]
564 return []
565
566 def GetCflagsC(self, config):
567 """Returns the flags that need to be added to .c compilations."""
568 config = self._TargetConfig(config)
569 return self._GetPchFlags(config, ".c")
570
571 def GetCflagsCC(self, config):
572 """Returns the flags that need to be added to .cc compilations."""
573 config = self._TargetConfig(config)
574 return ["/TP"] + self._GetPchFlags(config, ".cc")
575
576 def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path):
577 """Get and normalize the list of paths in AdditionalLibraryDirectories
578 setting."""
579 config = self._TargetConfig(config)
580 libpaths = self._Setting(
581 (root, "AdditionalLibraryDirectories"), config, default=[]
582 )
583 libpaths = [
584 os.path.normpath(gyp_to_build_path(self.ConvertVSMacros(p, config=config)))
585 for p in libpaths
586 ]
587 return ['/LIBPATH:"' + p + '"' for p in libpaths]
588
589 def GetLibFlags(self, config, gyp_to_build_path):
590 """Returns the flags that need to be added to lib commands."""
591 config = self._TargetConfig(config)
592 libflags = []
593 lib = self._GetWrapper(
594 self, self.msvs_settings[config], "VCLibrarianTool", append=libflags
595 )
596 libflags.extend(
597 self._GetAdditionalLibraryDirectories(
598 "VCLibrarianTool", config, gyp_to_build_path
599 )
600 )
601 lib("LinkTimeCodeGeneration", map={"true": "/LTCG"})
602 lib(
603 "TargetMachine",
604 map={"1": "X86", "17": "X64", "3": "ARM"},
605 prefix="/MACHINE:",
606 )
607 lib("AdditionalOptions")
608 return libflags
609
610 def GetDefFile(self, gyp_to_build_path):
611 """Returns the .def file from sources, if any. Otherwise returns None."""
612 spec = self.spec
613 if spec["type"] in ("shared_library", "loadable_module", "executable"):
614 def_files = [
615 s for s in spec.get("sources", []) if s.lower().endswith(".def")
616 ]
617 if len(def_files) == 1:
618 return gyp_to_build_path(def_files[0])
619 elif len(def_files) > 1:
620 raise Exception("Multiple .def files")
621 return None
622
623 def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
624 """.def files get implicitly converted to a ModuleDefinitionFile for the
625 linker in the VS generator. Emulate that behaviour here."""
626 def_file = self.GetDefFile(gyp_to_build_path)
627 if def_file:
628 ldflags.append('/DEF:"%s"' % def_file)
629
630 def GetPGDName(self, config, expand_special):
631 """Gets the explicitly overridden pgd name for a target or returns None
632 if it's not overridden."""
633 config = self._TargetConfig(config)
634 output_file = self._Setting(("VCLinkerTool", "ProfileGuidedDatabase"), config)
635 if output_file:
636 output_file = expand_special(
637 self.ConvertVSMacros(output_file, config=config)
638 )
639 return output_file
640
641 def GetLdflags(
642 self,
643 config,
644 gyp_to_build_path,
645 expand_special,
646 manifest_base_name,
647 output_name,
648 is_executable,
649 build_dir,
650 ):
651 """Returns the flags that need to be added to link commands, and the
652 manifest files."""
653 config = self._TargetConfig(config)
654 ldflags = []
655 ld = self._GetWrapper(
656 self, self.msvs_settings[config], "VCLinkerTool", append=ldflags
657 )
658 self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
659 ld("GenerateDebugInformation", map={"true": "/DEBUG"})
660 # TODO: These 'map' values come from machineTypeOption enum,
661 # and does not have an official value for ARM64 in VS2017 (yet).
662 # It needs to verify the ARM64 value when machineTypeOption is updated.
663 ld(
664 "TargetMachine",
665 map={"1": "X86", "17": "X64", "3": "ARM", "18": "ARM64"},
666 prefix="/MACHINE:",
667 )
668 ldflags.extend(
669 self._GetAdditionalLibraryDirectories(
670 "VCLinkerTool", config, gyp_to_build_path
671 )
672 )
673 ld("DelayLoadDLLs", prefix="/DELAYLOAD:")
674 ld("TreatLinkerWarningAsErrors", prefix="/WX", map={"true": "", "false": ":NO"})
675 out = self.GetOutputName(config, expand_special)
676 if out:
677 ldflags.append("/OUT:" + out)
678 pdb = self.GetPDBName(config, expand_special, output_name + ".pdb")
679 if pdb:
680 ldflags.append("/PDB:" + pdb)
681 pgd = self.GetPGDName(config, expand_special)
682 if pgd:
683 ldflags.append("/PGD:" + pgd)
684 map_file = self.GetMapFileName(config, expand_special)
685 ld("GenerateMapFile", map={"true": "/MAP:" + map_file if map_file else "/MAP"})
686 ld("MapExports", map={"true": "/MAPINFO:EXPORTS"})
687 ld("AdditionalOptions", prefix="")
688
689 minimum_required_version = self._Setting(
690 ("VCLinkerTool", "MinimumRequiredVersion"), config, default=""
691 )
692 if minimum_required_version:
693 minimum_required_version = "," + minimum_required_version
694 ld(
695 "SubSystem",
696 map={
697 "1": "CONSOLE%s" % minimum_required_version,
698 "2": "WINDOWS%s" % minimum_required_version,
699 },
700 prefix="/SUBSYSTEM:",
701 )
702
703 stack_reserve_size = self._Setting(
704 ("VCLinkerTool", "StackReserveSize"), config, default=""
705 )
706 if stack_reserve_size:
707 stack_commit_size = self._Setting(
708 ("VCLinkerTool", "StackCommitSize"), config, default=""
709 )
710 if stack_commit_size:
711 stack_commit_size = "," + stack_commit_size
712 ldflags.append("/STACK:%s%s" % (stack_reserve_size, stack_commit_size))
713
714 ld("TerminalServerAware", map={"1": ":NO", "2": ""}, prefix="/TSAWARE")
715 ld("LinkIncremental", map={"1": ":NO", "2": ""}, prefix="/INCREMENTAL")
716 ld("BaseAddress", prefix="/BASE:")
717 ld("FixedBaseAddress", map={"1": ":NO", "2": ""}, prefix="/FIXED")
718 ld("RandomizedBaseAddress", map={"1": ":NO", "2": ""}, prefix="/DYNAMICBASE")
719 ld("DataExecutionPrevention", map={"1": ":NO", "2": ""}, prefix="/NXCOMPAT")
720 ld("OptimizeReferences", map={"1": "NOREF", "2": "REF"}, prefix="/OPT:")
721 ld("ForceSymbolReferences", prefix="/INCLUDE:")
722 ld("EnableCOMDATFolding", map={"1": "NOICF", "2": "ICF"}, prefix="/OPT:")
723 ld(
724 "LinkTimeCodeGeneration",
725 map={"1": "", "2": ":PGINSTRUMENT", "3": ":PGOPTIMIZE", "4": ":PGUPDATE"},
726 prefix="/LTCG",
727 )
728 ld("IgnoreDefaultLibraryNames", prefix="/NODEFAULTLIB:")
729 ld("ResourceOnlyDLL", map={"true": "/NOENTRY"})
730 ld("EntryPointSymbol", prefix="/ENTRY:")
731 ld("Profile", map={"true": "/PROFILE"})
732 ld("LargeAddressAware", map={"1": ":NO", "2": ""}, prefix="/LARGEADDRESSAWARE")
733 # TODO(scottmg): This should sort of be somewhere else (not really a flag).
734 ld("AdditionalDependencies", prefix="")
735
736 if self.GetArch(config) == "x86":
737 safeseh_default = "true"
738 else:
739 safeseh_default = None
740 ld(
741 "ImageHasSafeExceptionHandlers",
742 map={"false": ":NO", "true": ""},
743 prefix="/SAFESEH",
744 default=safeseh_default,
745 )
746
747 # If the base address is not specifically controlled, DYNAMICBASE should
748 # be on by default.
749 if not any("DYNAMICBASE" in flag or flag == "/FIXED" for flag in ldflags):
750 ldflags.append("/DYNAMICBASE")
751
752 # If the NXCOMPAT flag has not been specified, default to on. Despite the
753 # documentation that says this only defaults to on when the subsystem is
754 # Vista or greater (which applies to the linker), the IDE defaults it on
755 # unless it's explicitly off.
756 if not any("NXCOMPAT" in flag for flag in ldflags):
757 ldflags.append("/NXCOMPAT")
758
759 have_def_file = any(flag.startswith("/DEF:") for flag in ldflags)
760 (
761 manifest_flags,
762 intermediate_manifest,
763 manifest_files,
764 ) = self._GetLdManifestFlags(
765 config,
766 manifest_base_name,
767 gyp_to_build_path,
768 is_executable and not have_def_file,
769 build_dir,
770 )
771 ldflags.extend(manifest_flags)
772 return ldflags, intermediate_manifest, manifest_files
773
774 def _GetLdManifestFlags(
775 self, config, name, gyp_to_build_path, allow_isolation, build_dir
776 ):
777 """Returns a 3-tuple:
778 - the set of flags that need to be added to the link to generate
779 a default manifest
780 - the intermediate manifest that the linker will generate that should be
781 used to assert it doesn't add anything to the merged one.
782 - the list of all the manifest files to be merged by the manifest tool and
783 included into the link."""
784 generate_manifest = self._Setting(
785 ("VCLinkerTool", "GenerateManifest"), config, default="true"
786 )
787 if generate_manifest != "true":
788 # This means not only that the linker should not generate the intermediate
789 # manifest but also that the manifest tool should do nothing even when
790 # additional manifests are specified.
791 return ["/MANIFEST:NO"], [], []
792
793 output_name = name + ".intermediate.manifest"
794 flags = [
795 "/MANIFEST",
796 "/ManifestFile:" + output_name,
797 ]
798
799 # Instead of using the MANIFESTUAC flags, we generate a .manifest to
800 # include into the list of manifests. This allows us to avoid the need to
801 # do two passes during linking. The /MANIFEST flag and /ManifestFile are
802 # still used, and the intermediate manifest is used to assert that the
803 # final manifest we get from merging all the additional manifest files
804 # (plus the one we generate here) isn't modified by merging the
805 # intermediate into it.
806
807 # Always NO, because we generate a manifest file that has what we want.
808 flags.append("/MANIFESTUAC:NO")
809
810 config = self._TargetConfig(config)
811 enable_uac = self._Setting(
812 ("VCLinkerTool", "EnableUAC"), config, default="true"
813 )
814 manifest_files = []
815 generated_manifest_outer = (
816 "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>"
817 "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>"
818 "%s</assembly>"
819 )
820 if enable_uac == "true":
821 execution_level = self._Setting(
822 ("VCLinkerTool", "UACExecutionLevel"), config, default="0"
823 )
824 execution_level_map = {
825 "0": "asInvoker",
826 "1": "highestAvailable",
827 "2": "requireAdministrator",
828 }
829
830 ui_access = self._Setting(
831 ("VCLinkerTool", "UACUIAccess"), config, default="false"
832 )
833
834 inner = """
835<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
836 <security>
837 <requestedPrivileges>
838 <requestedExecutionLevel level='%s' uiAccess='%s' />
839 </requestedPrivileges>
840 </security>
841</trustInfo>""" % (
842 execution_level_map[execution_level],
843 ui_access,
844 )
845 else:
846 inner = ""
847
848 generated_manifest_contents = generated_manifest_outer % inner
849 generated_name = name + ".generated.manifest"
850 # Need to join with the build_dir here as we're writing it during
851 # generation time, but we return the un-joined version because the build
852 # will occur in that directory. We only write the file if the contents
853 # have changed so that simply regenerating the project files doesn't
854 # cause a relink.
855 build_dir_generated_name = os.path.join(build_dir, generated_name)
856 gyp.common.EnsureDirExists(build_dir_generated_name)
857 f = gyp.common.WriteOnDiff(build_dir_generated_name)
858 f.write(generated_manifest_contents)
859 f.close()
860 manifest_files = [generated_name]
861
862 if allow_isolation:
863 flags.append("/ALLOWISOLATION")
864
865 manifest_files += self._GetAdditionalManifestFiles(config, gyp_to_build_path)
866 return flags, output_name, manifest_files
867
868 def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
869 """Gets additional manifest files that are added to the default one
870 generated by the linker."""
871 files = self._Setting(
872 ("VCManifestTool", "AdditionalManifestFiles"), config, default=[]
873 )
874 if isinstance(files, str):
875 files = files.split(";")
876 return [
877 os.path.normpath(gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
878 for f in files
879 ]
880
881 def IsUseLibraryDependencyInputs(self, config):
882 """Returns whether the target should be linked via Use Library Dependency
883 Inputs (using component .objs of a given .lib)."""
884 config = self._TargetConfig(config)
885 uldi = self._Setting(("VCLinkerTool", "UseLibraryDependencyInputs"), config)
886 return uldi == "true"
887
888 def IsEmbedManifest(self, config):
889 """Returns whether manifest should be linked into binary."""
890 config = self._TargetConfig(config)
891 embed = self._Setting(
892 ("VCManifestTool", "EmbedManifest"), config, default="true"
893 )
894 return embed == "true"
895
896 def IsLinkIncremental(self, config):
897 """Returns whether the target should be linked incrementally."""
898 config = self._TargetConfig(config)
899 link_inc = self._Setting(("VCLinkerTool", "LinkIncremental"), config)
900 return link_inc != "1"
901
902 def GetRcflags(self, config, gyp_to_ninja_path):
903 """Returns the flags that need to be added to invocations of the resource
904 compiler."""
905 config = self._TargetConfig(config)
906 rcflags = []
907 rc = self._GetWrapper(
908 self, self.msvs_settings[config], "VCResourceCompilerTool", append=rcflags
909 )
910 rc("AdditionalIncludeDirectories", map=gyp_to_ninja_path, prefix="/I")
911 rcflags.append("/I" + gyp_to_ninja_path("."))
912 rc("PreprocessorDefinitions", prefix="/d")
913 # /l arg must be in hex without leading '0x'
914 rc("Culture", prefix="/l", map=lambda x: hex(int(x))[2:])
915 return rcflags
916
917 def BuildCygwinBashCommandLine(self, args, path_to_base):
918 """Build a command line that runs args via cygwin bash. We assume that all
919 incoming paths are in Windows normpath'd form, so they need to be
920 converted to posix style for the part of the command line that's passed to
921 bash. We also have to do some Visual Studio macro emulation here because
922 various rules use magic VS names for things. Also note that rules that
923 contain ninja variables cannot be fixed here (for example ${source}), so
924 the outer generator needs to make sure that the paths that are written out
925 are in posix style, if the command line will be used here."""
926 cygwin_dir = os.path.normpath(
927 os.path.join(path_to_base, self.msvs_cygwin_dirs[0])
928 )
929 cd = ("cd %s" % path_to_base).replace("\\", "/")
930 args = [a.replace("\\", "/").replace('"', '\\"') for a in args]
931 args = ["'%s'" % a.replace("'", "'\\''") for a in args]
932 bash_cmd = " ".join(args)
933 cmd = (
934 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir
935 + 'bash -c "%s ; %s"' % (cd, bash_cmd)
936 )
937 return cmd
938
939 def IsRuleRunUnderCygwin(self, rule):
940 """Determine if an action should be run under cygwin. If the variable is
941 unset, or set to 1 we use cygwin."""
942 return (
943 int(rule.get("msvs_cygwin_shell", self.spec.get("msvs_cygwin_shell", 1)))
944 != 0
945 )
946
947 def _HasExplicitRuleForExtension(self, spec, extension):
948 """Determine if there's an explicit rule for a particular extension."""
949 for rule in spec.get("rules", []):
950 if rule["extension"] == extension:
951 return True
952 return False
953
954 def _HasExplicitIdlActions(self, spec):
955 """Determine if an action should not run midl for .idl files."""
956 return any(
957 [action.get("explicit_idl_action", 0) for action in spec.get("actions", [])]
958 )
959
960 def HasExplicitIdlRulesOrActions(self, spec):
961 """Determine if there's an explicit rule or action for idl files. When
962 there isn't we need to generate implicit rules to build MIDL .idl files."""
963 return self._HasExplicitRuleForExtension(
964 spec, "idl"
965 ) or self._HasExplicitIdlActions(spec)
966
967 def HasExplicitAsmRules(self, spec):
968 """Determine if there's an explicit rule for asm files. When there isn't we
969 need to generate implicit rules to assemble .asm files."""
970 return self._HasExplicitRuleForExtension(spec, "asm")
971
972 def GetIdlBuildData(self, source, config):
973 """Determine the implicit outputs for an idl file. Returns output
974 directory, outputs, and variables and flags that are required."""
975 config = self._TargetConfig(config)
976 midl_get = self._GetWrapper(self, self.msvs_settings[config], "VCMIDLTool")
977
978 def midl(name, default=None):
979 return self.ConvertVSMacros(midl_get(name, default=default), config=config)
980
981 tlb = midl("TypeLibraryName", default="${root}.tlb")
982 header = midl("HeaderFileName", default="${root}.h")
983 dlldata = midl("DLLDataFileName", default="dlldata.c")
984 iid = midl("InterfaceIdentifierFileName", default="${root}_i.c")
985 proxy = midl("ProxyFileName", default="${root}_p.c")
986 # Note that .tlb is not included in the outputs as it is not always
987 # generated depending on the content of the input idl file.
988 outdir = midl("OutputDirectory", default="")
989 output = [header, dlldata, iid, proxy]
990 variables = [
991 ("tlb", tlb),
992 ("h", header),
993 ("dlldata", dlldata),
994 ("iid", iid),
995 ("proxy", proxy),
996 ]
997 # TODO(scottmg): Are there configuration settings to set these flags?
998 target_platform = self.GetArch(config)
999 if target_platform == "x86":
1000 target_platform = "win32"
1001 flags = ["/char", "signed", "/env", target_platform, "/Oicf"]
1002 return outdir, output, variables, flags
1003
1004
1005def _LanguageMatchesForPch(source_ext, pch_source_ext):
1006 c_exts = (".c",)
1007 cc_exts = (".cc", ".cxx", ".cpp")
1008 return (source_ext in c_exts and pch_source_ext in c_exts) or (
1009 source_ext in cc_exts and pch_source_ext in cc_exts
1010 )
1011
1012
1013class PrecompiledHeader(object):
1014 """Helper to generate dependencies and build rules to handle generation of
1015 precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
1016 """
1017
1018 def __init__(
1019 self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext
1020 ):
1021 self.settings = settings
1022 self.config = config
1023 pch_source = self.settings.msvs_precompiled_source[self.config]
1024 self.pch_source = gyp_to_build_path(pch_source)
1025 filename, _ = os.path.splitext(pch_source)
1026 self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
1027
1028 def _PchHeader(self):
1029 """Get the header that will appear in an #include line for all source
1030 files."""
1031 return self.settings.msvs_precompiled_header[self.config]
1032
1033 def GetObjDependencies(self, sources, objs, arch):
1034 """Given a list of sources files and the corresponding object files,
1035 returns a list of the pch files that should be depended upon. The
1036 additional wrapping in the return value is for interface compatibility
1037 with make.py on Mac, and xcode_emulation.py."""
1038 assert arch is None
1039 if not self._PchHeader():
1040 return []
1041 pch_ext = os.path.splitext(self.pch_source)[1]
1042 for source in sources:
1043 if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
1044 return [(None, None, self.output_obj)]
1045 return []
1046
1047 def GetPchBuildCommands(self, arch):
1048 """Not used on Windows as there are no additional build steps required
1049 (instead, existing steps are modified in GetFlagsModifications below)."""
1050 return []
1051
1052 def GetFlagsModifications(
1053 self, input, output, implicit, command, cflags_c, cflags_cc, expand_special
1054 ):
1055 """Get the modified cflags and implicit dependencies that should be used
1056 for the pch compilation step."""
1057 if input == self.pch_source:
1058 pch_output = ["/Yc" + self._PchHeader()]
1059 if command == "cxx":
1060 return (
1061 [("cflags_cc", map(expand_special, cflags_cc + pch_output))],
1062 self.output_obj,
1063 [],
1064 )
1065 elif command == "cc":
1066 return (
1067 [("cflags_c", map(expand_special, cflags_c + pch_output))],
1068 self.output_obj,
1069 [],
1070 )
1071 return [], output, implicit
1072
1073
1074vs_version = None
1075
1076
1077def GetVSVersion(generator_flags):
1078 global vs_version
1079 if not vs_version:
1080 vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
1081 generator_flags.get("msvs_version", "auto"), allow_fallback=False
1082 )
1083 return vs_version
1084
1085
1086def _GetVsvarsSetupArgs(generator_flags, arch):
1087 vs = GetVSVersion(generator_flags)
1088 return vs.SetupScript()
1089
1090
1091def ExpandMacros(string, expansions):
1092 """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
1093 for the canonical way to retrieve a suitable dict."""
1094 if "$" in string:
1095 for old, new in expansions.items():
1096 assert "$(" not in new, new
1097 string = string.replace(old, new)
1098 return string
1099
1100
1101def _ExtractImportantEnvironment(output_of_set):
1102 """Extracts environment variables required for the toolchain to run from
1103 a textual dump output by the cmd.exe 'set' command."""
1104 envvars_to_save = (
1105 "goma_.*", # TODO(scottmg): This is ugly, but needed for goma.
1106 "include",
1107 "lib",
1108 "libpath",
1109 "path",
1110 "pathext",
1111 "systemroot",
1112 "temp",
1113 "tmp",
1114 )
1115 env = {}
1116 # This occasionally happens and leads to misleading SYSTEMROOT error messages
1117 # if not caught here.
1118 if output_of_set.count("=") == 0:
1119 raise Exception("Invalid output_of_set. Value is:\n%s" % output_of_set)
1120 for line in output_of_set.splitlines():
1121 for envvar in envvars_to_save:
1122 if re.match(envvar + "=", line.lower()):
1123 var, setting = line.split("=", 1)
1124 if envvar == "path":
1125 # Our own rules (for running gyp-win-tool) and other actions in
1126 # Chromium rely on python being in the path. Add the path to this
1127 # python here so that if it's not in the path when ninja is run
1128 # later, python will still be found.
1129 setting = os.path.dirname(sys.executable) + os.pathsep + setting
1130 env[var.upper()] = setting
1131 break
1132 for required in ("SYSTEMROOT", "TEMP", "TMP"):
1133 if required not in env:
1134 raise Exception(
1135 'Environment variable "%s" '
1136 "required to be set to valid path" % required
1137 )
1138 return env
1139
1140
1141def _FormatAsEnvironmentBlock(envvar_dict):
1142 """Format as an 'environment block' directly suitable for CreateProcess.
1143 Briefly this is a list of key=value\0, terminated by an additional \0. See
1144 CreateProcess documentation for more details."""
1145 block = ""
1146 nul = "\0"
1147 for key, value in envvar_dict.items():
1148 block += key + "=" + value + nul
1149 block += nul
1150 return block
1151
1152
1153def _ExtractCLPath(output_of_where):
1154 """Gets the path to cl.exe based on the output of calling the environment
1155 setup batch file, followed by the equivalent of `where`."""
1156 # Take the first line, as that's the first found in the PATH.
1157 for line in output_of_where.strip().splitlines():
1158 if line.startswith("LOC:"):
1159 return line[len("LOC:") :].strip()
1160
1161
1162def GenerateEnvironmentFiles(
1163 toplevel_build_dir, generator_flags, system_includes, open_out
1164):
1165 """It's not sufficient to have the absolute path to the compiler, linker,
1166 etc. on Windows, as those tools rely on .dlls being in the PATH. We also
1167 need to support both x86 and x64 compilers within the same build (to support
1168 msvs_target_platform hackery). Different architectures require a different
1169 compiler binary, and different supporting environment variables (INCLUDE,
1170 LIB, LIBPATH). So, we extract the environment here, wrap all invocations
1171 of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
1172 sets up the environment, and then we do not prefix the compiler with
1173 an absolute path, instead preferring something like "cl.exe" in the rule
1174 which will then run whichever the environment setup has put in the path.
1175 When the following procedure to generate environment files does not
1176 meet your requirement (e.g. for custom toolchains), you can pass
1177 "-G ninja_use_custom_environment_files" to the gyp to suppress file
1178 generation and use custom environment files prepared by yourself."""
1179 archs = ("x86", "x64")
1180 if generator_flags.get("ninja_use_custom_environment_files", 0):
1181 cl_paths = {}
1182 for arch in archs:
1183 cl_paths[arch] = "cl.exe"
1184 return cl_paths
1185 vs = GetVSVersion(generator_flags)
1186 cl_paths = {}
1187 for arch in archs:
1188 # Extract environment variables for subprocesses.
1189 args = vs.SetupScript(arch)
1190 args.extend(("&&", "set"))
1191 popen = subprocess.Popen(
1192 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
1193 )
1194 variables, _ = popen.communicate()
1195 if PY3:
1196 variables = variables.decode("utf-8")
1197 if popen.returncode != 0:
1198 raise Exception('"%s" failed with error %d' % (args, popen.returncode))
1199 env = _ExtractImportantEnvironment(variables)
1200
1201 # Inject system includes from gyp files into INCLUDE.
1202 if system_includes:
1203 system_includes = system_includes | OrderedSet(
1204 env.get("INCLUDE", "").split(";")
1205 )
1206 env["INCLUDE"] = ";".join(system_includes)
1207
1208 env_block = _FormatAsEnvironmentBlock(env)
1209 f = open_out(os.path.join(toplevel_build_dir, "environment." + arch), "w")
1210 f.write(env_block)
1211 f.close()
1212
1213 # Find cl.exe location for this architecture.
1214 args = vs.SetupScript(arch)
1215 args.extend(
1216 ("&&", "for", "%i", "in", "(cl.exe)", "do", "@echo", "LOC:%~$PATH:i")
1217 )
1218 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
1219 output, _ = popen.communicate()
1220 if PY3:
1221 output = output.decode("utf-8")
1222 cl_paths[arch] = _ExtractCLPath(output)
1223 return cl_paths
1224
1225
1226def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
1227 """Emulate behavior of msvs_error_on_missing_sources present in the msvs
1228 generator: Check that all regular source files, i.e. not created at run time,
1229 exist on disk. Missing files cause needless recompilation when building via
1230 VS, and we want this check to match for people/bots that build using ninja,
1231 so they're not surprised when the VS build fails."""
1232 if int(generator_flags.get("msvs_error_on_missing_sources", 0)):
1233 no_specials = filter(lambda x: "$" not in x, sources)
1234 relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
1235 missing = [x for x in relative if not os.path.exists(x)]
1236 if missing:
1237 # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
1238 # path for a slightly less crazy looking output.
1239 cleaned_up = [os.path.normpath(x) for x in missing]
1240 raise Exception("Missing input files:\n%s" % "\n".join(cleaned_up))
1241
1242
1243# Sets some values in default_variables, which are required for many
1244# generators, run on Windows.
1245def CalculateCommonVariables(default_variables, params):
1246 generator_flags = params.get("generator_flags", {})
1247
1248 # Set a variable so conditions can be based on msvs_version.
1249 msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
1250 default_variables["MSVS_VERSION"] = msvs_version.ShortName()
1251
1252 # To determine processor word size on Windows, in addition to checking
1253 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
1254 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
1255 # contains the actual word size of the system when running thru WOW64).
1256 if "64" in os.environ.get("PROCESSOR_ARCHITECTURE", "") or "64" in os.environ.get(
1257 "PROCESSOR_ARCHITEW6432", ""
1258 ):
1259 default_variables["MSVS_OS_BITS"] = 64
1260 else:
1261 default_variables["MSVS_OS_BITS"] = 32
Note: See TracBrowser for help on using the repository browser.