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