Package SCons :: Package Platform :: Module win32
[hide private]
[frames] | no frames]

Source Code for Module SCons.Platform.win32

  1  """SCons.Platform.win32 
  2   
  3  Platform-specific initialization for Win32 systems. 
  4   
  5  There normally shouldn't be any need to import this module directly.  It 
  6  will usually be imported through the generic SCons.Platform.Platform() 
  7  selection method. 
  8  """ 
  9   
 10  # 
 11  # Copyright (c) 2001 - 2019 The SCons Foundation 
 12  # 
 13  # Permission is hereby granted, free of charge, to any person obtaining 
 14  # a copy of this software and associated documentation files (the 
 15  # "Software"), to deal in the Software without restriction, including 
 16  # without limitation the rights to use, copy, modify, merge, publish, 
 17  # distribute, sublicense, and/or sell copies of the Software, and to 
 18  # permit persons to whom the Software is furnished to do so, subject to 
 19  # the following conditions: 
 20  # 
 21  # The above copyright notice and this permission notice shall be included 
 22  # in all copies or substantial portions of the Software. 
 23  # 
 24  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 25  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 26  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 27  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 28  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 29  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 30  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 31  # 
 32   
 33  __revision__ = "src/engine/SCons/Platform/win32.py bee7caf9defd6e108fc2998a2520ddb36a967691 2019-12-17 02:07:09 bdeegan" 
 34   
 35  import os 
 36  import os.path 
 37  import sys 
 38  import tempfile 
 39   
 40  from SCons.Platform.posix import exitvalmap 
 41  from SCons.Platform import TempFileMunge 
 42  from SCons.Platform.virtualenv import ImportVirtualenv 
 43  from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv 
 44  import SCons.Util 
 45   
 46  CHOCO_DEFAULT_PATH = [ 
 47      r'C:\ProgramData\chocolatey\bin' 
 48  ] 
 49   
 50  try: 
 51      import msvcrt 
 52      import win32api 
 53      import win32con 
 54  except ImportError: 
 55      parallel_msg = \ 
 56          "you do not seem to have the pywin32 extensions installed;\n" + \ 
 57          "\tparallel (-j) builds may not work reliably with open Python files." 
 58  except AttributeError: 
 59      parallel_msg = \ 
 60          "your pywin32 extensions do not support file handle operations;\n" + \ 
 61          "\tparallel (-j) builds may not work reliably with open Python files." 
 62  else: 
 63      parallel_msg = None 
 64   
 65      if sys.version_info.major == 2: 
 66          import __builtin__ 
 67   
 68          _builtin_file = __builtin__.file 
 69          _builtin_open = __builtin__.open 
 70   
71 - def _scons_fixup_mode(mode):
72 """Adjust 'mode' to mark handle as non-inheritable. 73 74 SCons is multithreaded, so allowing handles to be inherited by 75 children opens us up to races, where (e.g.) processes spawned by 76 the Taskmaster may inherit and retain references to files opened 77 by other threads. This may lead to sharing violations and, 78 ultimately, build failures. 79 80 By including 'N' as part of fopen's 'mode' parameter, all file 81 handles returned from these functions are atomically marked as 82 non-inheritable. 83 """ 84 if not mode: 85 # Python's default is 'r'. 86 # https://docs.python.org/2/library/functions.html#open 87 mode = 'rN' 88 elif 'N' not in mode: 89 mode += 'N' 90 return mode
91
92 - class _scons_file(_builtin_file):
93 - def __init__(self, name, mode=None, *args, **kwargs):
94 _builtin_file.__init__(self, name, _scons_fixup_mode(mode), 95 *args, **kwargs)
96
97 - def _scons_open(name, mode=None, *args, **kwargs):
98 return _builtin_open(name, _scons_fixup_mode(mode), 99 *args, **kwargs)
100 101 __builtin__.file = _scons_file 102 __builtin__.open = _scons_open 103 104 105 106 if False: 107 # Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile 108 try: 109 from ctypes import windll 110 import shutil 111 112 CopyFile = windll.kernel32.CopyFileA 113 SetFileTime = windll.kernel32.SetFileTime 114 115 _shutil_copy = shutil.copy 116 _shutil_copy2 = shutil.copy2 117 118 shutil.copy2 = CopyFile 119
120 - def win_api_copyfile(src,dst):
121 CopyFile(src,dst) 122 os.utime(dst)
123 124 shutil.copy = win_api_copyfile 125 126 except AttributeError: 127 parallel_msg = \ 128 "Couldn't override shutil.copy or shutil.copy2 falling back to shutil defaults" 129 130 131 132 133 134 135 136 try: 137 import threading 138 spawn_lock = threading.Lock() 139 140 # This locked version of spawnve works around a Windows 141 # MSVCRT bug, because its spawnve is not thread-safe. 142 # Without this, python can randomly crash while using -jN. 143 # See the python bug at http://bugs.python.org/issue6476 144 # and SCons issue at 145 # https://github.com/SCons/scons/issues/2449
146 - def spawnve(mode, file, args, env):
147 spawn_lock.acquire() 148 try: 149 if mode == os.P_WAIT: 150 ret = os.spawnve(os.P_NOWAIT, file, args, env) 151 else: 152 ret = os.spawnve(mode, file, args, env) 153 finally: 154 spawn_lock.release() 155 if mode == os.P_WAIT: 156 pid, status = os.waitpid(ret, 0) 157 ret = status >> 8 158 return ret
159 except ImportError: 160 # Use the unsafe method of spawnve. 161 # Please, don't try to optimize this try-except block 162 # away by assuming that the threading module is always present. 163 # In the test test/option-j.py we intentionally call SCons with 164 # a fake threading.py that raises an import exception right away, 165 # simulating a non-existent package.
166 - def spawnve(mode, file, args, env):
167 return os.spawnve(mode, file, args, env)
168 169 # The upshot of all this is that, if you are using Python 1.5.2, 170 # you had better have cmd or command.com in your PATH when you run 171 # scons. 172 173
174 -def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
175 # There is no direct way to do that in python. What we do 176 # here should work for most cases: 177 # In case stdout (stderr) is not redirected to a file, 178 # we redirect it into a temporary file tmpFileStdout 179 # (tmpFileStderr) and copy the contents of this file 180 # to stdout (stderr) given in the argument 181 if not sh: 182 sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") 183 return 127 184 else: 185 # one temporary file for stdout and stderr 186 tmpFileStdout = os.path.normpath(tempfile.mktemp()) 187 tmpFileStderr = os.path.normpath(tempfile.mktemp()) 188 189 # check if output is redirected 190 stdoutRedirected = 0 191 stderrRedirected = 0 192 for arg in args: 193 # are there more possibilities to redirect stdout ? 194 if arg.find( ">", 0, 1 ) != -1 or arg.find( "1>", 0, 2 ) != -1: 195 stdoutRedirected = 1 196 # are there more possibilities to redirect stderr ? 197 if arg.find( "2>", 0, 2 ) != -1: 198 stderrRedirected = 1 199 200 # redirect output of non-redirected streams to our tempfiles 201 if stdoutRedirected == 0: 202 args.append(">" + str(tmpFileStdout)) 203 if stderrRedirected == 0: 204 args.append("2>" + str(tmpFileStderr)) 205 206 # actually do the spawn 207 try: 208 args = [sh, '/C', escape(' '.join(args))] 209 ret = spawnve(os.P_WAIT, sh, args, env) 210 except OSError as e: 211 # catch any error 212 try: 213 ret = exitvalmap[e.errno] 214 except KeyError: 215 sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror)) 216 if stderr is not None: 217 stderr.write("scons: %s: %s\n" % (cmd, e.strerror)) 218 # copy child output from tempfiles to our streams 219 # and do clean up stuff 220 if stdout is not None and stdoutRedirected == 0: 221 try: 222 with open(tmpFileStdout, "r" ) as tmp: 223 stdout.write(tmp.read()) 224 os.remove(tmpFileStdout) 225 except (IOError, OSError): 226 pass 227 228 if stderr is not None and stderrRedirected == 0: 229 try: 230 with open(tmpFileStderr, "r" ) as tmp: 231 stderr.write(tmp.read()) 232 os.remove(tmpFileStderr) 233 except (IOError, OSError): 234 pass 235 return ret
236 237
238 -def exec_spawn(l, env):
239 try: 240 result = spawnve(os.P_WAIT, l[0], l, env) 241 except (OSError, EnvironmentError) as e: 242 try: 243 result = exitvalmap[e.errno] 244 sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror)) 245 except KeyError: 246 result = 127 247 if len(l) > 2: 248 if len(l[2]) < 1000: 249 command = ' '.join(l[0:3]) 250 else: 251 command = l[0] 252 else: 253 command = l[0] 254 sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror)) 255 return result
256 257
258 -def spawn(sh, escape, cmd, args, env):
259 if not sh: 260 sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") 261 return 127 262 return exec_spawn([sh, '/C', escape(' '.join(args))], env)
263 264 # Windows does not allow special characters in file names anyway, so no 265 # need for a complex escape function, we will just quote the arg, except 266 # that "cmd /c" requires that if an argument ends with a backslash it 267 # needs to be escaped so as not to interfere with closing double quote 268 # that we add.
269 -def escape(x):
270 if x[-1] == '\\': 271 x = x + '\\' 272 return '"' + x + '"'
273 274 # Get the windows system directory name 275 _system_root = None 276 277
278 -def get_system_root():
279 global _system_root 280 if _system_root is not None: 281 return _system_root 282 283 # A resonable default if we can't read the registry 284 val = os.environ.get('SystemRoot', "C:\\WINDOWS") 285 286 if SCons.Util.can_read_reg: 287 try: 288 # Look for Windows NT system root 289 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 290 'Software\\Microsoft\\Windows NT\\CurrentVersion') 291 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 292 except SCons.Util.RegError: 293 try: 294 # Okay, try the Windows 9x system root 295 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 296 'Software\\Microsoft\\Windows\\CurrentVersion') 297 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 298 except KeyboardInterrupt: 299 raise 300 except: 301 pass 302 303 # Ensure system root is a string and not unicode 304 # (This only matters for py27 were unicode in env passed to POpen fails) 305 val = str(val) 306 _system_root = val 307 return val
308 309
310 -def get_program_files_dir():
311 """ 312 Get the location of the program files directory 313 Returns 314 ------- 315 316 """ 317 # Now see if we can look in the registry... 318 val = '' 319 if SCons.Util.can_read_reg: 320 try: 321 # Look for Windows Program Files directory 322 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 323 'Software\\Microsoft\\Windows\\CurrentVersion') 324 val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') 325 except SCons.Util.RegError: 326 val = '' 327 pass 328 329 if val == '': 330 # A reasonable default if we can't read the registry 331 # (Actually, it's pretty reasonable even if we can :-) 332 val = os.path.join(os.path.dirname(get_system_root()),"Program Files") 333 334 return val
335 336
337 -class ArchDefinition(object):
338 """ 339 Determine which windows CPU were running on. 340 A class for defining architecture-specific settings and logic. 341 """
342 - def __init__(self, arch, synonyms=[]):
343 self.arch = arch 344 self.synonyms = synonyms
345 346 SupportedArchitectureList = [ 347 ArchDefinition( 348 'x86', 349 ['i386', 'i486', 'i586', 'i686'], 350 ), 351 352 ArchDefinition( 353 'x86_64', 354 ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], 355 ), 356 357 ArchDefinition( 358 'ia64', 359 ['IA64'], 360 ), 361 ] 362 363 SupportedArchitectureMap = {} 364 for a in SupportedArchitectureList: 365 SupportedArchitectureMap[a.arch] = a 366 for s in a.synonyms: 367 SupportedArchitectureMap[s] = a 368 369
370 -def get_architecture(arch=None):
371 """Returns the definition for the specified architecture string. 372 373 If no string is specified, the system default is returned (as defined 374 by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment 375 variables). 376 """ 377 if arch is None: 378 arch = os.environ.get('PROCESSOR_ARCHITEW6432') 379 if not arch: 380 arch = os.environ.get('PROCESSOR_ARCHITECTURE') 381 return SupportedArchitectureMap.get(arch, ArchDefinition('', ['']))
382 383
384 -def generate(env):
385 # Attempt to find cmd.exe (for WinNT/2k/XP) or 386 # command.com for Win9x 387 cmd_interp = '' 388 # First see if we can look in the registry... 389 if SCons.Util.can_read_reg: 390 try: 391 # Look for Windows NT system root 392 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 393 'Software\\Microsoft\\Windows NT\\CurrentVersion') 394 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 395 cmd_interp = os.path.join(val, 'System32\\cmd.exe') 396 except SCons.Util.RegError: 397 try: 398 # Okay, try the Windows 9x system root 399 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 400 'Software\\Microsoft\\Windows\\CurrentVersion') 401 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 402 cmd_interp = os.path.join(val, 'command.com') 403 except KeyboardInterrupt: 404 raise 405 except: 406 pass 407 408 # For the special case of not having access to the registry, we 409 # use a temporary path and pathext to attempt to find the command 410 # interpreter. If we fail, we try to find the interpreter through 411 # the env's PATH. The problem with that is that it might not 412 # contain an ENV and a PATH. 413 if not cmd_interp: 414 systemroot = get_system_root() 415 tmp_path = systemroot + os.pathsep + \ 416 os.path.join(systemroot,'System32') 417 tmp_pathext = '.com;.exe;.bat;.cmd' 418 if 'PATHEXT' in os.environ: 419 tmp_pathext = os.environ['PATHEXT'] 420 cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext) 421 if not cmd_interp: 422 cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext) 423 424 if not cmd_interp: 425 cmd_interp = env.Detect('cmd') 426 if not cmd_interp: 427 cmd_interp = env.Detect('command') 428 429 if 'ENV' not in env: 430 env['ENV'] = {} 431 432 # Import things from the external environment to the construction 433 # environment's ENV. This is a potential slippery slope, because we 434 # *don't* want to make builds dependent on the user's environment by 435 # default. We're doing this for SystemRoot, though, because it's 436 # needed for anything that uses sockets, and seldom changes, and 437 # for SystemDrive because it's related. 438 # 439 # Weigh the impact carefully before adding other variables to this list. 440 import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ] 441 for var in import_env: 442 v = os.environ.get(var) 443 if v: 444 env['ENV'][var] = v 445 446 if 'COMSPEC' not in env['ENV']: 447 v = os.environ.get("COMSPEC") 448 if v: 449 env['ENV']['COMSPEC'] = v 450 451 env.AppendENVPath('PATH', get_system_root() + '\\System32') 452 453 env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD' 454 env['OBJPREFIX'] = '' 455 env['OBJSUFFIX'] = '.obj' 456 env['SHOBJPREFIX'] = '$OBJPREFIX' 457 env['SHOBJSUFFIX'] = '$OBJSUFFIX' 458 env['PROGPREFIX'] = '' 459 env['PROGSUFFIX'] = '.exe' 460 env['LIBPREFIX'] = '' 461 env['LIBSUFFIX'] = '.lib' 462 env['SHLIBPREFIX'] = '' 463 env['SHLIBSUFFIX'] = '.dll' 464 env['LIBPREFIXES'] = [ '$LIBPREFIX' ] 465 env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] 466 env['PSPAWN'] = piped_spawn 467 env['SPAWN'] = spawn 468 env['SHELL'] = cmd_interp 469 env['TEMPFILE'] = TempFileMunge 470 env['TEMPFILEPREFIX'] = '@' 471 env['MAXLINELENGTH'] = 2048 472 env['ESCAPE'] = escape 473 474 env['HOST_OS'] = 'win32' 475 env['HOST_ARCH'] = get_architecture().arch 476 477 if enable_virtualenv and not ignore_virtualenv: 478 ImportVirtualenv(env)
479 480 481 # Local Variables: 482 # tab-width:4 483 # indent-tabs-mode:nil 484 # End: 485 # vim: set expandtab tabstop=4 shiftwidth=4: 486