Commit 01a07bef authored by Tarek Ziadé's avatar Tarek Ziadé

#6466 refactored distutils duplicate get_versions() functions (used to get gcc/ld/dllwrap versions)

parent 0e0874b3
...@@ -50,16 +50,15 @@ __revision__ = "$Id$" ...@@ -50,16 +50,15 @@ __revision__ = "$Id$"
import os import os
import sys import sys
import copy import copy
from subprocess import Popen, PIPE
import re import re
from warnings import warn
from distutils.ccompiler import gen_preprocess_options, gen_lib_options from distutils.ccompiler import gen_preprocess_options, gen_lib_options
from distutils.unixccompiler import UnixCCompiler from distutils.unixccompiler import UnixCCompiler
from distutils.file_util import write_file from distutils.file_util import write_file
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
from distutils import log from distutils import log
from distutils.version import LooseVersion from distutils.util import get_compiler_versions
from distutils.spawn import find_executable
def get_msvcr(): def get_msvcr():
"""Include the appropriate MSVC runtime library if Python was built """Include the appropriate MSVC runtime library if Python was built
...@@ -110,7 +109,7 @@ class CygwinCCompiler(UnixCCompiler): ...@@ -110,7 +109,7 @@ class CygwinCCompiler(UnixCCompiler):
% details) % details)
self.gcc_version, self.ld_version, self.dllwrap_version = \ self.gcc_version, self.ld_version, self.dllwrap_version = \
get_versions() get_compiler_versions()
self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
(self.gcc_version, (self.gcc_version,
self.ld_version, self.ld_version,
...@@ -359,31 +358,26 @@ def check_config_h(): ...@@ -359,31 +358,26 @@ def check_config_h():
return (CONFIG_H_UNCERTAIN, return (CONFIG_H_UNCERTAIN,
"couldn't read '%s': %s" % (fn, exc.strerror)) "couldn't read '%s': %s" % (fn, exc.strerror))
RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)') class _Deprecated_SRE_Pattern(object):
def __init__(self, pattern):
self.pattern = pattern
def _find_exe_version(cmd): def __getattr__(self, name):
"""Find the version of an executable by running `cmd` in the shell. if name in ('findall', 'finditer', 'match', 'scanner', 'search',
'split', 'sub', 'subn'):
warn("'distutils.cygwinccompiler.RE_VERSION' is deprecated "
"and will be removed in the next version", DeprecationWarning)
return getattr(self.pattern, name)
If the command is not found, or the output does not match RE_VERSION = _Deprecated_SRE_Pattern(re.compile('(\d+\.\d+(\.\d+)*)'))
`RE_VERSION`, returns None.
"""
executable = cmd.split()[0]
if find_executable(executable) is None:
return None
out = Popen(cmd, shell=True, stdout=PIPE).stdout
try:
out_string = out.read()
finally:
out.close()
result = RE_VERSION.search(out_string)
if result is None:
return None
return LooseVersion(result.group(1))
def get_versions(): def get_versions():
""" Try to find out the versions of gcc, ld and dllwrap. """ Try to find out the versions of gcc, ld and dllwrap.
If not possible it returns None for it. If not possible it returns None for it.
""" """
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] warn("'distutils.cygwinccompiler.get_versions' is deprecated "
return tuple([_find_exe_version(cmd) for cmd in commands]) "use 'distutils.util.get_compiler_versions' instead",
DeprecationWarning)
return get_compiler_versions()
...@@ -21,12 +21,15 @@ handles the EMX port of the GNU C compiler to OS/2. ...@@ -21,12 +21,15 @@ handles the EMX port of the GNU C compiler to OS/2.
__revision__ = "$Id$" __revision__ = "$Id$"
import os,sys,copy import os, sys, copy
from warnings import warn
from distutils.ccompiler import gen_preprocess_options, gen_lib_options from distutils.ccompiler import gen_preprocess_options, gen_lib_options
from distutils.unixccompiler import UnixCCompiler from distutils.unixccompiler import UnixCCompiler
from distutils.file_util import write_file from distutils.file_util import write_file
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
from distutils import log from distutils import log
from distutils.util import get_compiler_versions
class EMXCCompiler (UnixCCompiler): class EMXCCompiler (UnixCCompiler):
...@@ -55,8 +58,8 @@ class EMXCCompiler (UnixCCompiler): ...@@ -55,8 +58,8 @@ class EMXCCompiler (UnixCCompiler):
("Reason: %s." % details) + ("Reason: %s." % details) +
"Compiling may fail because of undefined preprocessor macros.") "Compiling may fail because of undefined preprocessor macros.")
(self.gcc_version, self.ld_version) = \ gcc_version, ld_version, dllwrap_version = get_compiler_versions()
get_versions() self.gcc_version, self.ld_version = gcc_version, ld_version
self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" % self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
(self.gcc_version, (self.gcc_version,
self.ld_version) ) self.ld_version) )
...@@ -293,23 +296,11 @@ def get_versions(): ...@@ -293,23 +296,11 @@ def get_versions():
""" Try to find out the versions of gcc and ld. """ Try to find out the versions of gcc and ld.
If not possible it returns None for it. If not possible it returns None for it.
""" """
from distutils.version import StrictVersion warn("'distutils.emxccompiler.get_versions' is deprecated "
from distutils.spawn import find_executable "use 'distutils.util.get_compiler_versions' instead",
import re DeprecationWarning)
gcc_exe = find_executable('gcc')
if gcc_exe:
out = os.popen(gcc_exe + ' -dumpversion','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+\.\d+)',out_string)
if result:
gcc_version = StrictVersion(result.group(1))
else:
gcc_version = None
else:
gcc_version = None
# EMX ld has no way of reporting version number, and we use GCC # EMX ld has no way of reporting version number, and we use GCC
# anyway - so we can link OMF DLLs # anyway - so we can link OMF DLLs
ld_version = None gcc_version, ld_version, dllwrap_version = get_compiler_versions()
return (gcc_version, ld_version) return gcc_version, None
...@@ -2,28 +2,19 @@ ...@@ -2,28 +2,19 @@
import unittest import unittest
import sys import sys
import os import os
from StringIO import StringIO import warnings
import subprocess
from test.test_support import check_warnings
from test.test_support import captured_stdout
from distutils import cygwinccompiler from distutils import cygwinccompiler
from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h, from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h,
CONFIG_H_OK, CONFIG_H_NOTOK, CONFIG_H_OK, CONFIG_H_NOTOK,
CONFIG_H_UNCERTAIN, get_versions, CONFIG_H_UNCERTAIN, get_versions,
get_msvcr) get_msvcr, RE_VERSION)
from distutils.util import get_compiler_versions
from distutils.tests import support from distutils.tests import support
class FakePopen(object):
test_class = None
def __init__(self, cmd, shell, stdout):
self.cmd = cmd.split()[0]
exes = self.test_class._exes
if self.cmd in exes:
self.stdout = StringIO(exes[self.cmd])
else:
self.stdout = os.popen(cmd, 'r')
class CygwinCCompilerTestCase(support.TempdirManager, class CygwinCCompilerTestCase(support.TempdirManager,
unittest.TestCase): unittest.TestCase):
...@@ -34,29 +25,16 @@ class CygwinCCompilerTestCase(support.TempdirManager, ...@@ -34,29 +25,16 @@ class CygwinCCompilerTestCase(support.TempdirManager,
from distutils import sysconfig from distutils import sysconfig
self.old_get_config_h_filename = sysconfig.get_config_h_filename self.old_get_config_h_filename = sysconfig.get_config_h_filename
sysconfig.get_config_h_filename = self._get_config_h_filename sysconfig.get_config_h_filename = self._get_config_h_filename
self.old_find_executable = cygwinccompiler.find_executable
cygwinccompiler.find_executable = self._find_executable
self._exes = {}
self.old_popen = cygwinccompiler.Popen
FakePopen.test_class = self
cygwinccompiler.Popen = FakePopen
def tearDown(self): def tearDown(self):
sys.version = self.version sys.version = self.version
from distutils import sysconfig from distutils import sysconfig
sysconfig.get_config_h_filename = self.old_get_config_h_filename sysconfig.get_config_h_filename = self.old_get_config_h_filename
cygwinccompiler.find_executable = self.old_find_executable
cygwinccompiler.Popen = self.old_popen
super(CygwinCCompilerTestCase, self).tearDown() super(CygwinCCompilerTestCase, self).tearDown()
def _get_config_h_filename(self): def _get_config_h_filename(self):
return self.python_h return self.python_h
def _find_executable(self, name):
if name in self._exes:
return name
return None
def test_check_config_h(self): def test_check_config_h(self):
# check_config_h looks for "GCC" in sys.version first # check_config_h looks for "GCC" in sys.version first
...@@ -80,40 +58,6 @@ class CygwinCCompilerTestCase(support.TempdirManager, ...@@ -80,40 +58,6 @@ class CygwinCCompilerTestCase(support.TempdirManager,
self.write_file(self.python_h, 'xxx __GNUC__ xxx') self.write_file(self.python_h, 'xxx __GNUC__ xxx')
self.assertEquals(check_config_h()[0], CONFIG_H_OK) self.assertEquals(check_config_h()[0], CONFIG_H_OK)
def test_get_versions(self):
# get_versions calls distutils.spawn.find_executable on
# 'gcc', 'ld' and 'dllwrap'
self.assertEquals(get_versions(), (None, None, None))
# Let's fake we have 'gcc' and it returns '3.4.5'
self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF'
res = get_versions()
self.assertEquals(str(res[0]), '3.4.5')
# and let's see what happens when the version
# doesn't match the regular expression
# (\d+\.\d+(\.\d+)*)
self._exes['gcc'] = 'very strange output'
res = get_versions()
self.assertEquals(res[0], None)
# same thing for ld
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
res = get_versions()
self.assertEquals(str(res[1]), '2.17.50')
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
res = get_versions()
self.assertEquals(res[1], None)
# and dllwrap
self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF'
res = get_versions()
self.assertEquals(str(res[2]), '2.17.50')
self._exes['dllwrap'] = 'Cheese Wrap'
res = get_versions()
self.assertEquals(res[2], None)
def test_get_msvcr(self): def test_get_msvcr(self):
# none # none
...@@ -146,6 +90,21 @@ class CygwinCCompilerTestCase(support.TempdirManager, ...@@ -146,6 +90,21 @@ class CygwinCCompilerTestCase(support.TempdirManager,
'[MSC v.1999 32 bits (Intel)]') '[MSC v.1999 32 bits (Intel)]')
self.assertRaises(ValueError, get_msvcr) self.assertRaises(ValueError, get_msvcr)
def test_get_version_deprecated(self):
with check_warnings() as w:
warnings.simplefilter("always")
# make sure get_compiler_versions and get_versions
# returns the same thing
self.assertEquals(get_compiler_versions(), get_versions())
# make sure using get_version() generated a warning
self.assertEquals(len(w.warnings), 1)
# make sure any usage of RE_VERSION will also
# generate a warning, but till works
version = RE_VERSION.search('1.2').group(1)
self.assertEquals(version, '1.2')
self.assertEquals(len(w.warnings), 2)
def test_suite(): def test_suite():
return unittest.makeSuite(CygwinCCompilerTestCase) return unittest.makeSuite(CygwinCCompilerTestCase)
......
"""Tests for distutils.emxccompiler."""
import unittest
import sys
import os
import warnings
from test.test_support import check_warnings
from test.test_support import captured_stdout
from distutils.emxccompiler import get_versions
from distutils.util import get_compiler_versions
from distutils.tests import support
class EmxCCompilerTestCase(support.TempdirManager,
unittest.TestCase):
def test_get_version_deprecated(self):
with check_warnings() as w:
warnings.simplefilter("always")
# make sure get_compiler_versions and get_versions
# returns the same gcc
gcc, ld, dllwrap = get_compiler_versions()
emx_gcc, emx_ld = get_versions()
self.assertEquals(gcc, emx_gcc)
# make sure using get_version() generated a warning
self.assertEquals(len(w.warnings), 1)
def test_suite():
return unittest.makeSuite(EmxCCompilerTestCase)
if __name__ == '__main__':
test_support.run_unittest(test_suite())
...@@ -6,15 +6,33 @@ import os ...@@ -6,15 +6,33 @@ import os
import sys import sys
import unittest import unittest
from copy import copy from copy import copy
from StringIO import StringIO
import subprocess
from distutils.errors import DistutilsPlatformError from distutils.errors import DistutilsPlatformError
from distutils.util import (get_platform, convert_path, change_root, from distutils.util import (get_platform, convert_path, change_root,
check_environ, split_quoted, strtobool, check_environ, split_quoted, strtobool,
rfc822_escape) rfc822_escape, get_compiler_versions,
from distutils import util # used to patch _environ_checked _find_exe_version, _MAC_OS_X_LD_VERSION)
from distutils import util
from distutils.sysconfig import get_config_vars from distutils.sysconfig import get_config_vars
from distutils import sysconfig from distutils import sysconfig
from distutils.tests import support from distutils.tests import support
from distutils.version import LooseVersion
class FakePopen(object):
test_class = None
def __init__(self, cmd, shell, stdout, stderr):
self.cmd = cmd.split()[0]
exes = self.test_class._exes
if self.cmd not in exes:
# we don't want to call the system, returning an empty
# output so it doesn't match
self.stdout = StringIO()
self.stderr = StringIO()
else:
self.stdout = StringIO(exes[self.cmd])
self.stderr = StringIO()
class UtilTestCase(support.EnvironGuard, unittest.TestCase): class UtilTestCase(support.EnvironGuard, unittest.TestCase):
...@@ -37,9 +55,16 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase): ...@@ -37,9 +55,16 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase):
else: else:
self.uname = None self.uname = None
self._uname = None self._uname = None
os.uname = self._get_uname os.uname = self._get_uname
# patching POpen
self.old_find_executable = util.find_executable
util.find_executable = self._find_executable
self._exes = {}
self.old_popen = subprocess.Popen
FakePopen.test_class = self
subprocess.Popen = FakePopen
def tearDown(self): def tearDown(self):
# getting back the environment # getting back the environment
os.name = self.name os.name = self.name
...@@ -54,6 +79,8 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase): ...@@ -54,6 +79,8 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase):
else: else:
del os.uname del os.uname
sysconfig._config_vars = copy(self._config_vars) sysconfig._config_vars = copy(self._config_vars)
util.find_executable = self.old_find_executable
subprocess.Popen = self.old_popen
super(UtilTestCase, self).tearDown() super(UtilTestCase, self).tearDown()
def _set_uname(self, uname): def _set_uname(self, uname):
...@@ -237,6 +264,70 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase): ...@@ -237,6 +264,70 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase):
'header%(8s)s') % {'8s': '\n'+8*' '} 'header%(8s)s') % {'8s': '\n'+8*' '}
self.assertEquals(res, wanted) self.assertEquals(res, wanted)
def test_find_exe_version(self):
# the ld version scheme under MAC OS is:
# ^@(#)PROGRAM:ld PROJECT:ld64-VERSION
#
# where VERSION is a 2-digit number for major
# revisions. For instance under Leopard, it's
# currently 77
#
# Dots are used when branching is done.
#
# The SnowLeopard ld64 is currently 95.2.12
for output, version in (('@(#)PROGRAM:ld PROJECT:ld64-77', '77'),
('@(#)PROGRAM:ld PROJECT:ld64-95.2.12',
'95.2.12')):
result = _MAC_OS_X_LD_VERSION.search(output)
self.assertEquals(result.group(1), version)
def _find_executable(self, name):
if name in self._exes:
return name
return None
def test_get_compiler_versions(self):
# get_versions calls distutils.spawn.find_executable on
# 'gcc', 'ld' and 'dllwrap'
self.assertEquals(get_compiler_versions(), (None, None, None))
# Let's fake we have 'gcc' and it returns '3.4.5'
self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF'
res = get_compiler_versions()
self.assertEquals(str(res[0]), '3.4.5')
# and let's see what happens when the version
# doesn't match the regular expression
# (\d+\.\d+(\.\d+)*)
self._exes['gcc'] = 'very strange output'
res = get_compiler_versions()
self.assertEquals(res[0], None)
# same thing for ld
if sys.platform != 'darwin':
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
res = get_compiler_versions()
self.assertEquals(str(res[1]), '2.17.50')
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
res = get_compiler_versions()
self.assertEquals(res[1], None)
else:
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
res = get_compiler_versions()
self.assertEquals(res[1], None)
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
res = get_compiler_versions()
self.assertEquals(str(res[1]), '77')
# and dllwrap
self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF'
res = get_compiler_versions()
self.assertEquals(str(res[2]), '2.17.50')
self._exes['dllwrap'] = 'Cheese Wrap'
res = get_compiler_versions()
self.assertEquals(res[2], None)
def test_suite(): def test_suite():
return unittest.makeSuite(UtilTestCase) return unittest.makeSuite(UtilTestCase)
......
...@@ -7,10 +7,12 @@ one of the other *util.py modules. ...@@ -7,10 +7,12 @@ one of the other *util.py modules.
__revision__ = "$Id$" __revision__ = "$Id$"
import sys, os, string, re import sys, os, string, re
from distutils.errors import DistutilsPlatformError from distutils.errors import DistutilsPlatformError
from distutils.dep_util import newer from distutils.dep_util import newer
from distutils.spawn import spawn from distutils.spawn import spawn, find_executable
from distutils import log from distutils import log
from distutils.version import LooseVersion
def get_platform(): def get_platform():
"""Return a string that identifies the current platform. """Return a string that identifies the current platform.
...@@ -539,3 +541,53 @@ def rfc822_escape(header): ...@@ -539,3 +541,53 @@ def rfc822_escape(header):
lines = [x.strip() for x in header.split('\n')] lines = [x.strip() for x in header.split('\n')]
sep = '\n' + 8*' ' sep = '\n' + 8*' '
return sep.join(lines) return sep.join(lines)
_RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)')
_MAC_OS_X_LD_VERSION = re.compile('^@\(#\)PROGRAM:ld PROJECT:ld64-((\d+)(\.\d+)*)')
def _find_ld_version():
"""Finds the ld version. The version scheme differs under Mac OSX."""
if sys.platform == 'darwin':
return _find_exe_version('ld -v', _MAC_OS_X_LD_VERSION)
else:
return _find_exe_version('ld -v')
def _find_exe_version(cmd, pattern=_RE_VERSION):
"""Find the version of an executable by running `cmd` in the shell.
`pattern` is a compiled regular expression. If not provided, default
to _RE_VERSION. If the command is not found, or the output does not
match the mattern, returns None.
"""
from subprocess import Popen, PIPE
executable = cmd.split()[0]
if find_executable(executable) is None:
return None
pipe = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
try:
stdout, stderr = pipe.stdout.read(), pipe.stderr.read()
finally:
pipe.stdout.close()
pipe.stderr.close()
# some commands like ld under MacOS X, will give the
# output in the stderr, rather than stdout.
if stdout != '':
out_string = stdout
else:
out_string = stderr
result = pattern.search(out_string)
if result is None:
return None
return LooseVersion(result.group(1))
def get_compiler_versions():
"""Returns a tuple providing the versions of gcc, ld and dllwrap
For each command, if a command is not found, None is returned.
Otherwise a LooseVersion instance is returned.
"""
gcc = _find_exe_version('gcc -dumpversion')
ld = _find_ld_version()
dllwrap = _find_exe_version('dllwrap --version')
return gcc, ld, dllwrap
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment