Skip to content

Commit 9e06227

Browse files
committed
Merge heads
2 parents 2fb3b82 + f1e8c70 commit 9e06227

4 files changed

Lines changed: 52 additions & 19 deletions

File tree

Doc/distutils/setupscript.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,8 @@ include the following code fragment in your :file:`setup.py` before the
685685
DistributionMetadata.download_url = None
686686

687687

688+
.. _debug-setup-script:
689+
688690
Debugging the setup script
689691
==========================
690692

@@ -700,7 +702,8 @@ installation is broken because they don't read all the way down to the bottom
700702
and see that it's a permission problem.
701703

702704
On the other hand, this doesn't help the developer to find the cause of the
703-
failure. For this purpose, the DISTUTILS_DEBUG environment variable can be set
705+
failure. For this purpose, the :envvar:`DISTUTILS_DEBUG` environment variable can be set
704706
to anything except an empty string, and distutils will now print detailed
705-
information what it is doing, and prints the full traceback in case an exception
706-
occurs.
707+
information about what it is doing, dump the full traceback when an exception
708+
occurs, and print the whole command line when an external program (like a C
709+
compiler) fails.

Doc/install/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ new goodies to their toolbox. You don't need to know Python to read this
5858
document; there will be some brief forays into using Python's interactive mode
5959
to explore your installation, but that's it. If you're looking for information
6060
on how to distribute your own Python modules so that others may use them, see
61-
the :ref:`distutils-index` manual.
61+
the :ref:`distutils-index` manual. :ref:`debug-setup-script` may also be of
62+
interest.
6263

6364

6465
.. _inst-trivial-install:

Lib/distutils/spawn.py

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import os
1111

1212
from distutils.errors import DistutilsPlatformError, DistutilsExecError
13+
from distutils.debug import DEBUG
1314
from distutils import log
1415

1516
def spawn(cmd, search_path=1, verbose=0, dry_run=0):
@@ -28,10 +29,15 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0):
2829
Raise DistutilsExecError if running the program fails in any way; just
2930
return on success.
3031
"""
32+
# cmd is documented as a list, but just in case some code passes a tuple
33+
# in, protect our %-formatting code against horrible death
34+
cmd = list(cmd)
3135
if os.name == 'posix':
3236
_spawn_posix(cmd, search_path, dry_run=dry_run)
3337
elif os.name == 'nt':
3438
_spawn_nt(cmd, search_path, dry_run=dry_run)
39+
elif os.name == 'os2':
40+
_spawn_os2(cmd, search_path, dry_run=dry_run)
3541
else:
3642
raise DistutilsPlatformError(
3743
"don't know how to spawn programs on platform '%s'" % os.name)
@@ -65,12 +71,16 @@ def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0):
6571
rc = os.spawnv(os.P_WAIT, executable, cmd)
6672
except OSError as exc:
6773
# this seems to happen when the command isn't found
74+
if not DEBUG:
75+
cmd = executable
6876
raise DistutilsExecError(
69-
"command '%s' failed: %s" % (cmd[0], exc.args[-1]))
77+
"command %r failed: %s" % (cmd, exc.args[-1]))
7078
if rc != 0:
7179
# and this reflects the command running but failing
80+
if not DEBUG:
81+
cmd = executable
7282
raise DistutilsExecError(
73-
"command '%s' failed with exit status %d" % (cmd[0], rc))
83+
"command %r failed with exit status %d" % (cmd, rc))
7484

7585
if sys.platform == 'darwin':
7686
from distutils import sysconfig
@@ -81,8 +91,9 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
8191
log.info(' '.join(cmd))
8292
if dry_run:
8393
return
94+
executable = cmd[0]
8495
exec_fn = search_path and os.execvp or os.execv
85-
exec_args = [cmd[0], cmd]
96+
env = None
8697
if sys.platform == 'darwin':
8798
global _cfg_target, _cfg_target_split
8899
if _cfg_target is None:
@@ -103,17 +114,23 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
103114
env = dict(os.environ,
104115
MACOSX_DEPLOYMENT_TARGET=cur_target)
105116
exec_fn = search_path and os.execvpe or os.execve
106-
exec_args.append(env)
107117
pid = os.fork()
108118
if pid == 0: # in the child
109119
try:
110-
exec_fn(*exec_args)
120+
if env is None:
121+
exec_fn(executable, cmd)
122+
else:
123+
exec_fn(executable, cmd, env)
111124
except OSError as e:
112-
sys.stderr.write("unable to execute %s: %s\n"
113-
% (cmd[0], e.strerror))
125+
if not DEBUG:
126+
cmd = executable
127+
sys.stderr.write("unable to execute %r: %s\n"
128+
% (cmd, e.strerror))
114129
os._exit(1)
115130

116-
sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0])
131+
if not DEBUG:
132+
cmd = executable
133+
sys.stderr.write("unable to execute %r for unknown reasons" % cmd)
117134
os._exit(1)
118135
else: # in the parent
119136
# Loop until the child either exits or is terminated by a signal
@@ -125,26 +142,34 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
125142
import errno
126143
if exc.errno == errno.EINTR:
127144
continue
145+
if not DEBUG:
146+
cmd = executable
128147
raise DistutilsExecError(
129-
"command '%s' failed: %s" % (cmd[0], exc.args[-1]))
148+
"command %r failed: %s" % (cmd, exc.args[-1]))
130149
if os.WIFSIGNALED(status):
150+
if not DEBUG:
151+
cmd = executable
131152
raise DistutilsExecError(
132-
"command '%s' terminated by signal %d"
133-
% (cmd[0], os.WTERMSIG(status)))
153+
"command %r terminated by signal %d"
154+
% (cmd, os.WTERMSIG(status)))
134155
elif os.WIFEXITED(status):
135156
exit_status = os.WEXITSTATUS(status)
136157
if exit_status == 0:
137158
return # hey, it succeeded!
138159
else:
160+
if not DEBUG:
161+
cmd = executable
139162
raise DistutilsExecError(
140-
"command '%s' failed with exit status %d"
141-
% (cmd[0], exit_status))
163+
"command %r failed with exit status %d"
164+
% (cmd, exit_status))
142165
elif os.WIFSTOPPED(status):
143166
continue
144167
else:
168+
if not DEBUG:
169+
cmd = executable
145170
raise DistutilsExecError(
146-
"unknown error executing '%s': termination status %d"
147-
% (cmd[0], status))
171+
"unknown error executing %r: termination status %d"
172+
% (cmd, status))
148173

149174
def find_executable(executable, path=None):
150175
"""Tries to find 'executable' in the directories listed in 'path'.

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ Library
2323
- Issue #19157: Include the broadcast address in the usuable hosts for IPv6
2424
in ipaddress.
2525

26+
- Issue #11599: When an external command (e.g. compiler) fails, distutils now
27+
prints out the whole command line (instead of just the command name) if the
28+
environment variable DISTUTILS_DEBUG is set.
29+
2630
- Issue #4931: distutils should not produce unhelpful "error: None" messages
2731
anymore. distutils.util.grok_environment_error is kept but doc-deprecated.
2832

0 commit comments

Comments
 (0)