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 a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 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 stdout.write(open( tmpFileStdout, "r" ).read()) 211 os.remove( tmpFileStdout ) 212 except (IOError, OSError): 213 pass 214 215 if stderr is not None and stderrRedirected == 0: 216 try: 217 stderr.write(open( tmpFileStderr, "r" ).read()) 218 os.remove( tmpFileStderr ) 219 except (IOError, OSError): 220 pass 221 return ret
222 223
224 -def exec_spawn(l, env):
225 try: 226 result = spawnve(os.P_WAIT, l[0], l, env) 227 except (OSError, EnvironmentError) as e: 228 try: 229 result = exitvalmap[e.errno] 230 sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror)) 231 except KeyError: 232 result = 127 233 if len(l) > 2: 234 if len(l[2]) < 1000: 235 command = ' '.join(l[0:3]) 236 else: 237 command = l[0] 238 else: 239 command = l[0] 240 sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror)) 241 return result
242 243
244 -def spawn(sh, escape, cmd, args, env):
245 if not sh: 246 sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") 247 return 127 248 return exec_spawn([sh, '/C', escape(' '.join(args))], env)
249 250 # Windows does not allow special characters in file names anyway, so no 251 # need for a complex escape function, we will just quote the arg, except 252 # that "cmd /c" requires that if an argument ends with a backslash it 253 # needs to be escaped so as not to interfere with closing double quote 254 # that we add.
255 -def escape(x):
256 if x[-1] == '\\': 257 x = x + '\\' 258 return '"' + x + '"'
259 260 # Get the windows system directory name 261 _system_root = None 262 263
264 -def get_system_root():
265 global _system_root 266 if _system_root is not None: 267 return _system_root 268 269 # A resonable default if we can't read the registry 270 val = os.environ.get('SystemRoot', "C:\\WINDOWS") 271 272 if SCons.Util.can_read_reg: 273 try: 274 # Look for Windows NT system root 275 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 276 'Software\\Microsoft\\Windows NT\\CurrentVersion') 277 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 278 except SCons.Util.RegError: 279 try: 280 # Okay, try the Windows 9x system root 281 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 282 'Software\\Microsoft\\Windows\\CurrentVersion') 283 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 284 except KeyboardInterrupt: 285 raise 286 except: 287 pass 288 289 # Ensure system root is a string and not unicode 290 # (This only matters for py27 were unicode in env passed to POpen fails) 291 val = str(val) 292 _system_root = val 293 return val
294 295
296 -def get_program_files_dir():
297 """ 298 Get the location of the program files directory 299 Returns 300 ------- 301 302 """ 303 # Now see if we can look in the registry... 304 val = '' 305 if SCons.Util.can_read_reg: 306 try: 307 # Look for Windows Program Files directory 308 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 309 'Software\\Microsoft\\Windows\\CurrentVersion') 310 val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') 311 except SCons.Util.RegError: 312 val = '' 313 pass 314 315 if val == '': 316 # A reasonable default if we can't read the registry 317 # (Actually, it's pretty reasonable even if we can :-) 318 val = os.path.join(os.path.dirname(get_system_root()),"Program Files") 319 320 return val
321 322
323 -class ArchDefinition(object):
324 """ 325 Determine which windows CPU were running on. 326 A class for defining architecture-specific settings and logic. 327 """
328 - def __init__(self, arch, synonyms=[]):
329 self.arch = arch 330 self.synonyms = synonyms
331 332 SupportedArchitectureList = [ 333 ArchDefinition( 334 'x86', 335 ['i386', 'i486', 'i586', 'i686'], 336 ), 337 338 ArchDefinition( 339 'x86_64', 340 ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], 341 ), 342 343 ArchDefinition( 344 'ia64', 345 ['IA64'], 346 ), 347 ] 348 349 SupportedArchitectureMap = {} 350 for a in SupportedArchitectureList: 351 SupportedArchitectureMap[a.arch] = a 352 for s in a.synonyms: 353 SupportedArchitectureMap[s] = a 354 355
356 -def get_architecture(arch=None):
357 """Returns the definition for the specified architecture string. 358 359 If no string is specified, the system default is returned (as defined 360 by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment 361 variables). 362 """ 363 if arch is None: 364 arch = os.environ.get('PROCESSOR_ARCHITEW6432') 365 if not arch: 366 arch = os.environ.get('PROCESSOR_ARCHITECTURE') 367 return SupportedArchitectureMap.get(arch, ArchDefinition('', ['']))
368 369
370 -def generate(env):
371 # Attempt to find cmd.exe (for WinNT/2k/XP) or 372 # command.com for Win9x 373 cmd_interp = '' 374 # First see if we can look in the registry... 375 if SCons.Util.can_read_reg: 376 try: 377 # Look for Windows NT system root 378 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 379 'Software\\Microsoft\\Windows NT\\CurrentVersion') 380 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 381 cmd_interp = os.path.join(val, 'System32\\cmd.exe') 382 except SCons.Util.RegError: 383 try: 384 # Okay, try the Windows 9x system root 385 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 386 'Software\\Microsoft\\Windows\\CurrentVersion') 387 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') 388 cmd_interp = os.path.join(val, 'command.com') 389 except KeyboardInterrupt: 390 raise 391 except: 392 pass 393 394 # For the special case of not having access to the registry, we 395 # use a temporary path and pathext to attempt to find the command 396 # interpreter. If we fail, we try to find the interpreter through 397 # the env's PATH. The problem with that is that it might not 398 # contain an ENV and a PATH. 399 if not cmd_interp: 400 systemroot = get_system_root() 401 tmp_path = systemroot + os.pathsep + \ 402 os.path.join(systemroot,'System32') 403 tmp_pathext = '.com;.exe;.bat;.cmd' 404 if 'PATHEXT' in os.environ: 405 tmp_pathext = os.environ['PATHEXT'] 406 cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext) 407 if not cmd_interp: 408 cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext) 409 410 if not cmd_interp: 411 cmd_interp = env.Detect('cmd') 412 if not cmd_interp: 413 cmd_interp = env.Detect('command') 414 415 if 'ENV' not in env: 416 env['ENV'] = {} 417 418 # Import things from the external environment to the construction 419 # environment's ENV. This is a potential slippery slope, because we 420 # *don't* want to make builds dependent on the user's environment by 421 # default. We're doing this for SystemRoot, though, because it's 422 # needed for anything that uses sockets, and seldom changes, and 423 # for SystemDrive because it's related. 424 # 425 # Weigh the impact carefully before adding other variables to this list. 426 import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ] 427 for var in import_env: 428 v = os.environ.get(var) 429 if v: 430 env['ENV'][var] = v 431 432 if 'COMSPEC' not in env['ENV']: 433 v = os.environ.get("COMSPEC") 434 if v: 435 env['ENV']['COMSPEC'] = v 436 437 env.AppendENVPath('PATH', get_system_root() + '\\System32') 438 439 env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD' 440 env['OBJPREFIX'] = '' 441 env['OBJSUFFIX'] = '.obj' 442 env['SHOBJPREFIX'] = '$OBJPREFIX' 443 env['SHOBJSUFFIX'] = '$OBJSUFFIX' 444 env['PROGPREFIX'] = '' 445 env['PROGSUFFIX'] = '.exe' 446 env['LIBPREFIX'] = '' 447 env['LIBSUFFIX'] = '.lib' 448 env['SHLIBPREFIX'] = '' 449 env['SHLIBSUFFIX'] = '.dll' 450 env['LIBPREFIXES'] = [ '$LIBPREFIX' ] 451 env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] 452 env['PSPAWN'] = piped_spawn 453 env['SPAWN'] = spawn 454 env['SHELL'] = cmd_interp 455 env['TEMPFILE'] = TempFileMunge 456 env['TEMPFILEPREFIX'] = '@' 457 env['MAXLINELENGTH'] = 2048 458 env['ESCAPE'] = escape 459 460 env['HOST_OS'] = 'win32' 461 env['HOST_ARCH'] = get_architecture().arch 462 463 if enable_virtualenv and not ignore_virtualenv: 464 ImportVirtualenv(env)
465 466 467 # Local Variables: 468 # tab-width:4 469 # indent-tabs-mode:nil 470 # End: 471 # vim: set expandtab tabstop=4 shiftwidth=4: 472