spawn.py 4.6 KB

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