From c348ef1ad1d4ffb64b25c4e48521abe9fec3b608 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sun, 16 Mar 2014 23:05:59 -0700 Subject: Version bump to 3.5, step 2. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 4c716e2075..328bea6ffe 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.4.0rc1" +__version__ = "3.5.0a0" #--end constants-- -- cgit v1.2.1 From e5f00e0ebe778f59bd07ace54c5b3f120c66de44 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola' Date: Thu, 27 Mar 2014 14:14:16 +0100 Subject: Minor cosmetic enhancement to provide a more readable repr()esentation of Extension instances: - + --- Lib/distutils/extension.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Lib/distutils') diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py index a93655af2c..cc04a18a3a 100644 --- a/Lib/distutils/extension.py +++ b/Lib/distutils/extension.py @@ -131,6 +131,14 @@ class Extension: msg = "Unknown Extension options: %s" % options warnings.warn(msg) + def __repr__(self): + return '<%s.%s(%r) at %#x>' % ( + self.__class__.__module__, + self.__class__.__name__, + self.name, + id(self)) + + def read_setup_file(filename): """Reads a Setup file and returns Extension instances.""" from distutils.sysconfig import (parse_makefile, expand_makefile_vars, -- cgit v1.2.1 From 1753aecfc67b10ec3d4f37eaf7a5532069744c40 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 10 May 2014 13:20:28 -0400 Subject: Clean up style in distutils upload command --- Lib/distutils/command/upload.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index d6762e46fd..4882db428f 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -1,18 +1,21 @@ -"""distutils.command.upload +""" +distutils.command.upload -Implements the Distutils 'upload' subcommand (upload package to PyPI).""" +Implements the Distutils 'upload' subcommand (upload package to a package +index). +""" -from distutils.errors import * -from distutils.core import PyPIRCCommand -from distutils.spawn import spawn -from distutils import log import sys -import os, io -import socket +import os +import io import platform from base64 import standard_b64encode from urllib.request import urlopen, Request, HTTPError from urllib.parse import urlparse +from distutils.errors import * +from distutils.core import PyPIRCCommand +from distutils.spawn import spawn +from distutils import log # this keeps compatibility for 2.3 and 2.4 if sys.version < "2.5": @@ -106,7 +109,7 @@ class upload(PyPIRCCommand): 'md5_digest': md5(content).hexdigest(), # additional meta-data - 'metadata_version' : '1.0', + 'metadata_version': '1.0', 'summary': meta.get_description(), 'home_page': meta.get_url(), 'author': meta.get_contact(), @@ -167,13 +170,15 @@ class upload(PyPIRCCommand): body.write(b"\n") body = body.getvalue() - self.announce("Submitting %s to %s" % (filename, self.repository), log.INFO) + msg = "Submitting %s to %s" % (filename, self.repository) + self.announce(msg, log.INFO) # build the Request - headers = {'Content-type': - 'multipart/form-data; boundary=%s' % boundary, - 'Content-length': str(len(body)), - 'Authorization': auth} + headers = { + 'Content-type': 'multipart/form-data; boundary=%s' % boundary, + 'Content-length': str(len(body)), + 'Authorization': auth, + } request = Request(self.repository, data=body, headers=headers) -- cgit v1.2.1 From e733d9effac0813a47ea7675f5aa40086dc3584e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 10 May 2014 13:21:02 -0400 Subject: Replace import * with explicit import --- Lib/distutils/command/upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 4882db428f..7824466605 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -12,7 +12,7 @@ import platform from base64 import standard_b64encode from urllib.request import urlopen, Request, HTTPError from urllib.parse import urlparse -from distutils.errors import * +from distutils.errors import DistutilsOptionError from distutils.core import PyPIRCCommand from distutils.spawn import spawn from distutils import log -- cgit v1.2.1 From 913816791e20ec6571a05b767392334de23909ea Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 10 May 2014 13:22:43 -0400 Subject: Drop support for Python 2.4 in upload command. --- Lib/distutils/command/upload.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 7824466605..75498b14d5 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -5,10 +5,10 @@ Implements the Distutils 'upload' subcommand (upload package to a package index). """ -import sys import os import io import platform +import hashlib from base64 import standard_b64encode from urllib.request import urlopen, Request, HTTPError from urllib.parse import urlparse @@ -17,12 +17,6 @@ from distutils.core import PyPIRCCommand from distutils.spawn import spawn from distutils import log -# this keeps compatibility for 2.3 and 2.4 -if sys.version < "2.5": - from md5 import md5 -else: - from hashlib import md5 - class upload(PyPIRCCommand): description = "upload binary package to PyPI" @@ -106,7 +100,7 @@ class upload(PyPIRCCommand): 'content': (os.path.basename(filename),content), 'filetype': command, 'pyversion': pyversion, - 'md5_digest': md5(content).hexdigest(), + 'md5_digest': hashlib.md5(content).hexdigest(), # additional meta-data 'metadata_version': '1.0', -- cgit v1.2.1 From 8588add6192d768ac48b90a23ae73afbf5520fb8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 10 May 2014 13:24:18 -0400 Subject: Replace overly-aggressive comparison for type equality with an isinstance check. --- Lib/distutils/command/upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 75498b14d5..c279b591c4 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -146,7 +146,7 @@ class upload(PyPIRCCommand): for key, value in data.items(): title = '\nContent-Disposition: form-data; name="%s"' % key # handle multiple entries for the same name - if type(value) != type([]): + if not isinstance(value, list): value = [value] for value in value: if type(value) is tuple: -- cgit v1.2.1 From c97553b3a3d06b154c91576081335955d327d29f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 10 May 2014 13:24:58 -0400 Subject: Reindent long line --- Lib/distutils/command/upload.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index c279b591c4..b906435203 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -57,7 +57,8 @@ class upload(PyPIRCCommand): def run(self): if not self.distribution.dist_files: - raise DistutilsOptionError("No dist file created in earlier command") + msg = "No dist file created in earlier command" + raise DistutilsOptionError(msg) for command, pyversion, filename in self.distribution.dist_files: self.upload_file(command, pyversion, filename) -- cgit v1.2.1 From e99c61bf4560e430de0cdb6bc4b9d4ddd3ca2e52 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 2 Jul 2014 08:36:19 -0400 Subject: Normalize style per PEP-8 --- Lib/distutils/dist.py | 69 +++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py index 7eb04bc3f5..ffb33ff645 100644 --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -4,7 +4,9 @@ Provides the Distribution class, which represents the module distribution being built/installed/distributed. """ -import sys, os, re +import sys +import os +import re from email import message_from_file try: @@ -22,7 +24,7 @@ from distutils.debug import DEBUG # the same as a Python NAME -- I don't allow leading underscores. The fact # that they're very similar is no coincidence; the default naming scheme is # to look for a Python module named after the command. -command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$') +command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') class Distribution: @@ -39,7 +41,6 @@ class Distribution: See the code for 'setup()', in core.py, for details. """ - # 'global_options' describes the command-line options that may be # supplied to the setup script prior to any actual commands. # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of @@ -48,12 +49,13 @@ class Distribution: # don't want to pollute the commands with too many options that they # have minimal control over. # The fourth entry for verbose means that it can be repeated. - global_options = [('verbose', 'v', "run verbosely (default)", 1), - ('quiet', 'q', "run quietly (turns verbosity off)"), - ('dry-run', 'n', "don't actually do anything"), - ('help', 'h', "show detailed help message"), - ('no-user-cfg', None, - 'ignore pydistutils.cfg in your home directory'), + global_options = [ + ('verbose', 'v', "run verbosely (default)", 1), + ('quiet', 'q', "run quietly (turns verbosity off)"), + ('dry-run', 'n', "don't actually do anything"), + ('help', 'h', "show detailed help message"), + ('no-user-cfg', None, + 'ignore pydistutils.cfg in your home directory'), ] # 'common_usage' is a short (2-3 line) string describing the common @@ -115,10 +117,9 @@ Common commands: (see '--help-commands' for more) # negative options are options that exclude other options negative_opt = {'quiet': 'verbose'} - # -- Creation/initialization methods ------------------------------- - def __init__ (self, attrs=None): + def __init__(self, attrs=None): """Construct a new Distribution instance: initialize all the attributes of a Distribution, and then use 'attrs' (a dictionary mapping attribute names to values) to assign some of those @@ -532,15 +533,15 @@ Common commands: (see '--help-commands' for more) # to be sure that the basic "command" interface is implemented. if not issubclass(cmd_class, Command): raise DistutilsClassError( - "command class %s must subclass Command" % cmd_class) + "command class %s must subclass Command" % cmd_class) # Also make sure that the command object provides a list of its # known options. if not (hasattr(cmd_class, 'user_options') and isinstance(cmd_class.user_options, list)): - raise DistutilsClassError(("command class %s must provide " + - "'user_options' attribute (a list of tuples)") % \ - cmd_class) + msg = ("command class %s must provide " + "'user_options' attribute (a list of tuples)") + raise DistutilsClassError(msg % cmd_class) # If the command class has a list of negative alias options, # merge it in with the global negative aliases. @@ -552,12 +553,11 @@ Common commands: (see '--help-commands' for more) # Check for help_options in command class. They have a different # format (tuple of four) so we need to preprocess them here. if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): + isinstance(cmd_class.help_options, list)): help_options = fix_help_options(cmd_class.help_options) else: help_options = [] - # All commands support the global options too, just by adding # in 'global_options'. parser.set_option_table(self.global_options + @@ -570,7 +570,7 @@ Common commands: (see '--help-commands' for more) return if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): + isinstance(cmd_class.help_options, list)): help_option_found=0 for (help_option, short, desc, func) in cmd_class.help_options: if hasattr(opts, parser.get_attr_name(help_option)): @@ -647,7 +647,7 @@ Common commands: (see '--help-commands' for more) else: klass = self.get_command_class(command) if (hasattr(klass, 'help_options') and - isinstance(klass.help_options, list)): + isinstance(klass.help_options, list)): parser.set_option_table(klass.user_options + fix_help_options(klass.help_options)) else: @@ -814,7 +814,7 @@ Common commands: (see '--help-commands' for more) klass_name = command try: - __import__ (module_name) + __import__(module_name) module = sys.modules[module_name] except ImportError: continue @@ -823,8 +823,8 @@ Common commands: (see '--help-commands' for more) klass = getattr(module, klass_name) except AttributeError: raise DistutilsModuleError( - "invalid command '%s' (no class '%s' in module '%s')" - % (command, klass_name, module_name)) + "invalid command '%s' (no class '%s' in module '%s')" + % (command, klass_name, module_name)) self.cmdclass[command] = klass return klass @@ -840,7 +840,7 @@ Common commands: (see '--help-commands' for more) cmd_obj = self.command_obj.get(command) if not cmd_obj and create: if DEBUG: - self.announce("Distribution.get_command_obj(): " \ + self.announce("Distribution.get_command_obj(): " "creating '%s' command object" % command) klass = self.get_command_class(command) @@ -897,8 +897,8 @@ Common commands: (see '--help-commands' for more) setattr(command_obj, option, value) else: raise DistutilsOptionError( - "error in %s: command '%s' has no such option '%s'" - % (source, command_name, option)) + "error in %s: command '%s' has no such option '%s'" + % (source, command_name, option)) except ValueError as msg: raise DistutilsOptionError(msg) @@ -974,7 +974,6 @@ Common commands: (see '--help-commands' for more) cmd_obj.run() self.have_run[command] = 1 - # -- Distribution query methods ------------------------------------ def has_pure_modules(self): @@ -1112,17 +1111,17 @@ class DistributionMetadata: """ version = '1.0' if (self.provides or self.requires or self.obsoletes or - self.classifiers or self.download_url): + self.classifiers or self.download_url): version = '1.1' file.write('Metadata-Version: %s\n' % version) - file.write('Name: %s\n' % self.get_name() ) - file.write('Version: %s\n' % self.get_version() ) - file.write('Summary: %s\n' % self.get_description() ) - file.write('Home-page: %s\n' % self.get_url() ) - file.write('Author: %s\n' % self.get_contact() ) - file.write('Author-email: %s\n' % self.get_contact_email() ) - file.write('License: %s\n' % self.get_license() ) + file.write('Name: %s\n' % self.get_name()) + file.write('Version: %s\n' % self.get_version()) + file.write('Summary: %s\n' % self.get_description()) + file.write('Home-page: %s\n' % self.get_url()) + file.write('Author: %s\n' % self.get_contact()) + file.write('Author-email: %s\n' % self.get_contact_email()) + file.write('License: %s\n' % self.get_license()) if self.download_url: file.write('Download-URL: %s\n' % self.download_url) @@ -1131,7 +1130,7 @@ class DistributionMetadata: keywords = ','.join(self.get_keywords()) if keywords: - file.write('Keywords: %s\n' % keywords ) + file.write('Keywords: %s\n' % keywords) self._write_list(file, 'Platform', self.get_platforms()) self._write_list(file, 'Classifier', self.get_classifiers()) -- cgit v1.2.1 From 0996f49983c7463bd31595c0e2e2aa9995d62970 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 22 Jul 2014 15:00:37 +0300 Subject: Issue #22032: __qualname__ instead of __name__ is now always used to format fully qualified class names of Python implemented classes. --- Lib/distutils/extension.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py index cc04a18a3a..7efbb74f89 100644 --- a/Lib/distutils/extension.py +++ b/Lib/distutils/extension.py @@ -134,7 +134,7 @@ class Extension: def __repr__(self): return '<%s.%s(%r) at %#x>' % ( self.__class__.__module__, - self.__class__.__name__, + self.__class__.__qualname__, self.name, id(self)) -- cgit v1.2.1 From df9c20c2443c91c18a665b56b43f3f0b330cee66 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Fri, 26 Sep 2014 23:31:59 +0200 Subject: Issue #5309: distutils' build and build_ext commands now accept a ``-j`` option to enable parallel building of extension modules. --- Lib/distutils/command/build.py | 9 ++++++ Lib/distutils/command/build_ext.py | 57 ++++++++++++++++++++++++++++++----- Lib/distutils/tests/test_build_ext.py | 56 +++++++++++++++++++++------------- 3 files changed, 94 insertions(+), 28 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/build.py b/Lib/distutils/command/build.py index cfc15cf0dd..337dd0bfc1 100644 --- a/Lib/distutils/command/build.py +++ b/Lib/distutils/command/build.py @@ -36,6 +36,8 @@ class build(Command): "(default: %s)" % get_platform()), ('compiler=', 'c', "specify the compiler type"), + ('parallel=', 'j', + "number of parallel build jobs"), ('debug', 'g', "compile extensions and libraries with debugging information"), ('force', 'f', @@ -65,6 +67,7 @@ class build(Command): self.debug = None self.force = 0 self.executable = None + self.parallel = None def finalize_options(self): if self.plat_name is None: @@ -116,6 +119,12 @@ class build(Command): if self.executable is None: self.executable = os.path.normpath(sys.executable) + if isinstance(self.parallel, str): + try: + self.parallel = int(self.parallel) + except ValueError: + raise DistutilsOptionError("parallel should be an integer") + def run(self): # Run all relevant sub-commands. This will be some subset of: # - build_py - pure Python modules diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 3ab2d04bf9..08449e1a51 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -4,7 +4,10 @@ Implements the Distutils 'build_ext' command, for building extension modules (currently limited to C extensions, should accommodate C++ extensions ASAP).""" -import sys, os, re +import contextlib +import os +import re +import sys from distutils.core import Command from distutils.errors import * from distutils.sysconfig import customize_compiler, get_python_version @@ -85,6 +88,8 @@ class build_ext(Command): "forcibly build everything (ignore file timestamps)"), ('compiler=', 'c', "specify the compiler type"), + ('parallel=', 'j', + "number of parallel build jobs"), ('swig-cpp', None, "make SWIG create C++ files (default is C)"), ('swig-opts=', None, @@ -124,6 +129,7 @@ class build_ext(Command): self.swig_cpp = None self.swig_opts = None self.user = None + self.parallel = None def finalize_options(self): from distutils import sysconfig @@ -134,6 +140,7 @@ class build_ext(Command): ('compiler', 'compiler'), ('debug', 'debug'), ('force', 'force'), + ('parallel', 'parallel'), ('plat_name', 'plat_name'), ) @@ -274,6 +281,12 @@ class build_ext(Command): self.library_dirs.append(user_lib) self.rpath.append(user_lib) + if isinstance(self.parallel, str): + try: + self.parallel = int(self.parallel) + except ValueError: + raise DistutilsOptionError("parallel should be an integer") + def run(self): from distutils.ccompiler import new_compiler @@ -442,15 +455,45 @@ class build_ext(Command): def build_extensions(self): # First, sanity-check the 'extensions' list self.check_extensions_list(self.extensions) + if self.parallel: + self._build_extensions_parallel() + else: + self._build_extensions_serial() + + def _build_extensions_parallel(self): + workers = self.parallel + if self.parallel is True: + workers = os.cpu_count() # may return None + try: + from concurrent.futures import ThreadPoolExecutor + except ImportError: + workers = None + + if workers is None: + self._build_extensions_serial() + return + with ThreadPoolExecutor(max_workers=workers) as executor: + futures = [executor.submit(self.build_extension, ext) + for ext in self.extensions] + for ext, fut in zip(self.extensions, futures): + with self._filter_build_errors(ext): + fut.result() + + def _build_extensions_serial(self): for ext in self.extensions: - try: + with self._filter_build_errors(ext): self.build_extension(ext) - except (CCompilerError, DistutilsError, CompileError) as e: - if not ext.optional: - raise - self.warn('building extension "%s" failed: %s' % - (ext.name, e)) + + @contextlib.contextmanager + def _filter_build_errors(self, ext): + try: + yield + except (CCompilerError, DistutilsError, CompileError) as e: + if not ext.optional: + raise + self.warn('building extension "%s" failed: %s' % + (ext.name, e)) def build_extension(self, ext): sources = ext.sources diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index b9f407f401..366ffbec9f 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -37,6 +37,9 @@ class BuildExtTestCase(TempdirManager, from distutils.command import build_ext build_ext.USER_BASE = site.USER_BASE + def build_ext(self, *args, **kwargs): + return build_ext(*args, **kwargs) + def test_build_ext(self): global ALREADY_TESTED copy_xxmodule_c(self.tmp_dir) @@ -44,7 +47,7 @@ class BuildExtTestCase(TempdirManager, xx_ext = Extension('xx', [xx_c]) dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]}) dist.package_dir = self.tmp_dir - cmd = build_ext(dist) + cmd = self.build_ext(dist) fixup_build_ext(cmd) cmd.build_lib = self.tmp_dir cmd.build_temp = self.tmp_dir @@ -91,7 +94,7 @@ class BuildExtTestCase(TempdirManager, def test_solaris_enable_shared(self): dist = Distribution({'name': 'xx'}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) old = sys.platform sys.platform = 'sunos' # fooling finalize_options @@ -113,7 +116,7 @@ class BuildExtTestCase(TempdirManager, def test_user_site(self): import site dist = Distribution({'name': 'xx'}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) # making sure the user option is there options = [name for name, short, lable in @@ -144,14 +147,14 @@ class BuildExtTestCase(TempdirManager, # with the optional argument. modules = [Extension('foo', ['xxx'], optional=False)] dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.ensure_finalized() self.assertRaises((UnknownFileError, CompileError), cmd.run) # should raise an error modules = [Extension('foo', ['xxx'], optional=True)] dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.ensure_finalized() cmd.run() # should pass @@ -160,7 +163,7 @@ class BuildExtTestCase(TempdirManager, # etc.) are in the include search path. modules = [Extension('foo', ['xxx'], optional=False)] dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.finalize_options() from distutils import sysconfig @@ -172,14 +175,14 @@ class BuildExtTestCase(TempdirManager, # make sure cmd.libraries is turned into a list # if it's a string - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.libraries = 'my_lib, other_lib lastlib' cmd.finalize_options() self.assertEqual(cmd.libraries, ['my_lib', 'other_lib', 'lastlib']) # make sure cmd.library_dirs is turned into a list # if it's a string - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.library_dirs = 'my_lib_dir%sother_lib_dir' % os.pathsep cmd.finalize_options() self.assertIn('my_lib_dir', cmd.library_dirs) @@ -187,7 +190,7 @@ class BuildExtTestCase(TempdirManager, # make sure rpath is turned into a list # if it's a string - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.rpath = 'one%stwo' % os.pathsep cmd.finalize_options() self.assertEqual(cmd.rpath, ['one', 'two']) @@ -196,32 +199,32 @@ class BuildExtTestCase(TempdirManager, # make sure define is turned into 2-tuples # strings if they are ','-separated strings - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.define = 'one,two' cmd.finalize_options() self.assertEqual(cmd.define, [('one', '1'), ('two', '1')]) # make sure undef is turned into a list of # strings if they are ','-separated strings - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.undef = 'one,two' cmd.finalize_options() self.assertEqual(cmd.undef, ['one', 'two']) # make sure swig_opts is turned into a list - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.swig_opts = None cmd.finalize_options() self.assertEqual(cmd.swig_opts, []) - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.swig_opts = '1 2' cmd.finalize_options() self.assertEqual(cmd.swig_opts, ['1', '2']) def test_check_extensions_list(self): dist = Distribution() - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.finalize_options() #'extensions' option must be a list of Extension instances @@ -270,7 +273,7 @@ class BuildExtTestCase(TempdirManager, def test_get_source_files(self): modules = [Extension('foo', ['xxx'], optional=False)] dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.ensure_finalized() self.assertEqual(cmd.get_source_files(), ['xxx']) @@ -279,7 +282,7 @@ class BuildExtTestCase(TempdirManager, # should not be overriden by a compiler instance # when the command is run dist = Distribution() - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.compiler = 'unix' cmd.ensure_finalized() cmd.run() @@ -292,7 +295,7 @@ class BuildExtTestCase(TempdirManager, ext = Extension('foo', [c_file], optional=False) dist = Distribution({'name': 'xx', 'ext_modules': [ext]}) - cmd = build_ext(dist) + cmd = self.build_ext(dist) fixup_build_ext(cmd) cmd.ensure_finalized() self.assertEqual(len(cmd.get_outputs()), 1) @@ -355,7 +358,7 @@ class BuildExtTestCase(TempdirManager, #etree_ext = Extension('lxml.etree', [etree_c]) #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]}) dist = Distribution() - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.inplace = 1 cmd.distribution.package_dir = {'': 'src'} cmd.distribution.packages = ['lxml', 'lxml.html'] @@ -462,7 +465,7 @@ class BuildExtTestCase(TempdirManager, 'ext_modules': [deptarget_ext] }) dist.package_dir = self.tmp_dir - cmd = build_ext(dist) + cmd = self.build_ext(dist) cmd.build_lib = self.tmp_dir cmd.build_temp = self.tmp_dir @@ -481,8 +484,19 @@ class BuildExtTestCase(TempdirManager, self.fail("Wrong deployment target during compilation") +class ParallelBuildExtTestCase(BuildExtTestCase): + + def build_ext(self, *args, **kwargs): + build_ext = super().build_ext(*args, **kwargs) + build_ext.parallel = True + return build_ext + + def test_suite(): - return unittest.makeSuite(BuildExtTestCase) + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(BuildExtTestCase)) + suite.addTest(unittest.makeSuite(ParallelBuildExtTestCase)) + return suite if __name__ == '__main__': - support.run_unittest(test_suite()) + support.run_unittest(__name__) -- cgit v1.2.1 From b0cf0d466f602101fff7083e7238fdcdf97909a3 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 30 Sep 2014 14:58:22 +0200 Subject: Remove pointless "vile hack" that can cause the build step to fail when some extension modules can't be imported. See issue #5309 for the build failures, issue #458343 for the original motivation. --- Lib/distutils/command/build_ext.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 08449e1a51..2ffab18162 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -545,15 +545,8 @@ class build_ext(Command): extra_postargs=extra_args, depends=ext.depends) - # XXX -- this is a Vile HACK! - # - # The setup.py script for Python on Unix needs to be able to - # get this list so it can perform all the clean up needed to - # avoid keeping object files around when cleaning out a failed - # build of an extension module. Since Distutils does not - # track dependencies, we have to get rid of intermediates to - # ensure all the intermediates will be properly re-built. - # + # XXX outdated variable, kept here in case third-part code + # needs it. self._built_objects = objects[:] # Now link the object files together into a "shared object" -- -- cgit v1.2.1 From abd788eff0d3cda18a5b03bc92e556b2786150a3 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 22 Nov 2014 12:54:57 -0800 Subject: Issue #22919: Windows build updated to support VC 14.0 (Visual Studio 2015), which will be used for the official 3.5 release. --- Lib/distutils/command/build_ext.py | 2 +- Lib/distutils/command/wininst-14.0-amd64.exe | Bin 0 -> 84480 bytes Lib/distutils/command/wininst-14.0.exe | Bin 0 -> 75264 bytes Lib/distutils/msvc9compiler.py | 3 +++ Lib/distutils/msvccompiler.py | 3 +++ Lib/distutils/sysconfig.py | 27 +++++++++------------------ 6 files changed, 16 insertions(+), 19 deletions(-) create mode 100644 Lib/distutils/command/wininst-14.0-amd64.exe create mode 100644 Lib/distutils/command/wininst-14.0.exe (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 54ce13454f..605efbd68f 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -209,7 +209,7 @@ class build_ext(Command): if MSVC_VERSION >= 9: # Use the .lib files for the correct architecture if self.plat_name == 'win32': - suffix = '' + suffix = 'win32' else: # win-amd64 or win-ia64 suffix = self.plat_name[4:] diff --git a/Lib/distutils/command/wininst-14.0-amd64.exe b/Lib/distutils/command/wininst-14.0-amd64.exe new file mode 100644 index 0000000000..9affe13039 Binary files /dev/null and b/Lib/distutils/command/wininst-14.0-amd64.exe differ diff --git a/Lib/distutils/command/wininst-14.0.exe b/Lib/distutils/command/wininst-14.0.exe new file mode 100644 index 0000000000..3ce71b9f1b Binary files /dev/null and b/Lib/distutils/command/wininst-14.0.exe differ diff --git a/Lib/distutils/msvc9compiler.py b/Lib/distutils/msvc9compiler.py index 9688f20019..d1374efe13 100644 --- a/Lib/distutils/msvc9compiler.py +++ b/Lib/distutils/msvc9compiler.py @@ -179,6 +179,9 @@ def get_build_version(): i = i + len(prefix) s, rest = sys.version[i:].split(" ", 1) majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 minorVersion = int(s[2:3]) / 10.0 # I don't think paths are affected by minor version in version 6 if majorVersion == 6: diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py index 8116656961..1048cd4159 100644 --- a/Lib/distutils/msvccompiler.py +++ b/Lib/distutils/msvccompiler.py @@ -157,6 +157,9 @@ def get_build_version(): i = i + len(prefix) s, rest = sys.version[i:].split(" ", 1) majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 minorVersion = int(s[2:3]) / 10.0 # I don't think paths are affected by minor version in version 6 if majorVersion == 6: diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index a1452fe167..573724ddd7 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -9,6 +9,7 @@ Written by: Fred L. Drake, Jr. Email: """ +import _imp import os import re import sys @@ -22,23 +23,15 @@ BASE_PREFIX = os.path.normpath(sys.base_prefix) BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) # Path to the base directory of the project. On Windows the binary may -# live in project/PCBuild9. If we're dealing with an x64 Windows build, -# it'll live in project/PCbuild/amd64. +# live in project/PCBuild/win32 or project/PCBuild/amd64. # set for cross builds if "_PYTHON_PROJECT_BASE" in os.environ: project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) else: project_base = os.path.dirname(os.path.abspath(sys.executable)) -if os.name == "nt" and "pcbuild" in project_base[-8:].lower(): - project_base = os.path.abspath(os.path.join(project_base, os.path.pardir)) -# PC/VS7.1 -if os.name == "nt" and "\\pc\\v" in project_base[-10:].lower(): - project_base = os.path.abspath(os.path.join(project_base, os.path.pardir, - os.path.pardir)) -# PC/AMD64 -if os.name == "nt" and "\\pcbuild\\amd64" in project_base[-14:].lower(): - project_base = os.path.abspath(os.path.join(project_base, os.path.pardir, - os.path.pardir)) +if (os.name == 'nt' and + project_base.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))): + project_base = os.path.dirname(os.path.dirname(project_base)) # python_build: (Boolean) if true, we're either building Python or # building an extension with an un-installed Python, so we use @@ -51,11 +44,9 @@ def _is_python_source_dir(d): return True return False _sys_home = getattr(sys, '_home', None) -if _sys_home and os.name == 'nt' and \ - _sys_home.lower().endswith(('pcbuild', 'pcbuild\\amd64')): - _sys_home = os.path.dirname(_sys_home) - if _sys_home.endswith('pcbuild'): # must be amd64 - _sys_home = os.path.dirname(_sys_home) +if (_sys_home and os.name == 'nt' and + _sys_home.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))): + _sys_home = os.path.dirname(os.path.dirname(_sys_home)) def _python_build(): if _sys_home: return _is_python_source_dir(_sys_home) @@ -468,7 +459,7 @@ def _init_nt(): # XXX hmmm.. a normal install puts include files here g['INCLUDEPY'] = get_python_inc(plat_specific=0) - g['EXT_SUFFIX'] = '.pyd' + g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] g['EXE'] = ".exe" g['VERSION'] = get_python_version().replace(".", "") g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) -- cgit v1.2.1 From cab4b16dfb478e452f79309587b5609502168c43 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 15 Dec 2014 15:03:44 -0800 Subject: Removes bdist_wininst dependency on MFC. --- Lib/distutils/command/wininst-14.0-amd64.exe | Bin 84480 -> 84480 bytes Lib/distutils/command/wininst-14.0.exe | Bin 75264 -> 75264 bytes 2 files changed, 0 insertions(+), 0 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/wininst-14.0-amd64.exe b/Lib/distutils/command/wininst-14.0-amd64.exe index 9affe13039..43b85b6d4f 100644 Binary files a/Lib/distutils/command/wininst-14.0-amd64.exe and b/Lib/distutils/command/wininst-14.0-amd64.exe differ diff --git a/Lib/distutils/command/wininst-14.0.exe b/Lib/distutils/command/wininst-14.0.exe index 3ce71b9f1b..764524d746 100644 Binary files a/Lib/distutils/command/wininst-14.0.exe and b/Lib/distutils/command/wininst-14.0.exe differ -- cgit v1.2.1 From bb226570f4d5ec025569c966ea3c9a42590dee6f Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 15 Dec 2014 20:45:23 -0800 Subject: Fixes distutils adding/expecting too many _d suffixes. --- Lib/distutils/command/build_ext.py | 3 --- Lib/distutils/tests/test_install.py | 2 -- 2 files changed, 5 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 605efbd68f..c5a3ce1915 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -691,10 +691,7 @@ class build_ext(Command): """ from distutils.sysconfig import get_config_var ext_path = ext_name.split('.') - # extensions in debug_mode are named 'module_d.pyd' under windows ext_suffix = get_config_var('EXT_SUFFIX') - if os.name == 'nt' and self.debug: - return os.path.join(*ext_path) + '_d' + ext_suffix return os.path.join(*ext_path) + ext_suffix def get_export_symbols(self, ext): diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py index 18e1e57505..9313330e2b 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py @@ -20,8 +20,6 @@ from distutils.tests import support def _make_ext_name(modname): - if os.name == 'nt' and sys.executable.endswith('_d.exe'): - modname += '_d' return modname + sysconfig.get_config_var('EXT_SUFFIX') -- cgit v1.2.1 From 1e73b7a71628034a0d6b33defbe5ace89713fe69 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 31 Jan 2015 12:05:05 +0200 Subject: Issue #23326: Removed __ne__ implementations. Since fixing default __ne__ implementation in issue #21408 they are redundant. --- Lib/distutils/version.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/version.py b/Lib/distutils/version.py index ebcab84e4e..af14cc1348 100644 --- a/Lib/distutils/version.py +++ b/Lib/distutils/version.py @@ -48,12 +48,6 @@ class Version: return c return c == 0 - def __ne__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c != 0 - def __lt__(self, other): c = self._cmp(other) if c is NotImplemented: -- cgit v1.2.1 From 166a57a01b10a5398290e02aa4ad6142cf9dc41e Mon Sep 17 00:00:00 2001 From: Charles-Fran?ois Natali Date: Sat, 7 Feb 2015 13:27:50 +0000 Subject: Issue #23285: PEP 475 -- Retry system calls failing with EINTR. --- Lib/distutils/spawn.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index 22e87e8fdb..5dd415a283 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -137,9 +137,6 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0): try: pid, status = os.waitpid(pid, 0) except OSError as exc: - import errno - if exc.errno == errno.EINTR: - continue if not DEBUG: cmd = executable raise DistutilsExecError( -- cgit v1.2.1 From fd700b4184cb6d730d1b29354f8a8d5bf23de999 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sat, 7 Feb 2015 16:00:55 -0800 Subject: Release bump for 3.5.0a1. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 328bea6ffe..67ec78b295 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a0" +__version__ = "3.5.0a1" #--end constants-- -- cgit v1.2.1 From a05ce640bc2c976127975d0e933a3f6342302ce0 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 14 Feb 2015 09:50:59 -0800 Subject: Closes #23437: Make user scripts directory versioned on Windows (patch by pmoore) --- Lib/distutils/command/install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index d768dc5463..67db007a02 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -51,7 +51,7 @@ if HAS_USER_SITE: 'purelib': '$usersite', 'platlib': '$usersite', 'headers': '$userbase/Python$py_version_nodot/Include/$dist_name', - 'scripts': '$userbase/Scripts', + 'scripts': '$userbase/Python$py_version_nodot/Scripts', 'data' : '$userbase', } -- cgit v1.2.1 From ebe018cd2c0afba30ec08c4ccb2736180607e8c1 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sun, 8 Mar 2015 00:24:34 -0800 Subject: Release bump for 3.5.0a2. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 67ec78b295..451c5fbebc 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a1" +__version__ = "3.5.0a2" #--end constants-- -- cgit v1.2.1 From d669bcddf2d74acd419d3f439ddf9704e04efcff Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sun, 29 Mar 2015 15:34:26 -0700 Subject: Release bump for Python 3.5.0a3. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 451c5fbebc..6b4287094b 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a2" +__version__ = "3.5.0a3" #--end constants-- -- cgit v1.2.1 From b09b34b211300f68cc98f6b882f7d2e2f4a76f10 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 13 Apr 2015 14:21:02 -0400 Subject: Issue #23731: Implement PEP 488. The concept of .pyo files no longer exists. Now .pyc files have an optional `opt-` tag which specifies if any extra optimizations beyond the peepholer were applied. --- Lib/distutils/command/build_py.py | 4 ++-- Lib/distutils/command/install_lib.py | 16 ++++++++-------- Lib/distutils/tests/test_build_py.py | 4 ++-- Lib/distutils/tests/test_install_lib.py | 13 ++++++------- Lib/distutils/util.py | 9 +++++---- 5 files changed, 23 insertions(+), 23 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/build_py.py b/Lib/distutils/command/build_py.py index 9100b96a2a..cf0ca57c32 100644 --- a/Lib/distutils/command/build_py.py +++ b/Lib/distutils/command/build_py.py @@ -314,10 +314,10 @@ class build_py (Command): if include_bytecode: if self.compile: outputs.append(importlib.util.cache_from_source( - filename, debug_override=True)) + filename, optimization='')) if self.optimize > 0: outputs.append(importlib.util.cache_from_source( - filename, debug_override=False)) + filename, optimization=self.optimize)) outputs += [ os.path.join(build_dir, filename) diff --git a/Lib/distutils/command/install_lib.py b/Lib/distutils/command/install_lib.py index 215813ba97..6154cf0943 100644 --- a/Lib/distutils/command/install_lib.py +++ b/Lib/distutils/command/install_lib.py @@ -22,15 +22,15 @@ class install_lib(Command): # possible scenarios: # 1) no compilation at all (--no-compile --no-optimize) # 2) compile .pyc only (--compile --no-optimize; default) - # 3) compile .pyc and "level 1" .pyo (--compile --optimize) - # 4) compile "level 1" .pyo only (--no-compile --optimize) - # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more) - # 6) compile "level 2" .pyo only (--no-compile --optimize-more) + # 3) compile .pyc and "opt-1" .pyc (--compile --optimize) + # 4) compile "opt-1" .pyc only (--no-compile --optimize) + # 5) compile .pyc and "opt-2" .pyc (--compile --optimize-more) + # 6) compile "opt-2" .pyc only (--no-compile --optimize-more) # - # The UI for this is two option, 'compile' and 'optimize'. + # The UI for this is two options, 'compile' and 'optimize'. # 'compile' is strictly boolean, and only decides whether to # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and - # decides both whether to generate .pyo files and what level of + # decides both whether to generate .pyc files and what level of # optimization to use. user_options = [ @@ -166,10 +166,10 @@ class install_lib(Command): continue if self.compile: bytecode_files.append(importlib.util.cache_from_source( - py_file, debug_override=True)) + py_file, optimization='')) if self.optimize > 0: bytecode_files.append(importlib.util.cache_from_source( - py_file, debug_override=False)) + py_file, optimization=self.optimize)) return bytecode_files diff --git a/Lib/distutils/tests/test_build_py.py b/Lib/distutils/tests/test_build_py.py index c8f6b89919..18283dc722 100644 --- a/Lib/distutils/tests/test_build_py.py +++ b/Lib/distutils/tests/test_build_py.py @@ -120,8 +120,8 @@ class BuildPyTestCase(support.TempdirManager, found = os.listdir(cmd.build_lib) self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py']) found = os.listdir(os.path.join(cmd.build_lib, '__pycache__')) - self.assertEqual(sorted(found), - ['boiledeggs.%s.pyo' % sys.implementation.cache_tag]) + expect = 'boiledeggs.{}.opt-1.pyc'.format(sys.implementation.cache_tag) + self.assertEqual(sorted(found), [expect]) def test_dir_in_package_data(self): """ diff --git a/Lib/distutils/tests/test_install_lib.py b/Lib/distutils/tests/test_install_lib.py index 40dd1a95a6..5378aa8249 100644 --- a/Lib/distutils/tests/test_install_lib.py +++ b/Lib/distutils/tests/test_install_lib.py @@ -44,12 +44,11 @@ class InstallLibTestCase(support.TempdirManager, f = os.path.join(project_dir, 'foo.py') self.write_file(f, '# python file') cmd.byte_compile([f]) - pyc_file = importlib.util.cache_from_source('foo.py', - debug_override=True) - pyo_file = importlib.util.cache_from_source('foo.py', - debug_override=False) + pyc_file = importlib.util.cache_from_source('foo.py', optimization='') + pyc_opt_file = importlib.util.cache_from_source('foo.py', + optimization=cmd.optimize) self.assertTrue(os.path.exists(pyc_file)) - self.assertTrue(os.path.exists(pyo_file)) + self.assertTrue(os.path.exists(pyc_opt_file)) def test_get_outputs(self): project_dir, dist = self.create_dist() @@ -66,8 +65,8 @@ class InstallLibTestCase(support.TempdirManager, cmd.distribution.packages = ['spam'] cmd.distribution.script_name = 'setup.py' - # get_outputs should return 4 elements: spam/__init__.py, .pyc and - # .pyo, foo.import-tag-abiflags.so / foo.pyd + # get_outputs should return 4 elements: spam/__init__.py and .pyc, + # foo.import-tag-abiflags.so / foo.pyd outputs = cmd.get_outputs() self.assertEqual(len(outputs), 4, outputs) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 5adcac5a95..e423325de4 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -322,11 +322,11 @@ def byte_compile (py_files, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None): - """Byte-compile a collection of Python source files to either .pyc - or .pyo files in a __pycache__ subdirectory. 'py_files' is a list + """Byte-compile a collection of Python source files to .pyc + files in a __pycache__ subdirectory. 'py_files' is a list of files to compile; any files that don't end in ".py" are silently skipped. 'optimize' must be one of the following: - 0 - don't optimize (generate .pyc) + 0 - don't optimize 1 - normal optimization (like "python -O") 2 - extra optimization (like "python -OO") If 'force' is true, all files are recompiled regardless of @@ -438,8 +438,9 @@ byte_compile(files, optimize=%r, force=%r, # cfile - byte-compiled file # dfile - purported source filename (same as 'file' by default) if optimize >= 0: + opt = '' if optimize == 0 else optimize cfile = importlib.util.cache_from_source( - file, debug_override=not optimize) + file, optimization=opt) else: cfile = importlib.util.cache_from_source(file) dfile = file -- cgit v1.2.1 From 5e9cf29cab8ae58a2d9154c756c4e1a81597a355 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sun, 19 Apr 2015 13:51:40 -0700 Subject: Version number bump for Python 3.5.0a4. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 6b4287094b..37bfd5a8f7 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a3" +__version__ = "3.5.0a4" #--end constants-- -- cgit v1.2.1 From 5536d97dfec7136900dfdd11af034101a4a98526 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 16 May 2015 22:13:27 +0300 Subject: Issue #16314: Added support for the LZMA compression in distutils. --- Lib/distutils/archive_util.py | 21 +++-- Lib/distutils/command/bdist.py | 3 +- Lib/distutils/command/bdist_dumb.py | 3 +- Lib/distutils/tests/test_archive_util.py | 154 +++++++++++++++++++++---------- Lib/distutils/tests/test_bdist.py | 2 +- 5 files changed, 121 insertions(+), 62 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/archive_util.py b/Lib/distutils/archive_util.py index 4470bb0222..bed1384900 100644 --- a/Lib/distutils/archive_util.py +++ b/Lib/distutils/archive_util.py @@ -57,26 +57,28 @@ def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) + 'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or + None. ("compress" will be deprecated in Python 3.2) 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). + the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z"). Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} + tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '', + 'compress': ''} + compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', + 'compress': '.Z'} # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext.keys(): raise ValueError( - "bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") + "bad value for 'compress': must be None, 'gzip', 'bzip2', " + "'xz' or 'compress'") archive_name = base_name + '.tar' if compress != 'compress': @@ -177,6 +179,7 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): ARCHIVE_FORMATS = { 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), + 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"), 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), 'zip': (make_zipfile, [],"ZIP file") @@ -197,8 +200,8 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", - or "gztar". + extension; 'format' is the archive format: one of "zip", "tar", "gztar", + "bztar", "xztar", or "ztar". 'root_dir' is a directory that will be the root directory of the archive; ie. we typically chdir into 'root_dir' before creating the diff --git a/Lib/distutils/command/bdist.py b/Lib/distutils/command/bdist.py index 6814a1c382..014871d280 100644 --- a/Lib/distutils/command/bdist.py +++ b/Lib/distutils/command/bdist.py @@ -61,13 +61,14 @@ class bdist(Command): 'nt': 'zip'} # Establish the preferred order (for the --help-formats option). - format_commands = ['rpm', 'gztar', 'bztar', 'ztar', 'tar', + format_commands = ['rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar', 'wininst', 'zip', 'msi'] # And the real information. format_command = {'rpm': ('bdist_rpm', "RPM distribution"), 'gztar': ('bdist_dumb', "gzip'ed tar file"), 'bztar': ('bdist_dumb', "bzip2'ed tar file"), + 'xztar': ('bdist_dumb', "xz'ed tar file"), 'ztar': ('bdist_dumb', "compressed tar file"), 'tar': ('bdist_dumb', "tar file"), 'wininst': ('bdist_wininst', diff --git a/Lib/distutils/command/bdist_dumb.py b/Lib/distutils/command/bdist_dumb.py index 4405d12c05..f1bfb24923 100644 --- a/Lib/distutils/command/bdist_dumb.py +++ b/Lib/distutils/command/bdist_dumb.py @@ -22,7 +22,8 @@ class bdist_dumb(Command): "platform name to embed in generated filenames " "(default: %s)" % get_platform()), ('format=', 'f', - "archive format to create (tar, ztar, gztar, zip)"), + "archive format to create (tar, gztar, bztar, xztar, " + "ztar, zip)"), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), diff --git a/Lib/distutils/tests/test_archive_util.py b/Lib/distutils/tests/test_archive_util.py index 2d72af4aa6..81d4c74a7b 100644 --- a/Lib/distutils/tests/test_archive_util.py +++ b/Lib/distutils/tests/test_archive_util.py @@ -13,7 +13,7 @@ from distutils.archive_util import (check_archive_formats, make_tarball, ARCHIVE_FORMATS) from distutils.spawn import find_executable, spawn from distutils.tests import support -from test.support import check_warnings, run_unittest, patch +from test.support import check_warnings, run_unittest, patch, change_cwd try: import grp @@ -34,6 +34,16 @@ try: except ImportError: ZLIB_SUPPORT = False +try: + import bz2 +except ImportError: + bz2 = None + +try: + import lzma +except ImportError: + lzma = None + def can_fs_encode(filename): """ Return True if the filename can be saved in the file system. @@ -52,19 +62,36 @@ class ArchiveUtilTestCase(support.TempdirManager, unittest.TestCase): @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') - def test_make_tarball(self): - self._make_tarball('archive') + def test_make_tarball(self, name='archive'): + # creating something to tar + tmpdir = self._create_files() + self._make_tarball(tmpdir, name, '.tar.gz') + # trying an uncompressed one + self._make_tarball(tmpdir, name, '.tar', compress=None) @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') + def test_make_tarball_gzip(self): + tmpdir = self._create_files() + self._make_tarball(tmpdir, 'archive', '.tar.gz', compress='gzip') + + @unittest.skipUnless(bz2, 'Need bz2 support to run') + def test_make_tarball_bzip2(self): + tmpdir = self._create_files() + self._make_tarball(tmpdir, 'archive', '.tar.bz2', compress='bzip2') + + @unittest.skipUnless(lzma, 'Need lzma support to run') + def test_make_tarball_xz(self): + tmpdir = self._create_files() + self._make_tarball(tmpdir, 'archive', '.tar.xz', compress='xz') + @unittest.skipUnless(can_fs_encode('årchiv'), 'File system cannot handle this filename') def test_make_tarball_latin1(self): """ Mirror test_make_tarball, except filename contains latin characters. """ - self._make_tarball('årchiv') # note this isn't a real word + self.test_make_tarball('årchiv') # note this isn't a real word - @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') @unittest.skipUnless(can_fs_encode('のアーカイブ'), 'File system cannot handle this filename') def test_make_tarball_extended(self): @@ -72,16 +99,9 @@ class ArchiveUtilTestCase(support.TempdirManager, Mirror test_make_tarball, except filename contains extended characters outside the latin charset. """ - self._make_tarball('のアーカイブ') # japanese for archive - - def _make_tarball(self, target_name): - # creating something to tar - tmpdir = self.mkdtemp() - self.write_file([tmpdir, 'file1'], 'xxx') - self.write_file([tmpdir, 'file2'], 'xxx') - os.mkdir(os.path.join(tmpdir, 'sub')) - self.write_file([tmpdir, 'sub', 'file3'], 'xxx') + self.test_make_tarball('のアーカイブ') # japanese for archive + def _make_tarball(self, tmpdir, target_name, suffix, **kwargs): tmpdir2 = self.mkdtemp() unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], "source and target should be on same drive") @@ -89,27 +109,13 @@ class ArchiveUtilTestCase(support.TempdirManager, base_name = os.path.join(tmpdir2, target_name) # working with relative paths to avoid tar warnings - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - make_tarball(splitdrive(base_name)[1], '.') - finally: - os.chdir(old_dir) + with change_cwd(tmpdir): + make_tarball(splitdrive(base_name)[1], 'dist', **kwargs) # check if the compressed tarball was created - tarball = base_name + '.tar.gz' - self.assertTrue(os.path.exists(tarball)) - - # trying an uncompressed one - base_name = os.path.join(tmpdir2, target_name) - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - make_tarball(splitdrive(base_name)[1], '.', compress=None) - finally: - os.chdir(old_dir) - tarball = base_name + '.tar' + tarball = base_name + suffix self.assertTrue(os.path.exists(tarball)) + self.assertEqual(self._tarinfo(tarball), self._created_files) def _tarinfo(self, path): tar = tarfile.open(path) @@ -120,6 +126,9 @@ class ArchiveUtilTestCase(support.TempdirManager, finally: tar.close() + _created_files = ('dist', 'dist/file1', 'dist/file2', + 'dist/sub', 'dist/sub/file3', 'dist/sub2') + def _create_files(self): # creating something to tar tmpdir = self.mkdtemp() @@ -130,15 +139,15 @@ class ArchiveUtilTestCase(support.TempdirManager, os.mkdir(os.path.join(dist, 'sub')) self.write_file([dist, 'sub', 'file3'], 'xxx') os.mkdir(os.path.join(dist, 'sub2')) - tmpdir2 = self.mkdtemp() - base_name = os.path.join(tmpdir2, 'archive') - return tmpdir, tmpdir2, base_name + return tmpdir @unittest.skipUnless(find_executable('tar') and find_executable('gzip') and ZLIB_SUPPORT, 'Need the tar, gzip and zlib command to run') def test_tarfile_vs_tar(self): - tmpdir, tmpdir2, base_name = self._create_files() + tmpdir = self._create_files() + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') old_dir = os.getcwd() os.chdir(tmpdir) try: @@ -164,7 +173,8 @@ class ArchiveUtilTestCase(support.TempdirManager, self.assertTrue(os.path.exists(tarball2)) # let's compare both tarballs - self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2)) + self.assertEqual(self._tarinfo(tarball), self._created_files) + self.assertEqual(self._tarinfo(tarball2), self._created_files) # trying an uncompressed one base_name = os.path.join(tmpdir2, 'archive') @@ -191,7 +201,8 @@ class ArchiveUtilTestCase(support.TempdirManager, @unittest.skipUnless(find_executable('compress'), 'The compress program is required') def test_compress_deprecated(self): - tmpdir, tmpdir2, base_name = self._create_files() + tmpdir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') # using compress and testing the PendingDeprecationWarning old_dir = os.getcwd() @@ -224,17 +235,17 @@ class ArchiveUtilTestCase(support.TempdirManager, 'Need zip and zlib support to run') def test_make_zipfile(self): # creating something to tar - tmpdir = self.mkdtemp() - self.write_file([tmpdir, 'file1'], 'xxx') - self.write_file([tmpdir, 'file2'], 'xxx') - - tmpdir2 = self.mkdtemp() - base_name = os.path.join(tmpdir2, 'archive') - make_zipfile(base_name, tmpdir) + tmpdir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') + with change_cwd(tmpdir): + make_zipfile(base_name, 'dist') # check if the compressed tarball was created tarball = base_name + '.zip' self.assertTrue(os.path.exists(tarball)) + with zipfile.ZipFile(tarball) as zf: + self.assertEqual(sorted(zf.namelist()), + ['dist/file1', 'dist/file2', 'dist/sub/file3']) @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') def test_make_zipfile_no_zlib(self): @@ -250,18 +261,24 @@ class ArchiveUtilTestCase(support.TempdirManager, patch(self, archive_util.zipfile, 'ZipFile', fake_zipfile) # create something to tar and compress - tmpdir, tmpdir2, base_name = self._create_files() - make_zipfile(base_name, tmpdir) + tmpdir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') + with change_cwd(tmpdir): + make_zipfile(base_name, 'dist') tarball = base_name + '.zip' self.assertEqual(called, [((tarball, "w"), {'compression': zipfile.ZIP_STORED})]) self.assertTrue(os.path.exists(tarball)) + with zipfile.ZipFile(tarball) as zf: + self.assertEqual(sorted(zf.namelist()), + ['dist/file1', 'dist/file2', 'dist/sub/file3']) def test_check_archive_formats(self): self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']), 'xxx') - self.assertEqual(check_archive_formats(['gztar', 'zip']), None) + self.assertIsNone(check_archive_formats(['gztar', 'bztar', 'xztar', + 'ztar', 'tar', 'zip'])) def test_make_archive(self): tmpdir = self.mkdtemp() @@ -282,6 +299,41 @@ class ArchiveUtilTestCase(support.TempdirManager, finally: del ARCHIVE_FORMATS['xxx'] + def test_make_archive_tar(self): + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'tar', base_dir, 'dist') + self.assertTrue(os.path.exists(res)) + self.assertEqual(os.path.basename(res), 'archive.tar') + self.assertEqual(self._tarinfo(res), self._created_files) + + @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') + def test_make_archive_gztar(self): + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'gztar', base_dir, 'dist') + self.assertTrue(os.path.exists(res)) + self.assertEqual(os.path.basename(res), 'archive.tar.gz') + self.assertEqual(self._tarinfo(res), self._created_files) + + @unittest.skipUnless(bz2, 'Need bz2 support to run') + def test_make_archive_bztar(self): + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'bztar', base_dir, 'dist') + self.assertTrue(os.path.exists(res)) + self.assertEqual(os.path.basename(res), 'archive.tar.bz2') + self.assertEqual(self._tarinfo(res), self._created_files) + + @unittest.skipUnless(bz2, 'Need xz support to run') + def test_make_archive_xztar(self): + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'xztar', base_dir, 'dist') + self.assertTrue(os.path.exists(res)) + self.assertEqual(os.path.basename(res), 'archive.tar.xz') + self.assertEqual(self._tarinfo(res), self._created_files) + def test_make_archive_owner_group(self): # testing make_archive with owner and group, with various combinations # this works even if there's not gid/uid support @@ -291,7 +343,8 @@ class ArchiveUtilTestCase(support.TempdirManager, else: group = owner = 'root' - base_dir, root_dir, base_name = self._create_files() + base_dir = self._create_files() + root_dir = self.mkdtemp() base_name = os.path.join(self.mkdtemp() , 'archive') res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, group=group) @@ -311,7 +364,8 @@ class ArchiveUtilTestCase(support.TempdirManager, @unittest.skipUnless(ZLIB_SUPPORT, "Requires zlib") @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") def test_tarfile_root_owner(self): - tmpdir, tmpdir2, base_name = self._create_files() + tmpdir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') old_dir = os.getcwd() os.chdir(tmpdir) group = grp.getgrgid(0)[0] diff --git a/Lib/distutils/tests/test_bdist.py b/Lib/distutils/tests/test_bdist.py index 503a6e857d..f762f5d987 100644 --- a/Lib/distutils/tests/test_bdist.py +++ b/Lib/distutils/tests/test_bdist.py @@ -21,7 +21,7 @@ class BuildTestCase(support.TempdirManager, # what formats does bdist offer? formats = ['bztar', 'gztar', 'msi', 'rpm', 'tar', - 'wininst', 'zip', 'ztar'] + 'wininst', 'xztar', 'zip', 'ztar'] found = sorted(cmd.format_command) self.assertEqual(found, formats) -- cgit v1.2.1 From 6bfe4d50024fe441daab4df7dc18e7a666f3eb9c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 17 May 2015 02:23:02 +0300 Subject: Fixed issue #16314 test for the case when lzma is not available. --- Lib/distutils/tests/test_archive_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_archive_util.py b/Lib/distutils/tests/test_archive_util.py index 81d4c74a7b..02fa1e27a4 100644 --- a/Lib/distutils/tests/test_archive_util.py +++ b/Lib/distutils/tests/test_archive_util.py @@ -325,7 +325,7 @@ class ArchiveUtilTestCase(support.TempdirManager, self.assertEqual(os.path.basename(res), 'archive.tar.bz2') self.assertEqual(self._tarinfo(res), self._created_files) - @unittest.skipUnless(bz2, 'Need xz support to run') + @unittest.skipUnless(lzma, 'Need xz support to run') def test_make_archive_xztar(self): base_dir = self._create_files() base_name = os.path.join(self.mkdtemp() , 'archive') -- cgit v1.2.1 From 95d76ac01836713d43c6add1a569b6427db82291 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 20 May 2015 16:10:04 +0300 Subject: Issue #24245: Eliminated senseless expect clauses that have no any effect. Patch by Martin Panter. --- Lib/distutils/core.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/core.py b/Lib/distutils/core.py index 2bfe66aa2f..f05b34b295 100644 --- a/Lib/distutils/core.py +++ b/Lib/distutils/core.py @@ -221,8 +221,6 @@ def run_setup (script_name, script_args=None, stop_after="run"): # Hmm, should we do something if exiting with a non-zero code # (ie. error)? pass - except: - raise if _setup_distribution is None: raise RuntimeError(("'distutils.core.setup()' was never called -- " -- cgit v1.2.1 From 91823f6bd93314f667b8bf0f806fb46506f42629 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 23 May 2015 09:02:50 -0700 Subject: Issue #23970: Adds distutils._msvccompiler for new Visual Studio versions. --- Lib/distutils/_msvccompiler.py | 561 +++++++++++++++++++++++++++++++ Lib/distutils/ccompiler.py | 2 +- Lib/distutils/command/bdist_wininst.py | 31 +- Lib/distutils/command/build_ext.py | 36 +- Lib/distutils/tests/test_msvccompiler.py | 160 +++++++++ 5 files changed, 752 insertions(+), 38 deletions(-) create mode 100644 Lib/distutils/_msvccompiler.py create mode 100644 Lib/distutils/tests/test_msvccompiler.py (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py new file mode 100644 index 0000000000..896d9d927f --- /dev/null +++ b/Lib/distutils/_msvccompiler.py @@ -0,0 +1,561 @@ +"""distutils._msvccompiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for Microsoft Visual Studio 2015. + +The module is compatible with VS 2015 and later. You can find legacy support +for older versions in distutils.msvc9compiler and distutils.msvccompiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS 2005 and VS 2008 by Christian Heimes +# ported to VS 2015 by Steve Dower + +import os +import subprocess +import re + +from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ + CompileError, LibError, LinkError +from distutils.ccompiler import CCompiler, gen_lib_options +from distutils import log +from distutils.util import get_platform + +import winreg +from itertools import count + +def _find_vcvarsall(): + with winreg.OpenKeyEx( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) as key: + if not key: + log.debug("Visual C++ is not registered") + return None + + best_version = 0 + best_dir = None + for i in count(): + try: + v, vc_dir, vt = winreg.EnumValue(key, i) + except OSError: + break + if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir): + try: + version = int(float(v)) + except (ValueError, TypeError): + continue + if version >= 14 and version > best_version: + best_version, best_dir = version, vc_dir + if not best_version: + log.debug("No suitable Visual C++ version found") + return None + + vcvarsall = os.path.join(best_dir, "vcvarsall.bat") + if not os.path.isfile(vcvarsall): + log.debug("%s cannot be found", vcvarsall) + return None + + return vcvarsall + +def _get_vc_env(plat_spec): + if os.getenv("DISTUTILS_USE_SDK"): + return { + key.lower(): value + for key, value in os.environ.items() + } + + vcvarsall = _find_vcvarsall() + if not vcvarsall: + raise DistutilsPlatformError("Unable to find vcvarsall.bat") + + try: + out = subprocess.check_output( + '"{}" {} && set'.format(vcvarsall, plat_spec), + shell=True, + stderr=subprocess.STDOUT, + universal_newlines=True, + ) + except subprocess.CalledProcessError as exc: + log.error(exc.output) + raise DistutilsPlatformError("Error executing {}" + .format(exc.cmd)) + + return { + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + +def _find_exe(exe, paths=None): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + if not paths: + paths = os.getenv('path').split(os.pathsep) + for p in paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + return exe + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targetting amd64.) +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'amd64', +} + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.initialized = False + + def initialize(self, plat_name=None): + # multi-init means we would need to check platform same each time... + assert not self.initialized, "don't init multiple times" + if plat_name is None: + plat_name = get_platform() + # sanity check for platforms to prevent obscure errors later. + if plat_name not in PLAT_TO_VCVARS: + raise DistutilsPlatformError("--plat-name must be one of {}" + .format(tuple(PLAT_TO_VCVARS))) + + # On x86, 'vcvarsall.bat amd64' creates an env that doesn't work; + # to cross compile, you use 'x86_amd64'. + # On AMD64, 'vcvarsall.bat amd64' is a native build env; to cross + # compile use 'x86' (ie, it runs the x86 compiler directly) + if plat_name == get_platform() or plat_name == 'win32': + # native build or cross-compile to win32 + plat_spec = PLAT_TO_VCVARS[plat_name] + else: + # cross compile from win32 -> some 64bit + plat_spec = '{}_{}'.format( + PLAT_TO_VCVARS[get_platform()], + PLAT_TO_VCVARS[plat_name] + ) + + vc_env = _get_vc_env(plat_spec) + if not vc_env: + raise DistutilsPlatformError("Unable to find a compatible " + "Visual Studio installation.") + + paths = vc_env.get('path', '').split(os.pathsep) + self.cc = _find_exe("cl.exe", paths) + self.linker = _find_exe("link.exe", paths) + self.lib = _find_exe("lib.exe", paths) + self.rc = _find_exe("rc.exe", paths) # resource compiler + self.mc = _find_exe("mc.exe", paths) # message compiler + self.mt = _find_exe("mt.exe", paths) # message compiler + + for dir in vc_env.get('include', '').split(os.pathsep): + if dir: + self.add_include_dir(dir) + + for dir in vc_env.get('lib', '').split(os.pathsep): + if dir: + self.add_library_dir(dir) + + self.preprocess_options = None + self.compile_options = [ + '/nologo', '/Ox', '/MD', '/W3', '/GL', '/DNDEBUG' + ] + self.compile_options_debug = [ + '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' + ] + + self.ldflags_shared = [ + '/nologo', '/DLL', '/INCREMENTAL:NO' + ] + self.ldflags_shared_debug = [ + '/nologo', '/DLL', '/INCREMENTAL:no', '/DEBUG:FULL' + ] + self.ldflags_static = [ + '/nologo' + ] + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, + source_filenames, + strip_dir=0, + output_dir=''): + ext_map = {ext: self.obj_extension for ext in self.src_extensions} + ext_map.update((ext, self.res_extension) + for ext in self._rc_extensions + self._mc_extensions) + + def make_out_path(p): + base, ext = os.path.splitext(p) + if strip_dir: + base = os.path.basename(base) + else: + _, base = os.path.splitdrive(base) + if base.startswith((os.path.sep, os.path.altsep)): + base = base[1:] + try: + return base + ext_map[ext] + except LookupError: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError("Don't know how to compile {}".format(p)) + + output_dir = output_dir or '' + return [ + os.path.join(output_dir, make_out_path(src_name)) + for src_name in source_filenames + ] + + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=0, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + compile_info = self._setup_compile(output_dir, macros, include_dirs, + sources, depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = compile_info + + compile_opts = extra_preargs or [] + compile_opts.append('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + + add_cpp_opts = False + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + add_cpp_opts = True + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + [output_opt, input_opt]) + except DistutilsExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src]) + base, _ = os.path.splitext(os.path.basename (src)) + rc_file = os.path.join(rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc, "/fo" + obj, rc_file]) + + except DistutilsExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError("Don't know how to compile {} to {}" + .format(src, obj)) + + args = [self.cc] + compile_opts + pp_opts + if add_cpp_opts: + args.append('/EHsc') + args.append(input_opt) + args.append("/Fo" + obj) + args.extend(extra_postargs) + + try: + self.spawn(args) + except DistutilsExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, + objects, + output_libname, + output_dir=None, + debug=0, + target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, + output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + libraries, library_dirs, runtime_library_dirs = fixed_args + + if runtime_library_dirs: + self.warn("I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs)) + + lib_opts = gen_lib_options(self, + library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + ldflags = (self.ldflags_shared_debug if debug + else self.ldflags_shared) + if target_desc == CCompiler.EXECUTABLE: + ldflags = ldflags[1:] + + export_opts = [] + for sym in (export_symbols or []): + export_opts.append("/EXPORT:" + sym) + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + build_temp = os.path.dirname(objects[0]) + if export_symbols is not None: + (dll_name, dll_ext) = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + build_temp, + self.library_filename(dll_name)) + ld_args.append ('/IMPLIB:' + implib_file) + + self.manifest_setup_ldargs(output_filename, build_temp, ld_args) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + + # embed the manifest + # XXX - this is somewhat fragile - if mt.exe fails, distutils + # will still consider the DLL up-to-date, but it will not have a + # manifest. Maybe we should link to a temp file? OTOH, that + # implies a build environment error that shouldn't go undetected. + mfinfo = self.manifest_get_embed_info(target_desc, ld_args) + if mfinfo is not None: + mffilename, mfid = mfinfo + out_arg = '-outputresource:{};{}'.format(output_filename, mfid) + try: + self.spawn([self.mt, '-nologo', '-manifest', + mffilename, out_arg]) + except DistutilsExecError as msg: + raise LinkError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): + # If we need a manifest at all, an embedded manifest is recommended. + # See MSDN article titled + # "How to: Embed a Manifest Inside a C/C++ Application" + # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) + # Ask the linker to generate the manifest in the temp dir, so + # we can check it, and possibly embed it, later. + temp_manifest = os.path.join( + build_temp, + os.path.basename(output_filename) + ".manifest") + ld_args.append('/MANIFESTFILE:' + temp_manifest) + + def manifest_get_embed_info(self, target_desc, ld_args): + # If a manifest should be embedded, return a tuple of + # (manifest_filename, resource_id). Returns None if no manifest + # should be embedded. See http://bugs.python.org/issue7833 for why + # we want to avoid any manifest for extension modules if we can) + for arg in ld_args: + if arg.startswith("/MANIFESTFILE:"): + temp_manifest = arg.split(":", 1)[1] + break + else: + # no /MANIFESTFILE so nothing to do. + return None + if target_desc == CCompiler.EXECUTABLE: + # by default, executables always get the manifest with the + # CRT referenced. + mfid = 1 + else: + # Extension modules try and avoid any manifest if possible. + mfid = 2 + temp_manifest = self._remove_visual_c_ref(temp_manifest) + if temp_manifest is None: + return None + return temp_manifest, mfid + + def _remove_visual_c_ref(self, manifest_file): + try: + # Remove references to the Visual C runtime, so they will + # fall through to the Visual C dependency of Python.exe. + # This way, when installed for a restricted user (e.g. + # runtimes are not in WinSxS folder, but in Python's own + # folder), the runtimes do not need to be in every folder + # with .pyd's. + # Returns either the filename of the modified manifest or + # None if no manifest should be embedded. + manifest_f = open(manifest_file) + try: + manifest_buf = manifest_f.read() + finally: + manifest_f.close() + pattern = re.compile( + r"""|)""", + re.DOTALL) + manifest_buf = re.sub(pattern, "", manifest_buf) + pattern = "\s*" + manifest_buf = re.sub(pattern, "", manifest_buf) + # Now see if any other assemblies are referenced - if not, we + # don't want a manifest embedded. + pattern = re.compile( + r"""|)""", re.DOTALL) + if re.search(pattern, manifest_buf) is None: + return None + + manifest_f = open(manifest_file, 'w') + try: + manifest_f.write(manifest_buf) + return manifest_file + finally: + manifest_f.close() + except OSError: + pass + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise DistutilsPlatformError( + "don't know how to set runtime library search path for MSVC") + + def library_option(self, lib): + return self.library_filename(lib) + + def find_library_file(self, dirs, lib, debug=0): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.isfile(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py index 911e84dd3b..b7df394ecc 100644 --- a/Lib/distutils/ccompiler.py +++ b/Lib/distutils/ccompiler.py @@ -959,7 +959,7 @@ def get_default_compiler(osname=None, platform=None): # is assumed to be in the 'distutils' package.) compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', "standard UNIX-style compiler"), - 'msvc': ('msvccompiler', 'MSVCCompiler', + 'msvc': ('_msvccompiler', 'MSVCCompiler', "Microsoft Visual C++"), 'cygwin': ('cygwinccompiler', 'CygwinCCompiler', "Cygwin port of GNU C Compiler for Win32"), diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py index 959a8bf62e..a3eff7e7cf 100644 --- a/Lib/distutils/command/bdist_wininst.py +++ b/Lib/distutils/command/bdist_wininst.py @@ -303,7 +303,6 @@ class bdist_wininst(Command): return installer_name def get_exe_bytes(self): - from distutils.msvccompiler import get_build_version # If a target-version other than the current version has been # specified, then using the MSVC version from *this* build is no good. # Without actually finding and executing the target version and parsing @@ -313,20 +312,28 @@ class bdist_wininst(Command): # We can then execute this program to obtain any info we need, such # as the real sys.version string for the build. cur_version = get_python_version() - if self.target_version and self.target_version != cur_version: - # If the target version is *later* than us, then we assume they - # use what we use - # string compares seem wrong, but are what sysconfig.py itself uses - if self.target_version > cur_version: - bv = get_build_version() + + # If the target version is *later* than us, then we assume they + # use what we use + # string compares seem wrong, but are what sysconfig.py itself uses + if self.target_version and self.target_version < cur_version: + if self.target_version < "2.4": + bv = 6.0 + elif self.target_version == "2.4": + bv = 7.1 + elif self.target_version == "2.5": + bv = 8.0 + elif self.target_version <= "3.2": + bv = 9.0 + elif self.target_version <= "3.4": + bv = 10.0 else: - if self.target_version < "2.4": - bv = 6.0 - else: - bv = 7.1 + bv = 14.0 else: # for current version - use authoritative check. - bv = get_build_version() + from msvcrt import CRT_ASSEMBLY_VERSION + bv = float('.'.join(CRT_ASSEMBLY_VERSION.split('.', 2)[:2])) + # wininst-x.y.exe is in the same directory as this file directory = os.path.dirname(__file__) diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index c5a3ce1915..d4cb11e6db 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -19,10 +19,6 @@ from distutils import log from site import USER_BASE -if os.name == 'nt': - from distutils.msvccompiler import get_build_version - MSVC_VERSION = int(get_build_version()) - # An extension name is just a dot-separated list of Python NAMEs (ie. # the same as a fully-qualified module name). extension_name_re = re.compile \ @@ -206,27 +202,17 @@ class build_ext(Command): _sys_home = getattr(sys, '_home', None) if _sys_home: self.library_dirs.append(_sys_home) - if MSVC_VERSION >= 9: - # Use the .lib files for the correct architecture - if self.plat_name == 'win32': - suffix = 'win32' - else: - # win-amd64 or win-ia64 - suffix = self.plat_name[4:] - new_lib = os.path.join(sys.exec_prefix, 'PCbuild') - if suffix: - new_lib = os.path.join(new_lib, suffix) - self.library_dirs.append(new_lib) - - elif MSVC_VERSION == 8: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VS8.0')) - elif MSVC_VERSION == 7: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VS7.1')) + + # Use the .lib files for the correct architecture + if self.plat_name == 'win32': + suffix = 'win32' else: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VC6')) + # win-amd64 or win-ia64 + suffix = self.plat_name[4:] + new_lib = os.path.join(sys.exec_prefix, 'PCbuild') + if suffix: + new_lib = os.path.join(new_lib, suffix) + self.library_dirs.append(new_lib) # for extensions under Cygwin and AtheOS Python's library directory must be # appended to library_dirs @@ -716,7 +702,7 @@ class build_ext(Command): # to need it mentioned explicitly, though, so that's what we do. # Append '_d' to the python import library on debug builds. if sys.platform == "win32": - from distutils.msvccompiler import MSVCCompiler + from distutils._msvccompiler import MSVCCompiler if not isinstance(self.compiler, MSVCCompiler): template = "python%d%d" if self.debug: diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py new file mode 100644 index 0000000000..b4407543b1 --- /dev/null +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -0,0 +1,160 @@ +"""Tests for distutils._msvccompiler.""" +import sys +import unittest +import os + +from distutils.errors import DistutilsPlatformError +from distutils.tests import support +from test.support import run_unittest + +# A manifest with the only assembly reference being the msvcrt assembly, so +# should have the assembly completely stripped. Note that although the +# assembly has a reference the assembly is removed - that is +# currently a "feature", not a bug :) +_MANIFEST_WITH_ONLY_MSVC_REFERENCE = """\ + + + + + + + + + + + + + + + + + +""" + +# A manifest with references to assemblies other than msvcrt. When processed, +# this assembly should be returned with just the msvcrt part removed. +_MANIFEST_WITH_MULTIPLE_REFERENCES = """\ + + + + + + + + + + + + + + + + + + + + + + +""" + +_CLEANED_MANIFEST = """\ + + + + + + + + + + + + + + + + + + +""" + +SKIP_MESSAGE = (None if sys.platform == "win32" else + "These tests are only for win32") + +@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) +class msvccompilerTestCase(support.TempdirManager, + unittest.TestCase): + + def test_no_compiler(self): + # makes sure query_vcvarsall raises + # a DistutilsPlatformError if the compiler + # is not found + from distutils._msvccompiler import _get_vc_env + def _find_vcvarsall(): + return None + + import distutils._msvccompiler as _msvccompiler + old_find_vcvarsall = _msvccompiler._find_vcvarsall + _msvccompiler._find_vcvarsall = _find_vcvarsall + try: + self.assertRaises(DistutilsPlatformError, _get_vc_env, + 'wont find this version') + finally: + _msvccompiler._find_vcvarsall = old_find_vcvarsall + + def test_remove_visual_c_ref(self): + from distutils._msvccompiler import MSVCCompiler + tempdir = self.mkdtemp() + manifest = os.path.join(tempdir, 'manifest') + f = open(manifest, 'w') + try: + f.write(_MANIFEST_WITH_MULTIPLE_REFERENCES) + finally: + f.close() + + compiler = MSVCCompiler() + compiler._remove_visual_c_ref(manifest) + + # see what we got + f = open(manifest) + try: + # removing trailing spaces + content = '\n'.join([line.rstrip() for line in f.readlines()]) + finally: + f.close() + + # makes sure the manifest was properly cleaned + self.assertEqual(content, _CLEANED_MANIFEST) + + def test_remove_entire_manifest(self): + from distutils._msvccompiler import MSVCCompiler + tempdir = self.mkdtemp() + manifest = os.path.join(tempdir, 'manifest') + f = open(manifest, 'w') + try: + f.write(_MANIFEST_WITH_ONLY_MSVC_REFERENCE) + finally: + f.close() + + compiler = MSVCCompiler() + got = compiler._remove_visual_c_ref(manifest) + self.assertIsNone(got) + + +def test_suite(): + return unittest.makeSuite(msvccompilerTestCase) + +if __name__ == "__main__": + run_unittest(test_suite()) -- cgit v1.2.1 From e1fe1fa3bf99942536db47af587ce5173b7934d0 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 23 May 2015 12:15:57 -0700 Subject: Issue #23970: Fixes bdist_wininst not working on non-Windows platform. --- Lib/distutils/command/bdist_wininst.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py index a3eff7e7cf..0c0e2c1a26 100644 --- a/Lib/distutils/command/bdist_wininst.py +++ b/Lib/distutils/command/bdist_wininst.py @@ -331,8 +331,13 @@ class bdist_wininst(Command): bv = 14.0 else: # for current version - use authoritative check. - from msvcrt import CRT_ASSEMBLY_VERSION - bv = float('.'.join(CRT_ASSEMBLY_VERSION.split('.', 2)[:2])) + try: + from msvcrt import CRT_ASSEMBLY_VERSION + except ImportError: + # cross-building, so assume the latest version + bv = 14.0 + else: + bv = float('.'.join(CRT_ASSEMBLY_VERSION.split('.', 2)[:2])) # wininst-x.y.exe is in the same directory as this file -- cgit v1.2.1 From b5d153863a9e11921546e399111fc3faec12cf3b Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sat, 23 May 2015 17:43:05 -0700 Subject: Version bump for 3.5.0b1. --- Lib/distutils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 37bfd5a8f7..686ca1de88 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ used from a setup script as # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a4" +__version__ = "3.5.0b1" #--end constants-- -- cgit v1.2.1 From a6d79b5164cac2ee3207a00f7ae440e6b2719e0f Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Tue, 28 Jul 2015 15:55:07 +1200 Subject: Issue #23426: run_setup was broken in distutils. Patch from Alexander Belopolsky. --- Lib/distutils/core.py | 5 ++--- Lib/distutils/tests/test_core.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/core.py b/Lib/distutils/core.py index f05b34b295..d603d4a45a 100644 --- a/Lib/distutils/core.py +++ b/Lib/distutils/core.py @@ -204,16 +204,15 @@ def run_setup (script_name, script_args=None, stop_after="run"): global _setup_stop_after, _setup_distribution _setup_stop_after = stop_after - save_argv = sys.argv + save_argv = sys.argv.copy() g = {'__file__': script_name} - l = {} try: try: sys.argv[0] = script_name if script_args is not None: sys.argv[1:] = script_args with open(script_name, 'rb') as f: - exec(f.read(), g, l) + exec(f.read(), g) finally: sys.argv = save_argv _setup_stop_after = None diff --git a/Lib/distutils/tests/test_core.py b/Lib/distutils/tests/test_core.py index 41321f7db4..57856f19b6 100644 --- a/Lib/distutils/tests/test_core.py +++ b/Lib/distutils/tests/test_core.py @@ -28,6 +28,21 @@ from distutils.core import setup setup() """ +setup_does_nothing = """\ +from distutils.core import setup +setup() +""" + + +setup_defines_subclass = """\ +from distutils.core import setup +from distutils.command.install import install as _install + +class install(_install): + sub_commands = _install.sub_commands + ['cmd'] + +setup(cmdclass={'install': install}) +""" class CoreTestCase(support.EnvironGuard, unittest.TestCase): @@ -65,6 +80,21 @@ class CoreTestCase(support.EnvironGuard, unittest.TestCase): distutils.core.run_setup( self.write_setup(setup_using___file__)) + def test_run_setup_preserves_sys_argv(self): + # Make sure run_setup does not clobber sys.argv + argv_copy = sys.argv.copy() + distutils.core.run_setup( + self.write_setup(setup_does_nothing)) + self.assertEqual(sys.argv, argv_copy) + + def test_run_setup_defines_subclass(self): + # Make sure the script can use __file__; if that's missing, the test + # setup.py script will raise NameError. + dist = distutils.core.run_setup( + self.write_setup(setup_defines_subclass)) + install = dist.get_command_obj('install') + self.assertIn('cmd', install.sub_commands) + def test_run_setup_uses_current_dir(self): # This tests that the setup script is run with the current directory # as its own current directory; this was temporarily broken by a -- cgit v1.2.1 From e717aba805d9165a8600a6f13d15f69491822c13 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 30 Jul 2015 11:51:06 -0700 Subject: Update default msvccompiler link options to match the options used for core builds. This ensures that wheels will work when moved to machines that have the same subset of the MSVC libraries as a regular CPython install. Specifically, vcruntime##0.dll may not be installed, and should not be a dependency. --- Lib/distutils/_msvccompiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 896d9d927f..4e2eed72a9 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -207,10 +207,10 @@ class MSVCCompiler(CCompiler) : ] self.ldflags_shared = [ - '/nologo', '/DLL', '/INCREMENTAL:NO' + '/nologo', '/DLL', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib' ] self.ldflags_shared_debug = [ - '/nologo', '/DLL', '/INCREMENTAL:no', '/DEBUG:FULL' + '/nologo', '/DLL', '/INCREMENTAL:no', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib' ] self.ldflags_static = [ '/nologo' -- cgit v1.2.1 From 53e82ced429b80309bf8bdd7bee03a83c16ea917 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 5 Aug 2015 11:39:19 -0700 Subject: Issue #24798: _msvccompiler.py doesn't properly support manifests --- Lib/distutils/_msvccompiler.py | 167 +++++++++---------------------- Lib/distutils/tests/test_msvccompiler.py | 121 ---------------------- 2 files changed, 50 insertions(+), 238 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 4e2eed72a9..b344616e60 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -15,7 +15,6 @@ for older versions in distutils.msvc9compiler and distutils.msvccompiler. import os import subprocess -import re from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ CompileError, LibError, LinkError @@ -182,7 +181,8 @@ class MSVCCompiler(CCompiler) : raise DistutilsPlatformError("Unable to find a compatible " "Visual Studio installation.") - paths = vc_env.get('path', '').split(os.pathsep) + self._paths = vc_env.get('path', '') + paths = self._paths.split(os.pathsep) self.cc = _find_exe("cl.exe", paths) self.linker = _find_exe("link.exe", paths) self.lib = _find_exe("lib.exe", paths) @@ -199,23 +199,41 @@ class MSVCCompiler(CCompiler) : self.add_library_dir(dir) self.preprocess_options = None + # Use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib + # later to dynamically link to ucrtbase but not vcruntime. self.compile_options = [ - '/nologo', '/Ox', '/MD', '/W3', '/GL', '/DNDEBUG' + '/nologo', '/Ox', '/MT', '/W3', '/GL', '/DNDEBUG' ] self.compile_options_debug = [ - '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' + '/nologo', '/Od', '/MTd', '/Zi', '/W3', '/D_DEBUG' ] - self.ldflags_shared = [ - '/nologo', '/DLL', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib' + ldflags = [ + '/nologo', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib', ] - self.ldflags_shared_debug = [ - '/nologo', '/DLL', '/INCREMENTAL:no', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib' - ] - self.ldflags_static = [ - '/nologo' + ldflags_debug = [ + '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib', ] + self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] + self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1'] + self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] + self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] + self.ldflags_static = [*ldflags] + self.ldflags_static_debug = [*ldflags_debug] + + self._ldflags = { + (CCompiler.EXECUTABLE, None): self.ldflags_exe, + (CCompiler.EXECUTABLE, False): self.ldflags_exe, + (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug, + (CCompiler.SHARED_OBJECT, None): self.ldflags_shared, + (CCompiler.SHARED_OBJECT, False): self.ldflags_shared, + (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug, + (CCompiler.SHARED_LIBRARY, None): self.ldflags_static, + (CCompiler.SHARED_LIBRARY, False): self.ldflags_static, + (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug, + } + self.initialized = True # -- Worker methods ------------------------------------------------ @@ -224,9 +242,12 @@ class MSVCCompiler(CCompiler) : source_filenames, strip_dir=0, output_dir=''): - ext_map = {ext: self.obj_extension for ext in self.src_extensions} - ext_map.update((ext, self.res_extension) - for ext in self._rc_extensions + self._mc_extensions) + ext_map = { + **{ext: self.obj_extension for ext in self.src_extensions}, + **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions}, + } + + output_dir = output_dir or '' def make_out_path(p): base, ext = os.path.splitext(p) @@ -237,18 +258,17 @@ class MSVCCompiler(CCompiler) : if base.startswith((os.path.sep, os.path.altsep)): base = base[1:] try: - return base + ext_map[ext] + # XXX: This may produce absurdly long paths. We should check + # the length of the result and trim base until we fit within + # 260 characters. + return os.path.join(output_dir, base + ext_map[ext]) except LookupError: # Better to raise an exception instead of silently continuing # and later complain about sources and targets having # different lengths raise CompileError("Don't know how to compile {}".format(p)) - output_dir = output_dir or '' - return [ - os.path.join(output_dir, make_out_path(src_name)) - for src_name in source_filenames - ] + return list(map(make_out_path, source_filenames)) def compile(self, sources, @@ -359,6 +379,7 @@ class MSVCCompiler(CCompiler) : if debug: pass # XXX what goes here? try: + log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args)) self.spawn([self.lib] + lib_args) except DistutilsExecError as msg: raise LibError(msg) @@ -399,14 +420,9 @@ class MSVCCompiler(CCompiler) : output_filename = os.path.join(output_dir, output_filename) if self._need_link(objects, output_filename): - ldflags = (self.ldflags_shared_debug if debug - else self.ldflags_shared) - if target_desc == CCompiler.EXECUTABLE: - ldflags = ldflags[1:] + ldflags = self._ldflags[target_desc, debug] - export_opts = [] - for sym in (export_symbols or []): - export_opts.append("/EXPORT:" + sym) + export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])] ld_args = (ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename]) @@ -425,8 +441,6 @@ class MSVCCompiler(CCompiler) : self.library_filename(dll_name)) ld_args.append ('/IMPLIB:' + implib_file) - self.manifest_setup_ldargs(output_filename, build_temp, ld_args) - if extra_preargs: ld_args[:0] = extra_preargs if extra_postargs: @@ -434,101 +448,20 @@ class MSVCCompiler(CCompiler) : self.mkpath(os.path.dirname(output_filename)) try: + log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args)) self.spawn([self.linker] + ld_args) except DistutilsExecError as msg: raise LinkError(msg) - - # embed the manifest - # XXX - this is somewhat fragile - if mt.exe fails, distutils - # will still consider the DLL up-to-date, but it will not have a - # manifest. Maybe we should link to a temp file? OTOH, that - # implies a build environment error that shouldn't go undetected. - mfinfo = self.manifest_get_embed_info(target_desc, ld_args) - if mfinfo is not None: - mffilename, mfid = mfinfo - out_arg = '-outputresource:{};{}'.format(output_filename, mfid) - try: - self.spawn([self.mt, '-nologo', '-manifest', - mffilename, out_arg]) - except DistutilsExecError as msg: - raise LinkError(msg) else: log.debug("skipping %s (up-to-date)", output_filename) - def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): - # If we need a manifest at all, an embedded manifest is recommended. - # See MSDN article titled - # "How to: Embed a Manifest Inside a C/C++ Application" - # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) - # Ask the linker to generate the manifest in the temp dir, so - # we can check it, and possibly embed it, later. - temp_manifest = os.path.join( - build_temp, - os.path.basename(output_filename) + ".manifest") - ld_args.append('/MANIFESTFILE:' + temp_manifest) - - def manifest_get_embed_info(self, target_desc, ld_args): - # If a manifest should be embedded, return a tuple of - # (manifest_filename, resource_id). Returns None if no manifest - # should be embedded. See http://bugs.python.org/issue7833 for why - # we want to avoid any manifest for extension modules if we can) - for arg in ld_args: - if arg.startswith("/MANIFESTFILE:"): - temp_manifest = arg.split(":", 1)[1] - break - else: - # no /MANIFESTFILE so nothing to do. - return None - if target_desc == CCompiler.EXECUTABLE: - # by default, executables always get the manifest with the - # CRT referenced. - mfid = 1 - else: - # Extension modules try and avoid any manifest if possible. - mfid = 2 - temp_manifest = self._remove_visual_c_ref(temp_manifest) - if temp_manifest is None: - return None - return temp_manifest, mfid - - def _remove_visual_c_ref(self, manifest_file): + def spawn(self, cmd): + old_path = os.getenv('path') try: - # Remove references to the Visual C runtime, so they will - # fall through to the Visual C dependency of Python.exe. - # This way, when installed for a restricted user (e.g. - # runtimes are not in WinSxS folder, but in Python's own - # folder), the runtimes do not need to be in every folder - # with .pyd's. - # Returns either the filename of the modified manifest or - # None if no manifest should be embedded. - manifest_f = open(manifest_file) - try: - manifest_buf = manifest_f.read() - finally: - manifest_f.close() - pattern = re.compile( - r"""|)""", - re.DOTALL) - manifest_buf = re.sub(pattern, "", manifest_buf) - pattern = "\s*" - manifest_buf = re.sub(pattern, "", manifest_buf) - # Now see if any other assemblies are referenced - if not, we - # don't want a manifest embedded. - pattern = re.compile( - r"""|)""", re.DOTALL) - if re.search(pattern, manifest_buf) is None: - return None - - manifest_f = open(manifest_file, 'w') - try: - manifest_f.write(manifest_buf) - return manifest_file - finally: - manifest_f.close() - except OSError: - pass + os.environ['path'] = self._paths + return super().spawn(cmd) + finally: + os.environ['path'] = old_path # -- Miscellaneous methods ----------------------------------------- # These are all used by the 'gen_lib_options() function, in diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py index b4407543b1..1f8890792e 100644 --- a/Lib/distutils/tests/test_msvccompiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -7,88 +7,6 @@ from distutils.errors import DistutilsPlatformError from distutils.tests import support from test.support import run_unittest -# A manifest with the only assembly reference being the msvcrt assembly, so -# should have the assembly completely stripped. Note that although the -# assembly has a reference the assembly is removed - that is -# currently a "feature", not a bug :) -_MANIFEST_WITH_ONLY_MSVC_REFERENCE = """\ - - - - - - - - - - - - - - - - - -""" - -# A manifest with references to assemblies other than msvcrt. When processed, -# this assembly should be returned with just the msvcrt part removed. -_MANIFEST_WITH_MULTIPLE_REFERENCES = """\ - - - - - - - - - - - - - - - - - - - - - - -""" - -_CLEANED_MANIFEST = """\ - - - - - - - - - - - - - - - - - - -""" SKIP_MESSAGE = (None if sys.platform == "win32" else "These tests are only for win32") @@ -114,45 +32,6 @@ class msvccompilerTestCase(support.TempdirManager, finally: _msvccompiler._find_vcvarsall = old_find_vcvarsall - def test_remove_visual_c_ref(self): - from distutils._msvccompiler import MSVCCompiler - tempdir = self.mkdtemp() - manifest = os.path.join(tempdir, 'manifest') - f = open(manifest, 'w') - try: - f.write(_MANIFEST_WITH_MULTIPLE_REFERENCES) - finally: - f.close() - - compiler = MSVCCompiler() - compiler._remove_visual_c_ref(manifest) - - # see what we got - f = open(manifest) - try: - # removing trailing spaces - content = '\n'.join([line.rstrip() for line in f.readlines()]) - finally: - f.close() - - # makes sure the manifest was properly cleaned - self.assertEqual(content, _CLEANED_MANIFEST) - - def test_remove_entire_manifest(self): - from distutils._msvccompiler import MSVCCompiler - tempdir = self.mkdtemp() - manifest = os.path.join(tempdir, 'manifest') - f = open(manifest, 'w') - try: - f.write(_MANIFEST_WITH_ONLY_MSVC_REFERENCE) - finally: - f.close() - - compiler = MSVCCompiler() - got = compiler._remove_visual_c_ref(manifest) - self.assertIsNone(got) - - def test_suite(): return unittest.makeSuite(msvccompilerTestCase) -- cgit v1.2.1 From bafbebbddec0c6f005de9a456530057daa0e9d06 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 5 Aug 2015 11:48:14 -0700 Subject: Rebuild wininst-14.0[-amd64].exe with updated tools. --- Lib/distutils/command/wininst-14.0-amd64.exe | Bin 84480 -> 136192 bytes Lib/distutils/command/wininst-14.0.exe | Bin 75264 -> 129024 bytes 2 files changed, 0 insertions(+), 0 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/wininst-14.0-amd64.exe b/Lib/distutils/command/wininst-14.0-amd64.exe index 43b85b6d4f..7a5e78d52b 100644 Binary files a/Lib/distutils/command/wininst-14.0-amd64.exe and b/Lib/distutils/command/wininst-14.0-amd64.exe differ diff --git a/Lib/distutils/command/wininst-14.0.exe b/Lib/distutils/command/wininst-14.0.exe index 764524d746..cc43296b67 100644 Binary files a/Lib/distutils/command/wininst-14.0.exe and b/Lib/distutils/command/wininst-14.0.exe differ -- cgit v1.2.1 From be3e94a3ac84c4b4149463e18c6dec6588ef5039 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 8 Sep 2015 21:39:01 -0700 Subject: Issue #25027: Reverts partial-static build options and adds vcruntime140.dll to Windows installation. --- Lib/distutils/_msvccompiler.py | 76 ++++++++++++++++++++++++++------ Lib/distutils/tests/test_msvccompiler.py | 58 +++++++++++++++++++++--- 2 files changed, 116 insertions(+), 18 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index b344616e60..82b78a0ffe 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -14,6 +14,8 @@ for older versions in distutils.msvc9compiler and distutils.msvccompiler. # ported to VS 2015 by Steve Dower import os +import shutil +import stat import subprocess from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ @@ -25,7 +27,7 @@ from distutils.util import get_platform import winreg from itertools import count -def _find_vcvarsall(): +def _find_vcvarsall(plat_spec): with winreg.OpenKeyEx( winreg.HKEY_LOCAL_MACHINE, r"Software\Microsoft\VisualStudio\SxS\VC7", @@ -33,7 +35,7 @@ def _find_vcvarsall(): ) as key: if not key: log.debug("Visual C++ is not registered") - return None + return None, None best_version = 0 best_dir = None @@ -51,14 +53,23 @@ def _find_vcvarsall(): best_version, best_dir = version, vc_dir if not best_version: log.debug("No suitable Visual C++ version found") - return None + return None, None vcvarsall = os.path.join(best_dir, "vcvarsall.bat") if not os.path.isfile(vcvarsall): log.debug("%s cannot be found", vcvarsall) - return None + return None, None - return vcvarsall + vcruntime = None + vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST.get(plat_spec) + if vcruntime_spec: + vcruntime = os.path.join(best_dir, + vcruntime_spec.format(best_version)) + if not os.path.isfile(vcruntime): + log.debug("%s cannot be found", vcruntime) + vcruntime = None + + return vcvarsall, vcruntime def _get_vc_env(plat_spec): if os.getenv("DISTUTILS_USE_SDK"): @@ -67,7 +78,7 @@ def _get_vc_env(plat_spec): for key, value in os.environ.items() } - vcvarsall = _find_vcvarsall() + vcvarsall, vcruntime = _find_vcvarsall(plat_spec) if not vcvarsall: raise DistutilsPlatformError("Unable to find vcvarsall.bat") @@ -83,12 +94,16 @@ def _get_vc_env(plat_spec): raise DistutilsPlatformError("Error executing {}" .format(exc.cmd)) - return { + env = { key.lower(): value for key, _, value in (line.partition('=') for line in out.splitlines()) if key and value } + + if vcruntime: + env['py_vcruntime_redist'] = vcruntime + return env def _find_exe(exe, paths=None): """Return path to an MSVC executable program. @@ -115,6 +130,20 @@ PLAT_TO_VCVARS = { 'win-amd64' : 'amd64', } +# A map keyed by get_platform() return values to the file under +# the VC install directory containing the vcruntime redistributable. +_VCVARS_PLAT_TO_VCRUNTIME_REDIST = { + 'x86' : 'redist\\x86\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', + 'amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', + 'x86_amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', +} + +# A set containing the DLLs that are guaranteed to be available for +# all micro versions of this Python version. Known extension +# dependencies that are not in this set will be copied to the output +# path. +_BUNDLED_DLLS = frozenset(['vcruntime140.dll']) + class MSVCCompiler(CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, as defined by the CCompiler abstract class.""" @@ -189,6 +218,7 @@ class MSVCCompiler(CCompiler) : self.rc = _find_exe("rc.exe", paths) # resource compiler self.mc = _find_exe("mc.exe", paths) # message compiler self.mt = _find_exe("mt.exe", paths) # message compiler + self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '') for dir in vc_env.get('include', '').split(os.pathsep): if dir: @@ -199,20 +229,26 @@ class MSVCCompiler(CCompiler) : self.add_library_dir(dir) self.preprocess_options = None - # Use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib + # If vcruntime_redist is available, link against it dynamically. Otherwise, + # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib # later to dynamically link to ucrtbase but not vcruntime. self.compile_options = [ - '/nologo', '/Ox', '/MT', '/W3', '/GL', '/DNDEBUG' + '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG' ] + self.compile_options.append('/MD' if self._vcruntime_redist else '/MT') + self.compile_options_debug = [ - '/nologo', '/Od', '/MTd', '/Zi', '/W3', '/D_DEBUG' + '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' ] ldflags = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib', + '/nologo', '/INCREMENTAL:NO', '/LTCG' ] + if not self._vcruntime_redist: + ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib')) + ldflags_debug = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib', + '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' ] self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] @@ -446,15 +482,29 @@ class MSVCCompiler(CCompiler) : if extra_postargs: ld_args.extend(extra_postargs) - self.mkpath(os.path.dirname(output_filename)) + output_dir = os.path.dirname(os.path.abspath(output_filename)) + self.mkpath(output_dir) try: log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args)) self.spawn([self.linker] + ld_args) + self._copy_vcruntime(output_dir) except DistutilsExecError as msg: raise LinkError(msg) else: log.debug("skipping %s (up-to-date)", output_filename) + def _copy_vcruntime(self, output_dir): + vcruntime = self._vcruntime_redist + if not vcruntime or not os.path.isfile(vcruntime): + return + + if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS: + return + + log.debug('Copying "%s"', vcruntime) + vcruntime = shutil.copy(vcruntime, output_dir) + os.chmod(vcruntime, stat.S_IWRITE) + def spawn(self, cmd): old_path = os.getenv('path') try: diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py index 1f8890792e..0b8a69fa5a 100644 --- a/Lib/distutils/tests/test_msvccompiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -3,6 +3,8 @@ import sys import unittest import os +import distutils._msvccompiler as _msvccompiler + from distutils.errors import DistutilsPlatformError from distutils.tests import support from test.support import run_unittest @@ -19,19 +21,65 @@ class msvccompilerTestCase(support.TempdirManager, # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found - from distutils._msvccompiler import _get_vc_env - def _find_vcvarsall(): - return None + def _find_vcvarsall(plat_spec): + return None, None - import distutils._msvccompiler as _msvccompiler old_find_vcvarsall = _msvccompiler._find_vcvarsall _msvccompiler._find_vcvarsall = _find_vcvarsall try: - self.assertRaises(DistutilsPlatformError, _get_vc_env, + self.assertRaises(DistutilsPlatformError, + _msvccompiler._get_vc_env, 'wont find this version') finally: _msvccompiler._find_vcvarsall = old_find_vcvarsall + def test_compiler_options(self): + # suppress path to vcruntime from _find_vcvarsall to + # check that /MT is added to compile options + old_find_vcvarsall = _msvccompiler._find_vcvarsall + def _find_vcvarsall(plat_spec): + return old_find_vcvarsall(plat_spec)[0], None + _msvccompiler._find_vcvarsall = _find_vcvarsall + try: + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + + self.assertIn('/MT', compiler.compile_options) + self.assertNotIn('/MD', compiler.compile_options) + finally: + _msvccompiler._find_vcvarsall = old_find_vcvarsall + + def test_vcruntime_copy(self): + # force path to a known file - it doesn't matter + # what we copy as long as its name is not in + # _msvccompiler._BUNDLED_DLLS + old_find_vcvarsall = _msvccompiler._find_vcvarsall + def _find_vcvarsall(plat_spec): + return old_find_vcvarsall(plat_spec)[0], __file__ + _msvccompiler._find_vcvarsall = _find_vcvarsall + try: + tempdir = self.mkdtemp() + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + compiler._copy_vcruntime(tempdir) + + self.assertTrue(os.path.isfile(os.path.join( + tempdir, os.path.basename(__file__)))) + finally: + _msvccompiler._find_vcvarsall = old_find_vcvarsall + + def test_vcruntime_skip_copy(self): + tempdir = self.mkdtemp() + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + dll = compiler._vcruntime_redist + self.assertTrue(os.path.isfile(dll)) + + compiler._copy_vcruntime(tempdir) + + self.assertFalse(os.path.isfile(os.path.join( + tempdir, os.path.basename(dll)))) + def test_suite(): return unittest.makeSuite(msvccompilerTestCase) -- cgit v1.2.1 From f6ef491db26ec2f3efdb1a44ea00a2fce1b426b5 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 8 Sep 2015 23:42:51 -0700 Subject: Moves distutils test import within skippable class. --- Lib/distutils/tests/test_msvccompiler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py index 0b8a69fa5a..874d6035e8 100644 --- a/Lib/distutils/tests/test_msvccompiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -3,8 +3,6 @@ import sys import unittest import os -import distutils._msvccompiler as _msvccompiler - from distutils.errors import DistutilsPlatformError from distutils.tests import support from test.support import run_unittest @@ -18,6 +16,7 @@ class msvccompilerTestCase(support.TempdirManager, unittest.TestCase): def test_no_compiler(self): + import distutils._msvccompiler as _msvccompiler # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found @@ -34,6 +33,7 @@ class msvccompilerTestCase(support.TempdirManager, _msvccompiler._find_vcvarsall = old_find_vcvarsall def test_compiler_options(self): + import distutils._msvccompiler as _msvccompiler # suppress path to vcruntime from _find_vcvarsall to # check that /MT is added to compile options old_find_vcvarsall = _msvccompiler._find_vcvarsall @@ -50,6 +50,7 @@ class msvccompilerTestCase(support.TempdirManager, _msvccompiler._find_vcvarsall = old_find_vcvarsall def test_vcruntime_copy(self): + import distutils._msvccompiler as _msvccompiler # force path to a known file - it doesn't matter # what we copy as long as its name is not in # _msvccompiler._BUNDLED_DLLS @@ -69,6 +70,8 @@ class msvccompilerTestCase(support.TempdirManager, _msvccompiler._find_vcvarsall = old_find_vcvarsall def test_vcruntime_skip_copy(self): + import distutils._msvccompiler as _msvccompiler + tempdir = self.mkdtemp() compiler = _msvccompiler.MSVCCompiler() compiler.initialize() -- cgit v1.2.1 From 7577a73790da92ade16ff6611489727377090da7 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Wed, 9 Sep 2015 06:54:57 -0700 Subject: Whitespace fixes to make the commit hook on hg.python.org happy. --- Lib/distutils/_msvccompiler.py | 4 ++-- Lib/distutils/tests/test_msvccompiler.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 82b78a0ffe..03a5f10ee7 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -100,7 +100,7 @@ def _get_vc_env(plat_spec): (line.partition('=') for line in out.splitlines()) if key and value } - + if vcruntime: env['py_vcruntime_redist'] = vcruntime return env @@ -236,7 +236,7 @@ class MSVCCompiler(CCompiler) : '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG' ] self.compile_options.append('/MD' if self._vcruntime_redist else '/MT') - + self.compile_options_debug = [ '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' ] diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py index 874d6035e8..c4d911ff83 100644 --- a/Lib/distutils/tests/test_msvccompiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -77,7 +77,7 @@ class msvccompilerTestCase(support.TempdirManager, compiler.initialize() dll = compiler._vcruntime_redist self.assertTrue(os.path.isfile(dll)) - + compiler._copy_vcruntime(tempdir) self.assertFalse(os.path.isfile(os.path.join( -- cgit v1.2.1 From c04574efb5b8c21be304320e3332075126578be6 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 5 Oct 2015 10:35:00 -0700 Subject: Issue #25316: distutils raises OSError instead of DistutilsPlatformError when MSVC is not installed. --- Lib/distutils/_msvccompiler.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 03a5f10ee7..10a9ffda24 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -28,15 +28,17 @@ import winreg from itertools import count def _find_vcvarsall(plat_spec): - with winreg.OpenKeyEx( - winreg.HKEY_LOCAL_MACHINE, - r"Software\Microsoft\VisualStudio\SxS\VC7", - access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY - ) as key: - if not key: - log.debug("Visual C++ is not registered") - return None, None + try: + key = winreg.OpenKeyEx( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) + except OSError: + log.debug("Visual C++ is not registered") + return None, None + with key: best_version = 0 best_dir = None for i in count(): -- cgit v1.2.1 From 8ae48c0afb39a692964b901080251947fa1816cc Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 16 Jan 2016 12:39:10 -0800 Subject: Issue #25850: Use cross-compilation by default for 64-bit Windows. --- Lib/distutils/_msvccompiler.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 10a9ffda24..d0ba7d6d1e 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -125,11 +125,11 @@ def _find_exe(exe, paths=None): return exe # A map keyed by get_platform() return values to values accepted by -# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is -# the param to cross-compile on x86 targetting amd64.) +# 'vcvarsall.bat'. Always cross-compile from x86 to work with the +# lighter-weight MSVC installs that do not include native 64-bit tools. PLAT_TO_VCVARS = { 'win32' : 'x86', - 'win-amd64' : 'amd64', + 'win-amd64' : 'x86_amd64', } # A map keyed by get_platform() return values to the file under @@ -193,19 +193,8 @@ class MSVCCompiler(CCompiler) : raise DistutilsPlatformError("--plat-name must be one of {}" .format(tuple(PLAT_TO_VCVARS))) - # On x86, 'vcvarsall.bat amd64' creates an env that doesn't work; - # to cross compile, you use 'x86_amd64'. - # On AMD64, 'vcvarsall.bat amd64' is a native build env; to cross - # compile use 'x86' (ie, it runs the x86 compiler directly) - if plat_name == get_platform() or plat_name == 'win32': - # native build or cross-compile to win32 - plat_spec = PLAT_TO_VCVARS[plat_name] - else: - # cross compile from win32 -> some 64bit - plat_spec = '{}_{}'.format( - PLAT_TO_VCVARS[get_platform()], - PLAT_TO_VCVARS[plat_name] - ) + # Get the vcvarsall.bat spec for the requested platform. + plat_spec = PLAT_TO_VCVARS[plat_name] vc_env = _get_vc_env(plat_spec) if not vc_env: -- cgit v1.2.1 From 94ecea3cfb803f3539c48925804e92d2b954d5aa Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 16 Jan 2016 13:54:53 -0800 Subject: Issue #26071: bdist_wininst created binaries fail to start and find 32bit Python --- Lib/distutils/command/wininst-14.0-amd64.exe | Bin 136192 -> 589824 bytes Lib/distutils/command/wininst-14.0.exe | Bin 129024 -> 460288 bytes 2 files changed, 0 insertions(+), 0 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/wininst-14.0-amd64.exe b/Lib/distutils/command/wininst-14.0-amd64.exe index 7a5e78d52b..22299543a9 100644 Binary files a/Lib/distutils/command/wininst-14.0-amd64.exe and b/Lib/distutils/command/wininst-14.0-amd64.exe differ diff --git a/Lib/distutils/command/wininst-14.0.exe b/Lib/distutils/command/wininst-14.0.exe index cc43296b67..0dac1103d9 100644 Binary files a/Lib/distutils/command/wininst-14.0.exe and b/Lib/distutils/command/wininst-14.0.exe differ -- cgit v1.2.1 From f10f99298e48e3e471801ff5454a0b2af85f7c50 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 18 Jan 2016 12:15:08 +0100 Subject: subprocess._optim_args_from_interpreter_flags() Issue #26100: * Add subprocess._optim_args_from_interpreter_flags() * Add test.support.optim_args_from_interpreter_flags() * Use new functions in distutils, test_cmd_line_script, test_compileall and test_inspect The change enables test_details() test of test_inspect when -O or -OO command line option is used. --- Lib/distutils/util.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index e423325de4..fdcf6fabae 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -7,8 +7,8 @@ one of the other *util.py modules. import os import re import importlib.util -import sys import string +import sys from distutils.errors import DistutilsPlatformError from distutils.dep_util import newer from distutils.spawn import spawn @@ -350,6 +350,11 @@ def byte_compile (py_files, generated in indirect mode; unless you know what you're doing, leave it set to None. """ + + # Late import to fix a bootstrap issue: _posixsubprocess is built by + # setup.py, but setup.py uses distutils. + import subprocess + # nothing is done if sys.dont_write_bytecode is True if sys.dont_write_bytecode: raise DistutilsByteCompileError('byte-compiling is disabled.') @@ -412,11 +417,9 @@ byte_compile(files, optimize=%r, force=%r, script.close() - cmd = [sys.executable, script_name] - if optimize == 1: - cmd.insert(1, "-O") - elif optimize == 2: - cmd.insert(1, "-OO") + cmd = [sys.executable] + cmd.extend(subprocess._optim_args_from_interpreter_flags()) + cmd.append(script_name) spawn(cmd, dry_run=dry_run) execute(os.remove, (script_name,), "removing %s" % script_name, dry_run=dry_run) -- cgit v1.2.1 From 2b442f7d5b61dcefc5a7a18a6e7af9de5983790c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 11 Feb 2016 13:10:36 +0200 Subject: Issue #25985: sys.version_info is now used instead of sys.version to format short Python version. --- Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/command/bdist_wininst.py | 2 +- Lib/distutils/command/build.py | 4 ++-- Lib/distutils/command/install.py | 4 ++-- Lib/distutils/command/install_egg_info.py | 4 ++-- Lib/distutils/sysconfig.py | 2 +- Lib/distutils/tests/test_build.py | 5 +++-- 7 files changed, 12 insertions(+), 11 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py index b3cfe9ceff..f6c21aee44 100644 --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -199,7 +199,7 @@ class bdist_msi(Command): target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" - target_version = sys.version[0:3] + target_version = '%d.%d' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py index 0c0e2c1a26..d3e1d3af22 100644 --- a/Lib/distutils/command/bdist_wininst.py +++ b/Lib/distutils/command/bdist_wininst.py @@ -141,7 +141,7 @@ class bdist_wininst(Command): target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" - target_version = sys.version[0:3] + target_version = '%d.%d' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, diff --git a/Lib/distutils/command/build.py b/Lib/distutils/command/build.py index 337dd0bfc1..c6f52e61e1 100644 --- a/Lib/distutils/command/build.py +++ b/Lib/distutils/command/build.py @@ -81,7 +81,7 @@ class build(Command): "--plat-name only supported on Windows (try " "using './configure --help' on your platform)") - plat_specifier = ".%s-%s" % (self.plat_name, sys.version[0:3]) + plat_specifier = ".%s-%d.%d" % (self.plat_name, *sys.version_info[:2]) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build @@ -114,7 +114,7 @@ class build(Command): 'temp' + plat_specifier) if self.build_scripts is None: self.build_scripts = os.path.join(self.build_base, - 'scripts-' + sys.version[0:3]) + 'scripts-%d.%d' % sys.version_info[:2]) if self.executable is None: self.executable = os.path.normpath(sys.executable) diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index 67db007a02..9474e9c599 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -290,8 +290,8 @@ class install(Command): 'dist_version': self.distribution.get_version(), 'dist_fullname': self.distribution.get_fullname(), 'py_version': py_version, - 'py_version_short': py_version[0:3], - 'py_version_nodot': py_version[0] + py_version[2], + 'py_version_short': '%d.%d' % sys.version_info[:2], + 'py_version_nodot': '%d%d' % sys.version_info[:2], 'sys_prefix': prefix, 'prefix': prefix, 'sys_exec_prefix': exec_prefix, diff --git a/Lib/distutils/command/install_egg_info.py b/Lib/distutils/command/install_egg_info.py index c2a7d649c0..0ddc7367cc 100644 --- a/Lib/distutils/command/install_egg_info.py +++ b/Lib/distutils/command/install_egg_info.py @@ -21,10 +21,10 @@ class install_egg_info(Command): def finalize_options(self): self.set_undefined_options('install_lib',('install_dir','install_dir')) - basename = "%s-%s-py%s.egg-info" % ( + basename = "%s-%s-py%d.%d.egg-info" % ( to_filename(safe_name(self.distribution.get_name())), to_filename(safe_version(self.distribution.get_version())), - sys.version[:3] + *sys.version_info[:2] ) self.target = os.path.join(self.install_dir, basename) self.outputs = [self.target] diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 573724ddd7..d203f8e42b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -70,7 +70,7 @@ def get_python_version(): leaving off the patchlevel. Sample return values could be '1.5' or '2.2'. """ - return sys.version[:3] + return '%d.%d' % sys.version_info[:2] def get_python_inc(plat_specific=0, prefix=None): diff --git a/Lib/distutils/tests/test_build.py b/Lib/distutils/tests/test_build.py index 3391f36d4b..b020a5ba35 100644 --- a/Lib/distutils/tests/test_build.py +++ b/Lib/distutils/tests/test_build.py @@ -27,7 +27,7 @@ class BuildTestCase(support.TempdirManager, # build_platlib is 'build/lib.platform-x.x[-pydebug]' # examples: # build/lib.macosx-10.3-i386-2.7 - plat_spec = '.%s-%s' % (cmd.plat_name, sys.version[0:3]) + plat_spec = '.%s-%d.%d' % (cmd.plat_name, *sys.version_info[:2]) if hasattr(sys, 'gettotalrefcount'): self.assertTrue(cmd.build_platlib.endswith('-pydebug')) plat_spec += '-pydebug' @@ -42,7 +42,8 @@ class BuildTestCase(support.TempdirManager, self.assertEqual(cmd.build_temp, wanted) # build_scripts is build/scripts-x.x - wanted = os.path.join(cmd.build_base, 'scripts-' + sys.version[0:3]) + wanted = os.path.join(cmd.build_base, + 'scripts-%d.%d' % sys.version_info[:2]) self.assertEqual(cmd.build_scripts, wanted) # executable is os.path.normpath(sys.executable) -- cgit v1.2.1 From 713ff3df97481896d5cca05a00dc3e216ee80da2 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Thu, 25 Feb 2016 00:56:38 +1100 Subject: Issue #25136: Support Apple Xcode 7's new textual SDK stub libraries. As of Xcode 7, SDKs for Apple platforms now include textual-format stub libraries whose file names have a .tbd extension rather than the standard OS X .dylib extension. The Apple compiler tool chain handles these stub libraries transparently and the installed system shared libraries are still .dylibs. However, the new stub libraries cause problems for third-party programs that support building with Apple SDKs and make build-time decisions based on the presence or paths of system-supplied shared libraries in the SDK. In particular, building Python itself with an SDK fails to find system-supplied libraries during setup.py's build of standard library extension modules. The solution is to have find_library_file() in Distutils search for .tbd files, along with the existing types (.a, .so, and .dylib). Patch by Tim Smith. --- Lib/distutils/ccompiler.py | 4 ++-- Lib/distutils/unixccompiler.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py index 82fd7d5c4d..b71d1d39bc 100644 --- a/Lib/distutils/ccompiler.py +++ b/Lib/distutils/ccompiler.py @@ -875,9 +875,9 @@ main (int argc, char **argv) { def library_filename(self, libname, lib_type='static', # or 'shared' strip_dir=0, output_dir=''): assert output_dir is not None - if lib_type not in ("static", "shared", "dylib"): + if lib_type not in ("static", "shared", "dylib", "xcode_stub"): raise ValueError( - "'lib_type' must be \"static\", \"shared\" or \"dylib\"") + "'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"") fmt = getattr(self, lib_type + "_lib_format") ext = getattr(self, lib_type + "_lib_extension") diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 094a2f0bd0..92d14dfee7 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -76,7 +76,9 @@ class UnixCCompiler(CCompiler): static_lib_extension = ".a" shared_lib_extension = ".so" dylib_lib_extension = ".dylib" + xcode_stub_lib_extension = ".tbd" static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" + xcode_stub_lib_format = dylib_lib_format if sys.platform == "cygwin": exe_extension = ".exe" @@ -255,12 +257,28 @@ class UnixCCompiler(CCompiler): def find_library_file(self, dirs, lib, debug=0): shared_f = self.library_filename(lib, lib_type='shared') dylib_f = self.library_filename(lib, lib_type='dylib') + xcode_stub_f = self.library_filename(lib, lib_type='xcode_stub') static_f = self.library_filename(lib, lib_type='static') if sys.platform == 'darwin': # On OSX users can specify an alternate SDK using # '-isysroot', calculate the SDK root if it is specified # (and use it further on) + # + # Note that, as of Xcode 7, Apple SDKs may contain textual stub + # libraries with .tbd extensions rather than the normal .dylib + # shared libraries installed in /. The Apple compiler tool + # chain handles this transparently but it can cause problems + # for programs that are being built with an SDK and searching + # for specific libraries. Callers of find_library_file need to + # keep in mind that the base filename of the returned SDK library + # file might have a different extension from that of the library + # file installed on the running system, for example: + # /Applications/Xcode.app/Contents/Developer/Platforms/ + # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/ + # usr/lib/libedit.tbd + # vs + # /usr/lib/libedit.dylib cflags = sysconfig.get_config_var('CFLAGS') m = re.search(r'-isysroot\s+(\S+)', cflags) if m is None: @@ -274,6 +292,7 @@ class UnixCCompiler(CCompiler): shared = os.path.join(dir, shared_f) dylib = os.path.join(dir, dylib_f) static = os.path.join(dir, static_f) + xcode_stub = os.path.join(dir, xcode_stub_f) if sys.platform == 'darwin' and ( dir.startswith('/System/') or ( @@ -282,6 +301,7 @@ class UnixCCompiler(CCompiler): shared = os.path.join(sysroot, dir[1:], shared_f) dylib = os.path.join(sysroot, dir[1:], dylib_f) static = os.path.join(sysroot, dir[1:], static_f) + xcode_stub = os.path.join(sysroot, dir[1:], xcode_stub_f) # We're second-guessing the linker here, with not much hard # data to go on: GCC seems to prefer the shared library, so I'm @@ -289,6 +309,8 @@ class UnixCCompiler(CCompiler): # ignoring even GCC's "-static" option. So sue me. if os.path.exists(dylib): return dylib + elif os.path.exists(xcode_stub): + return xcode_stub elif os.path.exists(shared): return shared elif os.path.exists(static): -- cgit v1.2.1 From 02c7f74cab2d361683d67a57e55dc90c811dcdec Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Sun, 24 Apr 2016 01:55:09 +0300 Subject: Issue #26089: Remove duplicate field 'license' from DistributionMetadata It was renamed to 'license' in 178d19cff163. Patch by Augustin Laville. --- Lib/distutils/dist.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py index ffb33ff645..62a24516cf 100644 --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -1018,8 +1018,7 @@ class DistributionMetadata: "maintainer", "maintainer_email", "url", "license", "description", "long_description", "keywords", "platforms", "fullname", "contact", - "contact_email", "license", "classifiers", - "download_url", + "contact_email", "classifiers", "download_url", # PEP 314 "provides", "requires", "obsoletes", ) -- cgit v1.2.1 From 3e9690b3b9ac10e52a2f6b8c001b5b93887dcd9d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 24 Apr 2016 13:25:01 +0300 Subject: Issue #23277: Remove more unused sys and os imports. --- Lib/distutils/tests/test_clean.py | 1 - Lib/distutils/tests/test_config.py | 1 - Lib/distutils/tests/test_install_data.py | 1 - Lib/distutils/tests/test_install_headers.py | 1 - Lib/distutils/tests/test_unixccompiler.py | 1 - 5 files changed, 5 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_clean.py b/Lib/distutils/tests/test_clean.py index b64f300a04..df88ec1e34 100644 --- a/Lib/distutils/tests/test_clean.py +++ b/Lib/distutils/tests/test_clean.py @@ -1,5 +1,4 @@ """Tests for distutils.command.clean.""" -import sys import os import unittest import getpass diff --git a/Lib/distutils/tests/test_config.py b/Lib/distutils/tests/test_config.py index 4de825a81e..0929f8a47d 100644 --- a/Lib/distutils/tests/test_config.py +++ b/Lib/distutils/tests/test_config.py @@ -1,5 +1,4 @@ """Tests for distutils.pypirc.pypirc.""" -import sys import os import unittest import tempfile diff --git a/Lib/distutils/tests/test_install_data.py b/Lib/distutils/tests/test_install_data.py index 4d8c00acb9..d73624d00b 100644 --- a/Lib/distutils/tests/test_install_data.py +++ b/Lib/distutils/tests/test_install_data.py @@ -1,5 +1,4 @@ """Tests for distutils.command.install_data.""" -import sys import os import unittest import getpass diff --git a/Lib/distutils/tests/test_install_headers.py b/Lib/distutils/tests/test_install_headers.py index d953157bb7..d9ed6b7fd2 100644 --- a/Lib/distutils/tests/test_install_headers.py +++ b/Lib/distutils/tests/test_install_headers.py @@ -1,5 +1,4 @@ """Tests for distutils.command.install_headers.""" -import sys import os import unittest import getpass diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py index 3d14e12aa9..7c95be56d3 100644 --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -1,5 +1,4 @@ """Tests for distutils.unixccompiler.""" -import os import sys import unittest from test.support import EnvironmentVarGuard, run_unittest -- cgit v1.2.1 From aef13273534a1bb8bbac9b86fab434f8e785f66b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 24 Apr 2016 21:41:02 +0300 Subject: Issue #23277: Remove unused imports in tests. --- Lib/distutils/tests/test_bdist_rpm.py | 4 ---- Lib/distutils/tests/test_build_ext.py | 1 - Lib/distutils/tests/test_clean.py | 1 - Lib/distutils/tests/test_config.py | 1 - Lib/distutils/tests/test_cygwinccompiler.py | 3 +-- Lib/distutils/tests/test_dep_util.py | 1 - Lib/distutils/tests/test_file_util.py | 1 - Lib/distutils/tests/test_install_data.py | 1 - Lib/distutils/tests/test_install_headers.py | 1 - Lib/distutils/tests/test_spawn.py | 5 ++--- 10 files changed, 3 insertions(+), 16 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py index 25c14abd32..c1a2a041ee 100644 --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -3,16 +3,12 @@ import unittest import sys import os -import tempfile -import shutil from test.support import run_unittest from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm from distutils.tests import support from distutils.spawn import find_executable -from distutils import spawn -from distutils.errors import DistutilsExecError SETUP_PY = """\ from distutils.core import setup diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 366ffbec9f..3d84f8b1d7 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -166,7 +166,6 @@ class BuildExtTestCase(TempdirManager, cmd = self.build_ext(dist) cmd.finalize_options() - from distutils import sysconfig py_include = sysconfig.get_python_inc() self.assertIn(py_include, cmd.include_dirs) diff --git a/Lib/distutils/tests/test_clean.py b/Lib/distutils/tests/test_clean.py index df88ec1e34..c605afd860 100644 --- a/Lib/distutils/tests/test_clean.py +++ b/Lib/distutils/tests/test_clean.py @@ -1,7 +1,6 @@ """Tests for distutils.command.clean.""" import os import unittest -import getpass from distutils.command.clean import clean from distutils.tests import support diff --git a/Lib/distutils/tests/test_config.py b/Lib/distutils/tests/test_config.py index 0929f8a47d..d91dedd3a8 100644 --- a/Lib/distutils/tests/test_config.py +++ b/Lib/distutils/tests/test_config.py @@ -1,7 +1,6 @@ """Tests for distutils.pypirc.pypirc.""" import os import unittest -import tempfile from distutils.core import PyPIRCCommand from distutils.core import Distribution diff --git a/Lib/distutils/tests/test_cygwinccompiler.py b/Lib/distutils/tests/test_cygwinccompiler.py index 856921679d..9dc869de4c 100644 --- a/Lib/distutils/tests/test_cygwinccompiler.py +++ b/Lib/distutils/tests/test_cygwinccompiler.py @@ -3,11 +3,10 @@ import unittest import sys import os from io import BytesIO -import subprocess from test.support import run_unittest from distutils import cygwinccompiler -from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h, +from distutils.cygwinccompiler import (check_config_h, CONFIG_H_OK, CONFIG_H_NOTOK, CONFIG_H_UNCERTAIN, get_versions, get_msvcr) diff --git a/Lib/distutils/tests/test_dep_util.py b/Lib/distutils/tests/test_dep_util.py index 3e1c366892..c6fae39cfb 100644 --- a/Lib/distutils/tests/test_dep_util.py +++ b/Lib/distutils/tests/test_dep_util.py @@ -1,7 +1,6 @@ """Tests for distutils.dep_util.""" import unittest import os -import time from distutils.dep_util import newer, newer_pairwise, newer_group from distutils.errors import DistutilsFileError diff --git a/Lib/distutils/tests/test_file_util.py b/Lib/distutils/tests/test_file_util.py index a6d04f065d..03040afc79 100644 --- a/Lib/distutils/tests/test_file_util.py +++ b/Lib/distutils/tests/test_file_util.py @@ -1,7 +1,6 @@ """Tests for distutils.file_util.""" import unittest import os -import shutil import errno from unittest.mock import patch diff --git a/Lib/distutils/tests/test_install_data.py b/Lib/distutils/tests/test_install_data.py index d73624d00b..32ab296a32 100644 --- a/Lib/distutils/tests/test_install_data.py +++ b/Lib/distutils/tests/test_install_data.py @@ -1,7 +1,6 @@ """Tests for distutils.command.install_data.""" import os import unittest -import getpass from distutils.command.install_data import install_data from distutils.tests import support diff --git a/Lib/distutils/tests/test_install_headers.py b/Lib/distutils/tests/test_install_headers.py index d9ed6b7fd2..2217b321e6 100644 --- a/Lib/distutils/tests/test_install_headers.py +++ b/Lib/distutils/tests/test_install_headers.py @@ -1,7 +1,6 @@ """Tests for distutils.command.install_headers.""" import os import unittest -import getpass from distutils.command.install_headers import install_headers from distutils.tests import support diff --git a/Lib/distutils/tests/test_spawn.py b/Lib/distutils/tests/test_spawn.py index 6c7eb20c47..f507ef7750 100644 --- a/Lib/distutils/tests/test_spawn.py +++ b/Lib/distutils/tests/test_spawn.py @@ -1,11 +1,10 @@ """Tests for distutils.spawn.""" import unittest import os -import time -from test.support import captured_stdout, run_unittest +from test.support import run_unittest from distutils.spawn import _nt_quote_args -from distutils.spawn import spawn, find_executable +from distutils.spawn import spawn from distutils.errors import DistutilsExecError from distutils.tests import support -- cgit v1.2.1 From 0c19540a2ab8e5204fc1a49e55699c0db70b8632 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 25 Apr 2016 00:12:32 +0300 Subject: Removed unused imports. --- Lib/distutils/command/config.py | 2 +- Lib/distutils/command/register.py | 2 +- Lib/distutils/command/sdist.py | 1 - Lib/distutils/extension.py | 1 - Lib/distutils/text_file.py | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/config.py b/Lib/distutils/command/config.py index 847e858160..b1fd09e016 100644 --- a/Lib/distutils/command/config.py +++ b/Lib/distutils/command/config.py @@ -9,7 +9,7 @@ configure-like tasks: "try to compile this C code", or "figure out where this header file lives". """ -import sys, os, re +import os, re from distutils.core import Command from distutils.errors import DistutilsExecError diff --git a/Lib/distutils/command/register.py b/Lib/distutils/command/register.py index b49f86fe58..a3e0893a0b 100644 --- a/Lib/distutils/command/register.py +++ b/Lib/distutils/command/register.py @@ -5,7 +5,7 @@ Implements the Distutils 'register' command (register with the repository). # created 2002/10/21, Richard Jones -import os, string, getpass +import getpass import io import urllib.parse, urllib.request from warnings import warn diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py index 7ea3d5fa27..35a06eb09b 100644 --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -3,7 +3,6 @@ Implements the Distutils 'sdist' command (create a source distribution).""" import os -import string import sys from types import * from glob import glob diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py index 7efbb74f89..c507da360a 100644 --- a/Lib/distutils/extension.py +++ b/Lib/distutils/extension.py @@ -4,7 +4,6 @@ Provides the Extension class, used to describe C/C++ extension modules in setup scripts.""" import os -import sys import warnings # This class is really only used by the "build_ext" command, so it might diff --git a/Lib/distutils/text_file.py b/Lib/distutils/text_file.py index 478336f0d2..93abad38f4 100644 --- a/Lib/distutils/text_file.py +++ b/Lib/distutils/text_file.py @@ -4,7 +4,7 @@ provides the TextFile class, which gives an interface to text files that (optionally) takes care of stripping comments, ignoring blank lines, and joining lines with backslashes.""" -import sys, os, io +import sys, io class TextFile: -- cgit v1.2.1 From ec09e0e9556e3775e8096ae1a9ec7dc03c8a7bf5 Mon Sep 17 00:00:00 2001 From: doko Date: Sun, 5 Jun 2016 01:17:57 +0200 Subject: - Issue #21272: Use _sysconfigdata.py to initialize distutils.sysconfig. --- Lib/distutils/sysconfig.py | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index d203f8e42b..f205dcadeb 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -415,38 +415,11 @@ _config_vars = None def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" - g = {} - # load the installed Makefile: - try: - filename = get_makefile_filename() - parse_makefile(filename, g) - except OSError as msg: - my_msg = "invalid Python installation: unable to open %s" % filename - if hasattr(msg, "strerror"): - my_msg = my_msg + " (%s)" % msg.strerror - - raise DistutilsPlatformError(my_msg) - - # load the installed pyconfig.h: - try: - filename = get_config_h_filename() - with open(filename) as file: - parse_config_h(file, g) - except OSError as msg: - my_msg = "invalid Python installation: unable to open %s" % filename - if hasattr(msg, "strerror"): - my_msg = my_msg + " (%s)" % msg.strerror - - raise DistutilsPlatformError(my_msg) - - # On AIX, there are wrong paths to the linker scripts in the Makefile - # -- these paths are relative to the Python source, but when installed - # the scripts are in another directory. - if python_build: - g['LDSHARED'] = g['BLDSHARED'] - + # _sysconfigdata is generated at build time, see the sysconfig module + from _sysconfigdata import build_time_vars global _config_vars - _config_vars = g + _config_vars = {} + _config_vars.update(build_time_vars) def _init_nt(): -- cgit v1.2.1 From 008c426d4a560e63e9a5c56491de91c72417c68b Mon Sep 17 00:00:00 2001 From: doko Date: Tue, 14 Jun 2016 08:55:19 +0200 Subject: - Issue #23968: Rename the platform directory from plat-$(MACHDEP) to plat-$(PLATFORM_TRIPLET). Rename the config directory (LIBPL) from config-$(LDVERSION) to config-$(LDVERSION)-$(PLATFORM_TRIPLET). Install the platform specifc _sysconfigdata module into the platform directory and rename it to include the ABIFLAGS. --- Lib/distutils/sysconfig.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Lib/distutils') diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index f205dcadeb..e9cc4a95d4 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -242,6 +242,8 @@ def get_makefile_filename(): return os.path.join(_sys_home or project_base, "Makefile") lib_dir = get_python_lib(plat_specific=0, standard_lib=1) config_file = 'config-{}{}'.format(get_python_version(), build_flags) + if hasattr(sys.implementation, '_multiarch'): + config_file += '-%s' % sys.implementation._multiarch return os.path.join(lib_dir, config_file, 'Makefile') -- cgit v1.2.1 From 9591cc1bd328a80dc1fe6a2f2691d2b6f24451e3 Mon Sep 17 00:00:00 2001 From: doko Date: Tue, 14 Jun 2016 09:22:16 +0200 Subject: - Issue #23968: Update distutils/sysconfig.py to look for the renamed _sysconfigdata module too. --- Lib/distutils/sysconfig.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index e9cc4a95d4..f72b7f5a19 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -418,7 +418,9 @@ _config_vars = None def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see the sysconfig module - from _sysconfigdata import build_time_vars + name = '_sysconfigdata_' + sys.abiflags + _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) + build_time_vars = _temp.build_time_vars global _config_vars _config_vars = {} _config_vars.update(build_time_vars) -- cgit v1.2.1 From 1968105b8f73b8e9efeee7a8735df76f6ad06b29 Mon Sep 17 00:00:00 2001 From: Xavier de Gaye Date: Fri, 22 Jul 2016 12:15:29 +0200 Subject: Issue #27472: Add test.support.unix_shell as the path to the default shell. --- Lib/distutils/tests/test_spawn.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_spawn.py b/Lib/distutils/tests/test_spawn.py index f507ef7750..5edc24a3a1 100644 --- a/Lib/distutils/tests/test_spawn.py +++ b/Lib/distutils/tests/test_spawn.py @@ -1,7 +1,8 @@ """Tests for distutils.spawn.""" import unittest +import sys import os -from test.support import run_unittest +from test.support import run_unittest, unix_shell from distutils.spawn import _nt_quote_args from distutils.spawn import spawn @@ -29,9 +30,9 @@ class SpawnTestCase(support.TempdirManager, # creating something executable # through the shell that returns 1 - if os.name == 'posix': + if sys.platform != 'win32': exe = os.path.join(tmpdir, 'foo.sh') - self.write_file(exe, '#!/bin/sh\nexit 1') + self.write_file(exe, '#!%s\nexit 1' % unix_shell) else: exe = os.path.join(tmpdir, 'foo.bat') self.write_file(exe, 'exit 1') @@ -40,9 +41,9 @@ class SpawnTestCase(support.TempdirManager, self.assertRaises(DistutilsExecError, spawn, [exe]) # now something that works - if os.name == 'posix': + if sys.platform != 'win32': exe = os.path.join(tmpdir, 'foo.sh') - self.write_file(exe, '#!/bin/sh\nexit 0') + self.write_file(exe, '#!%s\nexit 0' % unix_shell) else: exe = os.path.join(tmpdir, 'foo.bat') self.write_file(exe, 'exit 0') -- cgit v1.2.1 From 99d9701d3084cc587261b78cc1d7b518d10f2ab1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 20 Aug 2016 17:31:07 -0400 Subject: Issue #27819: Simply default to gztar for sdist formats by default on all platforms. --- Lib/distutils/command/sdist.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py index 35a06eb09b..f1b8d91977 100644 --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -91,9 +91,6 @@ class sdist(Command): negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune' } - default_format = {'posix': 'gztar', - 'nt': 'zip' } - sub_commands = [('check', checking_metadata)] def initialize_options(self): @@ -110,7 +107,7 @@ class sdist(Command): self.manifest_only = 0 self.force_manifest = 0 - self.formats = None + self.formats = ['gztar'] self.keep_temp = 0 self.dist_dir = None @@ -126,13 +123,6 @@ class sdist(Command): self.template = "MANIFEST.in" self.ensure_string_list('formats') - if self.formats is None: - try: - self.formats = [self.default_format[os.name]] - except KeyError: - raise DistutilsPlatformError( - "don't know how to create source distributions " - "on platform %s" % os.name) bad_format = archive_util.check_archive_formats(self.formats) if bad_format: -- cgit v1.2.1 From 4846ba81c69ebc815b35a89ed54fef7b5ffb1417 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 30 Aug 2016 10:47:49 -0700 Subject: Issue #27895: Spelling fixes (Contributed by Ville Skytt?). --- Lib/distutils/tests/test_msvc9compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_msvc9compiler.py b/Lib/distutils/tests/test_msvc9compiler.py index 5e18c61360..77a07ef39d 100644 --- a/Lib/distutils/tests/test_msvc9compiler.py +++ b/Lib/distutils/tests/test_msvc9compiler.py @@ -125,7 +125,7 @@ class msvc9compilerTestCase(support.TempdirManager, self.assertRaises(KeyError, Reg.get_value, 'xxx', 'xxx') # looking for values that should exist on all - # windows registeries versions. + # windows registry versions. path = r'Control Panel\Desktop' v = Reg.get_value(path, 'dragfullwindows') self.assertIn(v, ('0', '1', '2')) -- cgit v1.2.1 From 6fae08cd104afd15190d836823a0dab7b228d0e6 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Wed, 31 Aug 2016 08:22:29 +0100 Subject: Closes #27904: Improved logging statements to defer formatting until needed. --- Lib/distutils/archive_util.py | 2 +- Lib/distutils/cmd.py | 3 +-- Lib/distutils/command/bdist_dumb.py | 2 +- Lib/distutils/command/build_ext.py | 6 +++--- Lib/distutils/command/config.py | 2 +- Lib/distutils/command/install.py | 2 +- Lib/distutils/command/register.py | 6 +++--- Lib/distutils/command/sdist.py | 2 +- 8 files changed, 12 insertions(+), 13 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/archive_util.py b/Lib/distutils/archive_util.py index bed1384900..78ae5757c3 100644 --- a/Lib/distutils/archive_util.py +++ b/Lib/distutils/archive_util.py @@ -171,7 +171,7 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): path = os.path.normpath(os.path.join(dirpath, name)) if os.path.isfile(path): zip.write(path, path) - log.info("adding '%s'" % path) + log.info("adding '%s'", path) zip.close() return zip_filename diff --git a/Lib/distutils/cmd.py b/Lib/distutils/cmd.py index c89d5efc45..b5d9dc387d 100644 --- a/Lib/distutils/cmd.py +++ b/Lib/distutils/cmd.py @@ -329,8 +329,7 @@ class Command: # -- External world manipulation ----------------------------------- def warn(self, msg): - log.warn("warning: %s: %s\n" % - (self.get_command_name(), msg)) + log.warn("warning: %s: %s\n", self.get_command_name(), msg) def execute(self, func, args, msg=None, level=1): util.execute(func, args, msg, dry_run=self.dry_run) diff --git a/Lib/distutils/command/bdist_dumb.py b/Lib/distutils/command/bdist_dumb.py index f1bfb24923..e9274d925a 100644 --- a/Lib/distutils/command/bdist_dumb.py +++ b/Lib/distutils/command/bdist_dumb.py @@ -85,7 +85,7 @@ class bdist_dumb(Command): install.skip_build = self.skip_build install.warn_dir = 0 - log.info("installing to %s" % self.bdist_dir) + log.info("installing to %s", self.bdist_dir) self.run_command('install') # And make an archive relative to the root of the diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index f03a4e31d8..5e51ae4ba1 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -363,9 +363,9 @@ class build_ext(Command): ext_name, build_info = ext - log.warn(("old-style (ext_name, build_info) tuple found in " - "ext_modules for extension '%s'" - "-- please convert to Extension instance" % ext_name)) + log.warn("old-style (ext_name, build_info) tuple found in " + "ext_modules for extension '%s'" + "-- please convert to Extension instance", ext_name) if not (isinstance(ext_name, str) and extension_name_re.match(ext_name)): diff --git a/Lib/distutils/command/config.py b/Lib/distutils/command/config.py index b1fd09e016..4ae153d194 100644 --- a/Lib/distutils/command/config.py +++ b/Lib/distutils/command/config.py @@ -337,7 +337,7 @@ def dump_file(filename, head=None): If head is not None, will be dumped before the file content. """ if head is None: - log.info('%s' % filename) + log.info('%s', filename) else: log.info(head) file = open(filename) diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index 9474e9c599..fca05d69c6 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -385,7 +385,7 @@ class install(Command): else: opt_name = opt_name.translate(longopt_xlate) val = getattr(self, opt_name) - log.debug(" %s: %s" % (opt_name, val)) + log.debug(" %s: %s", opt_name, val) def finalize_unix(self): """Finalizes options for posix platforms.""" diff --git a/Lib/distutils/command/register.py b/Lib/distutils/command/register.py index 456d50d519..0fac94e9e5 100644 --- a/Lib/distutils/command/register.py +++ b/Lib/distutils/command/register.py @@ -94,7 +94,7 @@ class register(PyPIRCCommand): ''' # send the info to the server and report the result (code, result) = self.post_to_server(self.build_post_data('verify')) - log.info('Server response (%s): %s' % (code, result)) + log.info('Server response (%s): %s', code, result) def send_metadata(self): ''' Send the metadata to the package index server. @@ -205,7 +205,7 @@ Your selection [default 1]: ''', log.INFO) data['email'] = input(' EMail: ') code, result = self.post_to_server(data) if code != 200: - log.info('Server response (%s): %s' % (code, result)) + log.info('Server response (%s): %s', code, result) else: log.info('You will receive an email shortly.') log.info(('Follow the instructions in it to ' @@ -216,7 +216,7 @@ Your selection [default 1]: ''', log.INFO) while not data['email']: data['email'] = input('Your email address: ') code, result = self.post_to_server(data) - log.info('Server response (%s): %s' % (code, result)) + log.info('Server response (%s): %s', code, result) def build_post_data(self, action): # figure the data to send - the metadata plus some additional diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py index f1b8d91977..4fd1d4715d 100644 --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -412,7 +412,7 @@ class sdist(Command): log.info(msg) for file in files: if not os.path.isfile(file): - log.warn("'%s' not a regular file -- skipping" % file) + log.warn("'%s' not a regular file -- skipping", file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) -- cgit v1.2.1 From 4a1c7fc65d46f2d4b28a01496e0bf6c57b36bc35 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Wed, 31 Aug 2016 11:39:35 -0400 Subject: #27904: fix distutils tests. Patch by Ville Skytt?. --- Lib/distutils/tests/test_build_py.py | 3 ++- Lib/distutils/tests/test_install_lib.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_build_py.py b/Lib/distutils/tests/test_build_py.py index 18283dc722..0712e92c6a 100644 --- a/Lib/distutils/tests/test_build_py.py +++ b/Lib/distutils/tests/test_build_py.py @@ -168,7 +168,8 @@ class BuildPyTestCase(support.TempdirManager, finally: sys.dont_write_bytecode = old_dont_write_bytecode - self.assertIn('byte-compiling is disabled', self.logs[0][1]) + self.assertIn('byte-compiling is disabled', + self.logs[0][1] % self.logs[0][2]) def test_suite(): diff --git a/Lib/distutils/tests/test_install_lib.py b/Lib/distutils/tests/test_install_lib.py index 5378aa8249..fda6315bbc 100644 --- a/Lib/distutils/tests/test_install_lib.py +++ b/Lib/distutils/tests/test_install_lib.py @@ -104,7 +104,8 @@ class InstallLibTestCase(support.TempdirManager, finally: sys.dont_write_bytecode = old_dont_write_bytecode - self.assertIn('byte-compiling is disabled', self.logs[0][1]) + self.assertIn('byte-compiling is disabled', + self.logs[0][1] % self.logs[0][2]) def test_suite(): -- cgit v1.2.1 From e7256f048f6506575dd31ea2a39f298692b09ee9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 1 Sep 2016 13:55:33 -0400 Subject: Issue #27919: Deprecate extra_path option in distutils. --- Lib/distutils/command/install.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Lib/distutils') diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index fca05d69c6..0258d3deae 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -175,6 +175,7 @@ class install(Command): self.compile = None self.optimize = None + # Deprecated # These two are for putting non-packagized distributions into their # own directory and creating a .pth file if it makes sense. # 'extra_path' comes from the setup file; 'install_path_file' can @@ -344,6 +345,7 @@ class install(Command): 'scripts', 'data', 'headers', 'userbase', 'usersite') + # Deprecated # Well, we're not actually fully completely finalized yet: we still # have to deal with 'extra_path', which is the hack for allowing # non-packagized module distributions (hello, Numerical Python!) to @@ -490,6 +492,10 @@ class install(Command): self.extra_path = self.distribution.extra_path if self.extra_path is not None: + log.warn( + "Distribution option extra_path is deprecated. " + "See issue27919 for details." + ) if isinstance(self.extra_path, str): self.extra_path = self.extra_path.split(',') -- cgit v1.2.1 From 03c8a473999b08710ae3661724cf1bf1d76bc555 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Thu, 8 Sep 2016 13:59:53 -0400 Subject: #27364: fix "incorrect" uses of escape character in the stdlib. And most of the tools. Patch by Emanual Barry, reviewed by me, Serhiy Storchaka, and Martin Panter. --- Lib/distutils/cmd.py | 2 +- Lib/distutils/command/bdist_msi.py | 4 ++-- Lib/distutils/command/build_scripts.py | 2 +- Lib/distutils/cygwinccompiler.py | 2 +- Lib/distutils/msvc9compiler.py | 2 +- Lib/distutils/sysconfig.py | 2 +- Lib/distutils/versionpredicate.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/cmd.py b/Lib/distutils/cmd.py index b5d9dc387d..939f795945 100644 --- a/Lib/distutils/cmd.py +++ b/Lib/distutils/cmd.py @@ -221,7 +221,7 @@ class Command: self._ensure_stringlike(option, "string", default) def ensure_string_list(self, option): - """Ensure that 'option' is a list of strings. If 'option' is + r"""Ensure that 'option' is a list of strings. If 'option' is currently a string, we split it either on /,\s*/ or /\s+/, so "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become ["foo", "bar", "baz"]. diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py index f6c21aee44..a4bd5a589d 100644 --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -623,7 +623,7 @@ class bdist_msi(Command): cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, "OK", "OK", "OK", bitmap=False) cost.text("Title", 15, 6, 200, 15, 0x30003, - "{\DlgFontBold8}Disk Space Requirements") + r"{\DlgFontBold8}Disk Space Requirements") cost.text("Description", 20, 20, 280, 20, 0x30003, "The disk space required for the installation of the selected features.") cost.text("Text", 20, 53, 330, 60, 3, @@ -670,7 +670,7 @@ class bdist_msi(Command): progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, "Cancel", "Cancel", "Cancel", bitmap=False) progress.text("Title", 20, 15, 200, 15, 0x30003, - "{\DlgFontBold8}[Progress1] [ProductName]") + r"{\DlgFontBold8}[Progress1] [ProductName]") progress.text("Text", 35, 65, 300, 30, 3, "Please wait while the Installer [Progress2] [ProductName]. " "This may take several minutes.") diff --git a/Lib/distutils/command/build_scripts.py b/Lib/distutils/command/build_scripts.py index 90a8380a04..ccc70e6465 100644 --- a/Lib/distutils/command/build_scripts.py +++ b/Lib/distutils/command/build_scripts.py @@ -51,7 +51,7 @@ class build_scripts(Command): def copy_scripts(self): - """Copy each script listed in 'self.scripts'; if it's marked as a + r"""Copy each script listed in 'self.scripts'; if it's marked as a Python script in the Unix way (first line matches 'first_line_re', ie. starts with "\#!" and contains "python"), then adjust the first line to refer to the current Python interpreter as we copy. diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py index c879646c0f..1c36990347 100644 --- a/Lib/distutils/cygwinccompiler.py +++ b/Lib/distutils/cygwinccompiler.py @@ -368,7 +368,7 @@ def check_config_h(): return (CONFIG_H_UNCERTAIN, "couldn't read '%s': %s" % (fn, exc.strerror)) -RE_VERSION = re.compile(b'(\d+\.\d+(\.\d+)*)') +RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') def _find_exe_version(cmd): """Find the version of an executable by running `cmd` in the shell. diff --git a/Lib/distutils/msvc9compiler.py b/Lib/distutils/msvc9compiler.py index 0b1fd19ff6..2119127622 100644 --- a/Lib/distutils/msvc9compiler.py +++ b/Lib/distutils/msvc9compiler.py @@ -716,7 +716,7 @@ class MSVCCompiler(CCompiler) : r"""VC\d{2}\.CRT("|').*?(/>|)""", re.DOTALL) manifest_buf = re.sub(pattern, "", manifest_buf) - pattern = "\s*" + pattern = r"\s*" manifest_buf = re.sub(pattern, "", manifest_buf) # Now see if any other assemblies are referenced - if not, we # don't want a manifest embedded. diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index f72b7f5a19..681359870c 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -278,7 +278,7 @@ def parse_config_h(fp, g=None): # Regexes needed for parsing Makefile (and similar syntaxes, # like old-style Setup files). -_variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") +_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") diff --git a/Lib/distutils/versionpredicate.py b/Lib/distutils/versionpredicate.py index b0dd9f45bf..062c98f248 100644 --- a/Lib/distutils/versionpredicate.py +++ b/Lib/distutils/versionpredicate.py @@ -154,7 +154,7 @@ def split_provision(value): global _provision_rx if _provision_rx is None: _provision_rx = re.compile( - "([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$", + r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$", re.ASCII) value = value.strip() m = _provision_rx.match(value) -- cgit v1.2.1 From d8eea9e1ca3787861b65da2fde7fcf79d3e8a3e8 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Fri, 9 Sep 2016 18:29:10 -0700 Subject: Issue #28046: Fix distutils Why do we have two sysconfig modules again? --- Lib/distutils/sysconfig.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 681359870c..229626e1b4 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -418,7 +418,11 @@ _config_vars = None def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see the sysconfig module - name = '_sysconfigdata_' + sys.abiflags + name = '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( + abi=sys.abiflags, + platform=sys.platform, + multiarch=getattr(sys.implementation, '_multiarch', ''), + ) _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) build_time_vars = _temp.build_time_vars global _config_vars -- cgit v1.2.1 From 03d61e6976c4e3899fc84576c91427b60e78cf7a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 11 Sep 2016 12:50:02 +0300 Subject: Issue #22493: Inline flags now should be used only at the start of the regular expression. Deprecation warning is emitted if uses them in the middle of the regular expression. --- Lib/distutils/filelist.py | 15 ++++++++++----- Lib/distutils/tests/test_filelist.py | 14 +++++++------- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/filelist.py b/Lib/distutils/filelist.py index 6522e69f06..c92d5fdba3 100644 --- a/Lib/distutils/filelist.py +++ b/Lib/distutils/filelist.py @@ -302,21 +302,26 @@ def translate_pattern(pattern, anchor=1, prefix=None, is_regex=0): else: return pattern + # ditch start and end characters + start, _, end = glob_to_re('_').partition('_') + if pattern: pattern_re = glob_to_re(pattern) + assert pattern_re.startswith(start) and pattern_re.endswith(end) else: pattern_re = '' if prefix is not None: - # ditch end of pattern character - empty_pattern = glob_to_re('') - prefix_re = glob_to_re(prefix)[:-len(empty_pattern)] + prefix_re = glob_to_re(prefix) + assert prefix_re.startswith(start) and prefix_re.endswith(end) + prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] sep = os.sep if os.sep == '\\': sep = r'\\' - pattern_re = "^" + sep.join((prefix_re, ".*" + pattern_re)) + pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] + pattern_re = r'%s\A%s%s.*%s%s' % (start, prefix_re, sep, pattern_re, end) else: # no prefix -- respect anchor flag if anchor: - pattern_re = "^" + pattern_re + pattern_re = r'%s\A%s' % (start, pattern_re[len(start):]) return re.compile(pattern_re) diff --git a/Lib/distutils/tests/test_filelist.py b/Lib/distutils/tests/test_filelist.py index 391af3cba2..c71342d0dc 100644 --- a/Lib/distutils/tests/test_filelist.py +++ b/Lib/distutils/tests/test_filelist.py @@ -51,14 +51,14 @@ class FileListTestCase(support.LoggingSilencer, for glob, regex in ( # simple cases - ('foo*', r'foo[^%(sep)s]*\Z(?ms)'), - ('foo?', r'foo[^%(sep)s]\Z(?ms)'), - ('foo??', r'foo[^%(sep)s][^%(sep)s]\Z(?ms)'), + ('foo*', r'(?s:foo[^%(sep)s]*)\Z'), + ('foo?', r'(?s:foo[^%(sep)s])\Z'), + ('foo??', r'(?s:foo[^%(sep)s][^%(sep)s])\Z'), # special cases - (r'foo\\*', r'foo\\\\[^%(sep)s]*\Z(?ms)'), - (r'foo\\\*', r'foo\\\\\\[^%(sep)s]*\Z(?ms)'), - ('foo????', r'foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s]\Z(?ms)'), - (r'foo\\??', r'foo\\\\[^%(sep)s][^%(sep)s]\Z(?ms)')): + (r'foo\\*', r'(?s:foo\\\\[^%(sep)s]*)\Z'), + (r'foo\\\*', r'(?s:foo\\\\\\[^%(sep)s]*)\Z'), + ('foo????', r'(?s:foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s])\Z'), + (r'foo\\??', r'(?s:foo\\\\[^%(sep)s][^%(sep)s])\Z')): regex = regex % {'sep': sep} self.assertEqual(glob_to_re(glob), regex) -- cgit v1.2.1 From ebadb5ed14af411ee0199a9c3f5d69da0bb3f190 Mon Sep 17 00:00:00 2001 From: Xavier de Gaye Date: Sun, 11 Sep 2016 22:22:24 +0200 Subject: Issue #28046: get_sysconfigdata_name() uses the _PYTHON_SYSCONFIGDATA_NAME environment variable that is defined when cross-compiling. --- Lib/distutils/sysconfig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 229626e1b4..8bf1a7016b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -418,11 +418,12 @@ _config_vars = None def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see the sysconfig module - name = '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( + name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', + '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( abi=sys.abiflags, platform=sys.platform, multiarch=getattr(sys.implementation, '_multiarch', ''), - ) + )) _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) build_time_vars = _temp.build_time_vars global _config_vars -- cgit v1.2.1 From 0d7cbc0265f573f4f3aaad4c93cf2c5175c8ee0a Mon Sep 17 00:00:00 2001 From: Xavier de Gaye Date: Thu, 17 Nov 2016 09:00:19 +0100 Subject: Issue 26931: Skip the test_distutils tests using a compiler executable that is not found --- Lib/distutils/tests/test_build_clib.py | 20 ++++++-------------- Lib/distutils/tests/test_build_ext.py | 6 ++++++ Lib/distutils/tests/test_config_cmd.py | 5 ++++- Lib/distutils/tests/test_install.py | 4 ++++ Lib/distutils/tests/test_sysconfig.py | 9 --------- 5 files changed, 20 insertions(+), 24 deletions(-) (limited to 'Lib/distutils') diff --git a/Lib/distutils/tests/test_build_clib.py b/Lib/distutils/tests/test_build_clib.py index acc99e78c1..85d09906f2 100644 --- a/Lib/distutils/tests/test_build_clib.py +++ b/Lib/distutils/tests/test_build_clib.py @@ -3,7 +3,7 @@ import unittest import os import sys -from test.support import run_unittest +from test.support import run_unittest, missing_compiler_executable from distutils.command.build_clib import build_clib from distutils.errors import DistutilsSetupError @@ -116,19 +116,11 @@ class BuildCLibTestCase(support.TempdirManager, cmd.build_temp = build_temp cmd.build_clib = build_temp - # before we run the command, we want to make sure - # all commands are present on the system - # by creating a compiler and checking its executables - from distutils.ccompiler import new_compiler - from distutils.sysconfig import customize_compiler - - compiler = new_compiler() - customize_compiler(compiler) - for ccmd in compiler.executables.values(): - if ccmd is None: - continue - if find_executable(ccmd[0]) is None: - self.skipTest('The %r command is not found' % ccmd[0]) + # Before we run the command, we want to make sure + # all commands are present on the system. + ccmd = missing_compiler_executable() + if ccmd is not None: + self.skipTest('The %r command is not found' % ccmd) # this should work cmd.run() diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 6be0ca233b..be7f5f38aa 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -41,6 +41,9 @@ class BuildExtTestCase(TempdirManager, return build_ext(*args, **kwargs) def test_build_ext(self): + cmd = support.missing_compiler_executable() + if cmd is not None: + self.skipTest('The %r command is not found' % cmd) global ALREADY_TESTED copy_xxmodule_c(self.tmp_dir) xx_c = os.path.join(self.tmp_dir, 'xxmodule.c') @@ -295,6 +298,9 @@ class BuildExtTestCase(TempdirManager, self.assertEqual(cmd.compiler, 'unix') def test_get_outputs(self): + cmd = support.missing_compiler_executable() + if cmd is not None: + self.skipTest('The %r command is not found' % cmd) tmp_dir = self.mkdtemp() c_file = os.path.join(tmp_dir, 'foo.c') self.write_file(c_file, 'void PyInit_foo(void) {}\n') diff --git a/Lib/distutils/tests/test_config_cmd.py b/Lib/distutils/tests/test_config_cmd.py index 0c8dbd8269..6e566e7915 100644 --- a/Lib/distutils/tests/test_config_cmd.py +++ b/Lib/distutils/tests/test_config_cmd.py @@ -2,7 +2,7 @@ import unittest import os import sys -from test.support import run_unittest +from test.support import run_unittest, missing_compiler_executable from distutils.command.config import dump_file, config from distutils.tests import support @@ -39,6 +39,9 @@ class ConfigTestCase(support.LoggingSilencer, @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") def test_search_cpp(self): + cmd = missing_compiler_executable(['preprocessor']) + if cmd is not None: + self.skipTest('The %r command is not found' % cmd) pkg_dir, dist = self.create_dist() cmd = config(dist) diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py index 9313330e2b..287ab1989e 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py @@ -17,6 +17,7 @@ from distutils.errors import DistutilsOptionError from distutils.extension import Extension from distutils.tests import support +from test import support as test_support def _make_ext_name(modname): @@ -196,6 +197,9 @@ class InstallTestCase(support.TempdirManager, self.assertEqual(found, expected) def test_record_extensions(self): + cmd = test_support.missing_compiler_executable() + if cmd is not None: + self.skipTest('The %r command is not found' % cmd) install_dir = self.mkdtemp() project_dir, dist = self.create_dist(ext_modules=[ Extension('xx', ['xxmodule.c'])]) diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py index fc4d1de185..fe4a2994e3 100644 --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -39,15 +39,6 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase): self.assertNotEqual(sysconfig.get_python_lib(), sysconfig.get_python_lib(prefix=TESTFN)) - def test_get_python_inc(self): - inc_dir = sysconfig.get_python_inc() - # This is not much of a test. We make sure Python.h exists - # in the directory returned by get_python_inc() but we don't know - # it is the correct file. - self.assertTrue(os.path.isdir(inc_dir), inc_dir) - python_h = os.path.join(inc_dir, "Python.h") - self.assertTrue(os.path.isfile(python_h), python_h) - def test_get_config_vars(self): cvars = sysconfig.get_config_vars() self.assertIsInstance(cvars, dict) -- cgit v1.2.1