mirror of
https://github.com/python/cpython.git
synced 2025-08-15 22:30:42 +00:00
Distutils: started code cleanup and test coverage for cygwinccompiler
This commit is contained in:
parent
1672dc60ec
commit
7ca57aa9fa
2 changed files with 170 additions and 71 deletions
|
@ -47,12 +47,19 @@ cygwin in no-cygwin mode).
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import os,sys,copy
|
import os
|
||||||
|
import sys
|
||||||
|
import copy
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
import re
|
||||||
|
|
||||||
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.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
|
||||||
|
@ -348,16 +355,16 @@ CONFIG_H_NOTOK = "not ok"
|
||||||
CONFIG_H_UNCERTAIN = "uncertain"
|
CONFIG_H_UNCERTAIN = "uncertain"
|
||||||
|
|
||||||
def check_config_h():
|
def check_config_h():
|
||||||
|
"""Check if the current Python installation appears amenable to building
|
||||||
|
extensions with GCC.
|
||||||
|
|
||||||
|
Returns a tuple (status, details), where 'status' is one of the following
|
||||||
|
constants:
|
||||||
|
|
||||||
|
- CONFIG_H_OK: all is well, go ahead and compile
|
||||||
|
- CONFIG_H_NOTOK: doesn't look good
|
||||||
|
- CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h
|
||||||
|
|
||||||
"""Check if the current Python installation (specifically, pyconfig.h)
|
|
||||||
appears amenable to building extensions with GCC. Returns a tuple
|
|
||||||
(status, details), where 'status' is one of the following constants:
|
|
||||||
CONFIG_H_OK
|
|
||||||
all is well, go ahead and compile
|
|
||||||
CONFIG_H_NOTOK
|
|
||||||
doesn't look good
|
|
||||||
CONFIG_H_UNCERTAIN
|
|
||||||
not sure -- unable to read pyconfig.h
|
|
||||||
'details' is a human-readable string explaining the situation.
|
'details' is a human-readable string explaining the situation.
|
||||||
|
|
||||||
Note there are two ways to conclude "OK": either 'sys.version' contains
|
Note there are two ways to conclude "OK": either 'sys.version' contains
|
||||||
|
@ -369,77 +376,49 @@ def check_config_h():
|
||||||
# "pyconfig.h" check -- should probably be renamed...
|
# "pyconfig.h" check -- should probably be renamed...
|
||||||
|
|
||||||
from distutils import sysconfig
|
from distutils import sysconfig
|
||||||
import string
|
|
||||||
# if sys.version contains GCC then python was compiled with
|
|
||||||
# GCC, and the pyconfig.h file should be OK
|
|
||||||
if string.find(sys.version,"GCC") >= 0:
|
|
||||||
return (CONFIG_H_OK, "sys.version mentions 'GCC'")
|
|
||||||
|
|
||||||
|
# if sys.version contains GCC then python was compiled with GCC, and the
|
||||||
|
# pyconfig.h file should be OK
|
||||||
|
if "GCC" in sys.version:
|
||||||
|
return CONFIG_H_OK, "sys.version mentions 'GCC'"
|
||||||
|
|
||||||
|
# let's see if __GNUC__ is mentioned in python.h
|
||||||
fn = sysconfig.get_config_h_filename()
|
fn = sysconfig.get_config_h_filename()
|
||||||
try:
|
try:
|
||||||
# It would probably better to read single lines to search.
|
with open(fn) as config_h:
|
||||||
# But we do this only once, and it is fast enough
|
if "__GNUC__" in config_h.read():
|
||||||
f = open(fn)
|
return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
|
||||||
s = f.read()
|
else:
|
||||||
f.close()
|
return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
|
||||||
|
|
||||||
except IOError, exc:
|
except IOError, exc:
|
||||||
# if we can't read this file, we cannot say it is wrong
|
|
||||||
# the compiler will complain later about this file as missing
|
|
||||||
return (CONFIG_H_UNCERTAIN,
|
return (CONFIG_H_UNCERTAIN,
|
||||||
"couldn't read '%s': %s" % (fn, exc.strerror))
|
"couldn't read '%s': %s" % (fn, exc.strerror))
|
||||||
|
|
||||||
else:
|
RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)')
|
||||||
# "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
|
|
||||||
if string.find(s,"__GNUC__") >= 0:
|
|
||||||
return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
|
|
||||||
else:
|
|
||||||
return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
|
|
||||||
|
|
||||||
|
def _find_exe_version(cmd):
|
||||||
|
"""Find the version of an executable by running `cmd` in the shell.
|
||||||
|
|
||||||
|
If the command is not found, or the output does not match
|
||||||
|
`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.
|
|
||||||
"""
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
from distutils.spawn import find_executable
|
|
||||||
import re
|
|
||||||
|
|
||||||
gcc_exe = find_executable('gcc')
|
If not possible it returns None for it.
|
||||||
if gcc_exe:
|
"""
|
||||||
out = os.popen(gcc_exe + ' -dumpversion','r')
|
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
|
||||||
out_string = out.read()
|
return tuple([_find_exe_version(cmd) for cmd in commands])
|
||||||
out.close()
|
|
||||||
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
|
|
||||||
if result:
|
|
||||||
gcc_version = LooseVersion(result.group(1))
|
|
||||||
else:
|
|
||||||
gcc_version = None
|
|
||||||
else:
|
|
||||||
gcc_version = None
|
|
||||||
ld_exe = find_executable('ld')
|
|
||||||
if ld_exe:
|
|
||||||
out = os.popen(ld_exe + ' -v','r')
|
|
||||||
out_string = out.read()
|
|
||||||
out.close()
|
|
||||||
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
|
|
||||||
if result:
|
|
||||||
ld_version = LooseVersion(result.group(1))
|
|
||||||
else:
|
|
||||||
ld_version = None
|
|
||||||
else:
|
|
||||||
ld_version = None
|
|
||||||
dllwrap_exe = find_executable('dllwrap')
|
|
||||||
if dllwrap_exe:
|
|
||||||
out = os.popen(dllwrap_exe + ' --version','r')
|
|
||||||
out_string = out.read()
|
|
||||||
out.close()
|
|
||||||
result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
|
|
||||||
if result:
|
|
||||||
dllwrap_version = LooseVersion(result.group(1))
|
|
||||||
else:
|
|
||||||
dllwrap_version = None
|
|
||||||
else:
|
|
||||||
dllwrap_version = None
|
|
||||||
return (gcc_version, ld_version, dllwrap_version)
|
|
||||||
|
|
120
Lib/distutils/tests/test_cygwinccompiler.py
Normal file
120
Lib/distutils/tests/test_cygwinccompiler.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
"""Tests for distutils.cygwinccompiler."""
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from StringIO import StringIO
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from distutils import cygwinccompiler
|
||||||
|
from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h,
|
||||||
|
CONFIG_H_OK, CONFIG_H_NOTOK,
|
||||||
|
CONFIG_H_UNCERTAIN, get_versions)
|
||||||
|
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,
|
||||||
|
unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(CygwinCCompilerTestCase, self).setUp()
|
||||||
|
self.version = sys.version
|
||||||
|
self.python_h = os.path.join(self.mkdtemp(), 'python.h')
|
||||||
|
from distutils import sysconfig
|
||||||
|
self.old_get_config_h_filename = sysconfig.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):
|
||||||
|
sys.version = self.version
|
||||||
|
from distutils import sysconfig
|
||||||
|
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()
|
||||||
|
|
||||||
|
def _get_config_h_filename(self):
|
||||||
|
return self.python_h
|
||||||
|
|
||||||
|
def _find_executable(self, name):
|
||||||
|
if name in self._exes:
|
||||||
|
return name
|
||||||
|
return None
|
||||||
|
|
||||||
|
def test_check_config_h(self):
|
||||||
|
|
||||||
|
# check_config_h looks for "GCC" in sys.version first
|
||||||
|
# returns CONFIG_H_OK if found
|
||||||
|
sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC '
|
||||||
|
'4.0.1 (Apple Computer, Inc. build 5370)]')
|
||||||
|
|
||||||
|
self.assertEquals(check_config_h()[0], CONFIG_H_OK)
|
||||||
|
|
||||||
|
# then it tries to see if it can find "__GNUC__" in pyconfig.h
|
||||||
|
sys.version = 'something without the *CC word'
|
||||||
|
|
||||||
|
# if the file doesn't exist it returns CONFIG_H_UNCERTAIN
|
||||||
|
self.assertEquals(check_config_h()[0], CONFIG_H_UNCERTAIN)
|
||||||
|
|
||||||
|
# if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK
|
||||||
|
self.write_file(self.python_h, 'xxx')
|
||||||
|
self.assertEquals(check_config_h()[0], CONFIG_H_NOTOK)
|
||||||
|
|
||||||
|
# and CONFIG_H_OK if __GNUC__ is found
|
||||||
|
self.write_file(self.python_h, 'xxx __GNUC__ xxx')
|
||||||
|
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_suite():
|
||||||
|
return unittest.makeSuite(CygwinCCompilerTestCase)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_support.run_unittest(test_suite())
|
Loading…
Add table
Add a link
Reference in a new issue