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