Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 015c810

Browse files
author
Tarek Ziadé
committed
Merged revisions 73336 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r73336 | tarek.ziade | 2009-06-10 20:49:50 +0200 (Wed, 10 Jun 2009) | 1 line Distutils: started code cleanup and test coverage for cygwinccompiler ........
1 parent fde29be commit 015c810

2 files changed

Lines changed: 170 additions & 70 deletions

File tree

Lib/distutils/cygwinccompiler.py

Lines changed: 50 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,19 @@
4747

4848
__revision__ = "$Id$"
4949

50-
import os,sys,copy
50+
import os
51+
import sys
52+
import copy
53+
from subprocess import Popen, PIPE
54+
import re
55+
5156
from distutils.ccompiler import gen_preprocess_options, gen_lib_options
5257
from distutils.unixccompiler import UnixCCompiler
5358
from distutils.file_util import write_file
5459
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
5560
from distutils import log
61+
from distutils.version import LooseVersion
62+
from distutils.spawn import find_executable
5663

5764
def get_msvcr():
5865
"""Include the appropriate MSVC runtime library if Python was built
@@ -347,16 +354,16 @@ def __init__ (self,
347354
CONFIG_H_UNCERTAIN = "uncertain"
348355

349356
def check_config_h():
357+
"""Check if the current Python installation appears amenable to building
358+
extensions with GCC.
359+
360+
Returns a tuple (status, details), where 'status' is one of the following
361+
constants:
362+
363+
- CONFIG_H_OK: all is well, go ahead and compile
364+
- CONFIG_H_NOTOK: doesn't look good
365+
- CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h
350366
351-
"""Check if the current Python installation (specifically, pyconfig.h)
352-
appears amenable to building extensions with GCC. Returns a tuple
353-
(status, details), where 'status' is one of the following constants:
354-
CONFIG_H_OK
355-
all is well, go ahead and compile
356-
CONFIG_H_NOTOK
357-
doesn't look good
358-
CONFIG_H_UNCERTAIN
359-
not sure -- unable to read pyconfig.h
360367
'details' is a human-readable string explaining the situation.
361368
362369
Note there are two ways to conclude "OK": either 'sys.version' contains
@@ -368,76 +375,49 @@ def check_config_h():
368375
# "pyconfig.h" check -- should probably be renamed...
369376

370377
from distutils import sysconfig
371-
# if sys.version contains GCC then python was compiled with
372-
# GCC, and the pyconfig.h file should be OK
373-
if sys.version.find("GCC") >= 0:
374-
return (CONFIG_H_OK, "sys.version mentions 'GCC'")
375378

379+
# if sys.version contains GCC then python was compiled with GCC, and the
380+
# pyconfig.h file should be OK
381+
if "GCC" in sys.version:
382+
return CONFIG_H_OK, "sys.version mentions 'GCC'"
383+
384+
# let's see if __GNUC__ is mentioned in python.h
376385
fn = sysconfig.get_config_h_filename()
377386
try:
378-
# It would probably better to read single lines to search.
379-
# But we do this only once, and it is fast enough
380-
f = open(fn)
381-
s = f.read()
382-
f.close()
383-
387+
with open(fn) as config_h:
388+
if "__GNUC__" in config_h.read():
389+
return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
390+
else:
391+
return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
384392
except IOError as exc:
385-
# if we can't read this file, we cannot say it is wrong
386-
# the compiler will complain later about this file as missing
387393
return (CONFIG_H_UNCERTAIN,
388394
"couldn't read '%s': %s" % (fn, exc.strerror))
389395

390-
else:
391-
# "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
392-
if s.find("__GNUC__") >= 0:
393-
return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
394-
else:
395-
return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
396+
RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)')
396397

398+
def _find_exe_version(cmd):
399+
"""Find the version of an executable by running `cmd` in the shell.
397400
401+
If the command is not found, or the output does not match
402+
`RE_VERSION`, returns None.
403+
"""
404+
executable = cmd.split()[0]
405+
if find_executable(executable) is None:
406+
return None
407+
out = Popen(cmd, shell=True, stdout=PIPE).stdout
408+
try:
409+
out_string = out.read()
410+
finally:
411+
out.close()
412+
result = RE_VERSION.search(out_string)
413+
if result is None:
414+
return None
415+
return LooseVersion(result.group(1))
398416

399417
def get_versions():
400418
""" Try to find out the versions of gcc, ld and dllwrap.
401-
If not possible it returns None for it.
402-
"""
403-
from distutils.version import LooseVersion
404-
from distutils.spawn import find_executable
405-
import re
406419
407-
gcc_exe = find_executable('gcc')
408-
if gcc_exe:
409-
out = os.popen(gcc_exe + ' -dumpversion','r')
410-
out_string = out.read()
411-
out.close()
412-
result = re.search('(\d+\.\d+(\.\d+)*)', out_string, re.ASCII)
413-
if result:
414-
gcc_version = LooseVersion(result.group(1))
415-
else:
416-
gcc_version = None
417-
else:
418-
gcc_version = None
419-
ld_exe = find_executable('ld')
420-
if ld_exe:
421-
out = os.popen(ld_exe + ' -v','r')
422-
out_string = out.read()
423-
out.close()
424-
result = re.search('(\d+\.\d+(\.\d+)*)', out_string, re.ASCII)
425-
if result:
426-
ld_version = LooseVersion(result.group(1))
427-
else:
428-
ld_version = None
429-
else:
430-
ld_version = None
431-
dllwrap_exe = find_executable('dllwrap')
432-
if dllwrap_exe:
433-
out = os.popen(dllwrap_exe + ' --version','r')
434-
out_string = out.read()
435-
out.close()
436-
result = re.search(' (\d+\.\d+(\.\d+)*)', out_string, re.ASCII)
437-
if result:
438-
dllwrap_version = LooseVersion(result.group(1))
439-
else:
440-
dllwrap_version = None
441-
else:
442-
dllwrap_version = None
443-
return (gcc_version, ld_version, dllwrap_version)
420+
If not possible it returns None for it.
421+
"""
422+
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
423+
return tuple([_find_exe_version(cmd) for cmd in commands])
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""Tests for distutils.cygwinccompiler."""
2+
import unittest
3+
import sys
4+
import os
5+
from io import StringIO
6+
import subprocess
7+
8+
from distutils import cygwinccompiler
9+
from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h,
10+
CONFIG_H_OK, CONFIG_H_NOTOK,
11+
CONFIG_H_UNCERTAIN, get_versions)
12+
from distutils.tests import support
13+
14+
class FakePopen(object):
15+
test_class = None
16+
17+
def __init__(self, cmd, shell, stdout):
18+
self.cmd = cmd.split()[0]
19+
exes = self.test_class._exes
20+
if self.cmd in exes:
21+
self.stdout = StringIO(exes[self.cmd])
22+
else:
23+
self.stdout = os.popen(cmd, 'r')
24+
25+
26+
class CygwinCCompilerTestCase(support.TempdirManager,
27+
unittest.TestCase):
28+
29+
def setUp(self):
30+
super(CygwinCCompilerTestCase, self).setUp()
31+
self.version = sys.version
32+
self.python_h = os.path.join(self.mkdtemp(), 'python.h')
33+
from distutils import sysconfig
34+
self.old_get_config_h_filename = sysconfig.get_config_h_filename
35+
sysconfig.get_config_h_filename = self._get_config_h_filename
36+
self.old_find_executable = cygwinccompiler.find_executable
37+
cygwinccompiler.find_executable = self._find_executable
38+
self._exes = {}
39+
self.old_popen = cygwinccompiler.Popen
40+
FakePopen.test_class = self
41+
cygwinccompiler.Popen = FakePopen
42+
43+
def tearDown(self):
44+
sys.version = self.version
45+
from distutils import sysconfig
46+
sysconfig.get_config_h_filename = self.old_get_config_h_filename
47+
cygwinccompiler.find_executable = self.old_find_executable
48+
cygwinccompiler.Popen = self.old_popen
49+
super(CygwinCCompilerTestCase, self).tearDown()
50+
51+
def _get_config_h_filename(self):
52+
return self.python_h
53+
54+
def _find_executable(self, name):
55+
if name in self._exes:
56+
return name
57+
return None
58+
59+
def test_check_config_h(self):
60+
61+
# check_config_h looks for "GCC" in sys.version first
62+
# returns CONFIG_H_OK if found
63+
sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC '
64+
'4.0.1 (Apple Computer, Inc. build 5370)]')
65+
66+
self.assertEquals(check_config_h()[0], CONFIG_H_OK)
67+
68+
# then it tries to see if it can find "__GNUC__" in pyconfig.h
69+
sys.version = 'something without the *CC word'
70+
71+
# if the file doesn't exist it returns CONFIG_H_UNCERTAIN
72+
self.assertEquals(check_config_h()[0], CONFIG_H_UNCERTAIN)
73+
74+
# if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK
75+
self.write_file(self.python_h, 'xxx')
76+
self.assertEquals(check_config_h()[0], CONFIG_H_NOTOK)
77+
78+
# and CONFIG_H_OK if __GNUC__ is found
79+
self.write_file(self.python_h, 'xxx __GNUC__ xxx')
80+
self.assertEquals(check_config_h()[0], CONFIG_H_OK)
81+
82+
def test_get_versions(self):
83+
84+
# get_versions calls distutils.spawn.find_executable on
85+
# 'gcc', 'ld' and 'dllwrap'
86+
self.assertEquals(get_versions(), (None, None, None))
87+
88+
# Let's fake we have 'gcc' and it returns '3.4.5'
89+
self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF'
90+
res = get_versions()
91+
self.assertEquals(str(res[0]), '3.4.5')
92+
93+
# and let's see what happens when the version
94+
# doesn't match the regular expression
95+
# (\d+\.\d+(\.\d+)*)
96+
self._exes['gcc'] = 'very strange output'
97+
res = get_versions()
98+
self.assertEquals(res[0], None)
99+
100+
# same thing for ld
101+
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
102+
res = get_versions()
103+
self.assertEquals(str(res[1]), '2.17.50')
104+
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
105+
res = get_versions()
106+
self.assertEquals(res[1], None)
107+
108+
# and dllwrap
109+
self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF'
110+
res = get_versions()
111+
self.assertEquals(str(res[2]), '2.17.50')
112+
self._exes['dllwrap'] = 'Cheese Wrap'
113+
res = get_versions()
114+
self.assertEquals(res[2], None)
115+
116+
def test_suite():
117+
return unittest.makeSuite(CygwinCCompilerTestCase)
118+
119+
if __name__ == '__main__':
120+
test_support.run_unittest(test_suite())

0 commit comments

Comments
 (0)