1"""distutils.spawn 2 3Provides the 'spawn()' function, a front-end to various platform- 4specific functions for launching another program in a sub-process. 5Also provides the 'find_executable()' to search the path for a given 6executable name. 7""" 8 9import sys 10import os 11import subprocess 12 13from distutils.errors import DistutilsPlatformError, DistutilsExecError 14from distutils.debug import DEBUG 15from distutils import log 16 17 18if sys.platform == 'darwin': 19 _cfg_target = None 20 _cfg_target_split = None 21 22 23def spawn(cmd, search_path=1, verbose=0, dry_run=0): 24 """Run another program, specified as a command list 'cmd', in a new process. 25 26 'cmd' is just the argument list for the new process, ie. 27 cmd[0] is the program to run and cmd[1:] are the rest of its arguments. 28 There is no way to run a program with a name different from that of its 29 executable. 30 31 If 'search_path' is true (the default), the system's executable 32 search path will be used to find the program; otherwise, cmd[0] 33 must be the exact path to the executable. If 'dry_run' is true, 34 the command will not actually be run. 35 36 Raise DistutilsExecError if running the program fails in any way; just 37 return on success. 38 """ 39 # cmd is documented as a list, but just in case some code passes a tuple 40 # in, protect our %-formatting code against horrible death 41 cmd = list(cmd) 42 43 log.info(' '.join(cmd)) 44 if dry_run: 45 return 46 47 if search_path: 48 executable = find_executable(cmd[0]) 49 if executable is not None: 50 cmd[0] = executable 51 52 env = None 53 if sys.platform == 'darwin': 54 global _cfg_target, _cfg_target_split 55 if _cfg_target is None: 56 from distutils import sysconfig 57 _cfg_target = sysconfig.get_config_var( 58 'MACOSX_DEPLOYMENT_TARGET') or '' 59 if _cfg_target: 60 _cfg_target_split = [int(x) for x in _cfg_target.split('.')] 61 if _cfg_target: 62 # Ensure that the deployment target of the build process is not 63 # less than 10.3 if the interpreter was built for 10.3 or later. 64 # This ensures extension modules are built with correct 65 # compatibility values, specifically LDSHARED which can use 66 # '-undefined dynamic_lookup' which only works on >= 10.3. 67 cur_target = os.environ.get('MACOSX_DEPLOYMENT_TARGET', _cfg_target) 68 cur_target_split = [int(x) for x in cur_target.split('.')] 69 if _cfg_target_split[:2] >= [10, 3] and cur_target_split[:2] < [10, 3]: 70 my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: ' 71 'now "%s" but "%s" during configure;' 72 'must use 10.3 or later' 73 % (cur_target, _cfg_target)) 74 raise DistutilsPlatformError(my_msg) 75 env = dict(os.environ, 76 MACOSX_DEPLOYMENT_TARGET=cur_target) 77 78 try: 79 proc = subprocess.Popen(cmd, env=env) 80 proc.wait() 81 exitcode = proc.returncode 82 except OSError as exc: 83 if not DEBUG: 84 cmd = cmd[0] 85 raise DistutilsExecError( 86 "command %r failed: %s" % (cmd, exc.args[-1])) from exc 87 88 if exitcode: 89 if not DEBUG: 90 cmd = cmd[0] 91 raise DistutilsExecError( 92 "command %r failed with exit code %s" % (cmd, exitcode)) 93 94 95def find_executable(executable, path=None): 96 """Tries to find 'executable' in the directories listed in 'path'. 97 98 A string listing directories separated by 'os.pathsep'; defaults to 99 os.environ['PATH']. Returns the complete filename or None if not found. 100 """ 101 _, ext = os.path.splitext(executable) 102 if (sys.platform == 'win32') and (ext != '.exe'): 103 executable = executable + '.exe' 104 105 if os.path.isfile(executable): 106 return executable 107 108 if path is None: 109 path = os.environ.get('PATH', None) 110 if path is None: 111 try: 112 path = os.confstr("CS_PATH") 113 except (AttributeError, ValueError): 114 # os.confstr() or CS_PATH is not available 115 path = os.defpath 116 # bpo-35755: Don't use os.defpath if the PATH environment variable is 117 # set to an empty string 118 119 # PATH='' doesn't match, whereas PATH=':' looks in the current directory 120 if not path: 121 return None 122 123 paths = path.split(os.pathsep) 124 for p in paths: 125 f = os.path.join(p, executable) 126 if os.path.isfile(f): 127 # the file exists, we have a shot at spawn working 128 return f 129 return None 130