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