"""SCons.Platform.win32 Platform-specific initialization for Win32 systems. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Platform.Platform() selection method. """ # # Copyright (c) 2001 - 2015 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Platform/win32.py rel_2.4.0:3365:9259ea1c13d7 2015/09/21 14:03:43 bdbaddog" import os import os.path import sys import tempfile from SCons.Platform.posix import exitvalmap from SCons.Platform import TempFileMunge import SCons.Util try: import msvcrt import win32api import win32con msvcrt.get_osfhandle win32api.SetHandleInformation win32con.HANDLE_FLAG_INHERIT except ImportError: parallel_msg = \ "you do not seem to have the pywin32 extensions installed;\n" + \ "\tparallel (-j) builds may not work reliably with open Python files." except AttributeError: parallel_msg = \ "your pywin32 extensions do not support file handle operations;\n" + \ "\tparallel (-j) builds may not work reliably with open Python files." else: parallel_msg = None import builtins _builtin_file = builtins.file _builtin_open = builtins.open class _scons_file(_builtin_file): def __init__(self, *args, **kw): _builtin_file.__init__(self, *args, **kw) win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()), win32con.HANDLE_FLAG_INHERIT, 0) def _scons_open(*args, **kw): fp = _builtin_open(*args, **kw) win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), win32con.HANDLE_FLAG_INHERIT, 0) return fp builtins.file = _scons_file builtins.open = _scons_open try: import threading spawn_lock = threading.Lock() # This locked version of spawnve works around a Windows # MSVCRT bug, because its spawnve is not thread-safe. # Without this, python can randomly crash while using -jN. # See the python bug at http://bugs.python.org/issue6476 # and SCons issue at # http://scons.tigris.org/issues/show_bug.cgi?id=2449 def spawnve(mode, file, args, env): spawn_lock.acquire() try: if mode == os.P_WAIT: ret = os.spawnve(os.P_NOWAIT, file, args, env) else: ret = os.spawnve(mode, file, args, env) finally: spawn_lock.release() if mode == os.P_WAIT: pid, status = os.waitpid(ret, 0) ret = status >> 8 return ret except ImportError: # Use the unsafe method of spawnve. # Please, don't try to optimize this try-except block # away by assuming that the threading module is always present. # In the test test/option-j.py we intentionally call SCons with # a fake threading.py that raises an import exception right away, # simulating a non-existent package. def spawnve(mode, file, args, env): return os.spawnve(mode, file, args, env) # The upshot of all this is that, if you are using Python 1.5.2, # you had better have cmd or command.com in your PATH when you run # scons. def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): # There is no direct way to do that in python. What we do # here should work for most cases: # In case stdout (stderr) is not redirected to a file, # we redirect it into a temporary file tmpFileStdout # (tmpFileStderr) and copy the contents of this file # to stdout (stderr) given in the argument if not sh: sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") return 127 else: # one temporary file for stdout and stderr tmpFileStdout = os.path.normpath(tempfile.mktemp()) tmpFileStderr = os.path.normpath(tempfile.mktemp()) # check if output is redirected stdoutRedirected = 0 stderrRedirected = 0 for arg in args: # are there more possibilities to redirect stdout ? if (arg.find( ">", 0, 1 ) != -1 or arg.find( "1>", 0, 2 ) != -1): stdoutRedirected = 1 # are there more possibilities to redirect stderr ? if arg.find( "2>", 0, 2 ) != -1: stderrRedirected = 1 # redirect output of non-redirected streams to our tempfiles if stdoutRedirected == 0: args.append(">" + str(tmpFileStdout)) if stderrRedirected == 0: args.append("2>" + str(tmpFileStderr)) # actually do the spawn try: args = [sh, '/C', escape(' '.join(args)) ] ret = spawnve(os.P_WAIT, sh, args, env) except OSError, e: # catch any error try: ret = exitvalmap[e[0]] except KeyError: sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1])) if stderr is not None: stderr.write("scons: %s: %s\n" % (cmd, e[1])) # copy child output from tempfiles to our streams # and do clean up stuff if stdout is not None and stdoutRedirected == 0: try: stdout.write(open( tmpFileStdout, "r" ).read()) os.remove( tmpFileStdout ) except (IOError, OSError): pass if stderr is not None and stderrRedirected == 0: try: stderr.write(open( tmpFileStderr, "r" ).read()) os.remove( tmpFileStderr ) except (IOError, OSError): pass return ret def exec_spawn(l, env): try: result = spawnve(os.P_WAIT, l[0], l, env) except OSError, e: try: result = exitvalmap[e[0]] sys.stderr.write("scons: %s: %s\n" % (l[0], e[1])) except KeyError: result = 127 if len(l) > 2: if len(l[2]) < 1000: command = ' '.join(l[0:3]) else: command = l[0] else: command = l[0] sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e[0], command, e[1])) return result def spawn(sh, escape, cmd, args, env): if not sh: sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") return 127 return exec_spawn([sh, '/C', escape(' '.join(args))], env) # Windows does not allow special characters in file names anyway, so no # need for a complex escape function, we will just quote the arg, except # that "cmd /c" requires that if an argument ends with a backslash it # needs to be escaped so as not to interfere with closing double quote # that we add. def escape(x): if x[-1] == '\\': x = x + '\\' return '"' + x + '"' # Get the windows system directory name _system_root = None def get_system_root(): global _system_root if _system_root is not None: return _system_root # A resonable default if we can't read the registry val = os.environ.get('SystemRoot', "C:\\WINDOWS") if SCons.Util.can_read_reg: try: # Look for Windows NT system root k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Microsoft\\Windows NT\\CurrentVersion') val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') except SCons.Util.RegError: try: # Okay, try the Windows 9x system root k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Microsoft\\Windows\\CurrentVersion') val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') except KeyboardInterrupt: raise except: pass _system_root = val return val # Get the location of the program files directory def get_program_files_dir(): # Now see if we can look in the registry... val = '' if SCons.Util.can_read_reg: try: # Look for Windows Program Files directory k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Microsoft\\Windows\\CurrentVersion') val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') except SCons.Util.RegError: val = '' pass if val == '': # A reasonable default if we can't read the registry # (Actually, it's pretty reasonable even if we can :-) val = os.path.join(os.path.dirname(get_system_root()),"Program Files") return val # Determine which windows CPU were running on. class ArchDefinition(object): """ A class for defining architecture-specific settings and logic. """ def __init__(self, arch, synonyms=[]): self.arch = arch self.synonyms = synonyms SupportedArchitectureList = [ ArchDefinition( 'x86', ['i386', 'i486', 'i586', 'i686'], ), ArchDefinition( 'x86_64', ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], ), ArchDefinition( 'ia64', ['IA64'], ), ] SupportedArchitectureMap = {} for a in SupportedArchitectureList: SupportedArchitectureMap[a.arch] = a for s in a.synonyms: SupportedArchitectureMap[s] = a def get_architecture(arch=None): """Returns the definition for the specified architecture string. If no string is specified, the system default is returned (as defined by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment variables). """ if arch is None: arch = os.environ.get('PROCESSOR_ARCHITEW6432') if not arch: arch = os.environ.get('PROCESSOR_ARCHITECTURE') return SupportedArchitectureMap.get(arch, ArchDefinition('', [''])) def generate(env): # Attempt to find cmd.exe (for WinNT/2k/XP) or # command.com for Win9x cmd_interp = '' # First see if we can look in the registry... if SCons.Util.can_read_reg: try: # Look for Windows NT system root k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Microsoft\\Windows NT\\CurrentVersion') val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') cmd_interp = os.path.join(val, 'System32\\cmd.exe') except SCons.Util.RegError: try: # Okay, try the Windows 9x system root k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Microsoft\\Windows\\CurrentVersion') val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') cmd_interp = os.path.join(val, 'command.com') except KeyboardInterrupt: raise except: pass # For the special case of not having access to the registry, we # use a temporary path and pathext to attempt to find the command # interpreter. If we fail, we try to find the interpreter through # the env's PATH. The problem with that is that it might not # contain an ENV and a PATH. if not cmd_interp: systemroot = get_system_root() tmp_path = systemroot + os.pathsep + \ os.path.join(systemroot,'System32') tmp_pathext = '.com;.exe;.bat;.cmd' if 'PATHEXT' in os.environ: tmp_pathext = os.environ['PATHEXT'] cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext) if not cmd_interp: cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext) if not cmd_interp: cmd_interp = env.Detect('cmd') if not cmd_interp: cmd_interp = env.Detect('command') if 'ENV' not in env: env['ENV'] = {} # Import things from the external environment to the construction # environment's ENV. This is a potential slippery slope, because we # *don't* want to make builds dependent on the user's environment by # default. We're doing this for SystemRoot, though, because it's # needed for anything that uses sockets, and seldom changes, and # for SystemDrive because it's related. # # Weigh the impact carefully before adding other variables to this list. import_env = [ 'SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ] for var in import_env: v = os.environ.get(var) if v: env['ENV'][var] = v if 'COMSPEC' not in env['ENV']: v = os.environ.get("COMSPEC") if v: env['ENV']['COMSPEC'] = v env.AppendENVPath('PATH', get_system_root() + '\System32') env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD' env['OBJPREFIX'] = '' env['OBJSUFFIX'] = '.obj' env['SHOBJPREFIX'] = '$OBJPREFIX' env['SHOBJSUFFIX'] = '$OBJSUFFIX' env['PROGPREFIX'] = '' env['PROGSUFFIX'] = '.exe' env['LIBPREFIX'] = '' env['LIBSUFFIX'] = '.lib' env['SHLIBPREFIX'] = '' env['SHLIBSUFFIX'] = '.dll' env['LIBPREFIXES'] = [ '$LIBPREFIX' ] env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] env['PSPAWN'] = piped_spawn env['SPAWN'] = spawn env['SHELL'] = cmd_interp env['TEMPFILE'] = TempFileMunge env['TEMPFILEPREFIX'] = '@' env['MAXLINELENGTH'] = 2048 env['ESCAPE'] = escape env['HOST_OS'] = 'win32' env['HOST_ARCH'] = get_architecture().arch # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: