• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Tests for distutils.sysconfig."""
2import contextlib
3import os
4import shutil
5import subprocess
6import sys
7import textwrap
8import unittest
9
10from distutils import sysconfig
11from distutils.ccompiler import get_default_compiler
12from distutils.tests import support
13from test.support import TESTFN, run_unittest, check_warnings, swap_item
14
15class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
16    def setUp(self):
17        super(SysconfigTestCase, self).setUp()
18        self.makefile = None
19
20    def tearDown(self):
21        if self.makefile is not None:
22            os.unlink(self.makefile)
23        self.cleanup_testfn()
24        super(SysconfigTestCase, self).tearDown()
25
26    def cleanup_testfn(self):
27        if os.path.isfile(TESTFN):
28            os.remove(TESTFN)
29        elif os.path.isdir(TESTFN):
30            shutil.rmtree(TESTFN)
31
32    def test_get_config_h_filename(self):
33        config_h = sysconfig.get_config_h_filename()
34        self.assertTrue(os.path.isfile(config_h), config_h)
35
36    def test_get_python_lib(self):
37        # XXX doesn't work on Linux when Python was never installed before
38        #self.assertTrue(os.path.isdir(lib_dir), lib_dir)
39        # test for pythonxx.lib?
40        self.assertNotEqual(sysconfig.get_python_lib(),
41                            sysconfig.get_python_lib(prefix=TESTFN))
42
43    def test_get_config_vars(self):
44        cvars = sysconfig.get_config_vars()
45        self.assertIsInstance(cvars, dict)
46        self.assertTrue(cvars)
47
48    def test_srcdir(self):
49        # See Issues #15322, #15364.
50        srcdir = sysconfig.get_config_var('srcdir')
51
52        self.assertTrue(os.path.isabs(srcdir), srcdir)
53        self.assertTrue(os.path.isdir(srcdir), srcdir)
54
55        if sysconfig.python_build:
56            # The python executable has not been installed so srcdir
57            # should be a full source checkout.
58            Python_h = os.path.join(srcdir, 'Include', 'Python.h')
59            self.assertTrue(os.path.exists(Python_h), Python_h)
60            self.assertTrue(sysconfig._is_python_source_dir(srcdir))
61        elif os.name == 'posix':
62            self.assertEqual(
63                os.path.dirname(sysconfig.get_makefile_filename()),
64                srcdir)
65
66    def test_srcdir_independent_of_cwd(self):
67        # srcdir should be independent of the current working directory
68        # See Issues #15322, #15364.
69        srcdir = sysconfig.get_config_var('srcdir')
70        cwd = os.getcwd()
71        try:
72            os.chdir('..')
73            srcdir2 = sysconfig.get_config_var('srcdir')
74        finally:
75            os.chdir(cwd)
76        self.assertEqual(srcdir, srcdir2)
77
78    def customize_compiler(self):
79        # make sure AR gets caught
80        class compiler:
81            compiler_type = 'unix'
82
83            def set_executables(self, **kw):
84                self.exes = kw
85
86        sysconfig_vars = {
87            'AR': 'sc_ar',
88            'CC': 'sc_cc',
89            'CXX': 'sc_cxx',
90            'ARFLAGS': '--sc-arflags',
91            'CFLAGS': '--sc-cflags',
92            'CCSHARED': '--sc-ccshared',
93            'LDSHARED': 'sc_ldshared',
94            'SHLIB_SUFFIX': 'sc_shutil_suffix',
95
96            # On macOS, disable _osx_support.customize_compiler()
97            'CUSTOMIZED_OSX_COMPILER': 'True',
98        }
99
100        comp = compiler()
101        with contextlib.ExitStack() as cm:
102            for key, value in sysconfig_vars.items():
103                cm.enter_context(swap_item(sysconfig._config_vars, key, value))
104            sysconfig.customize_compiler(comp)
105
106        return comp
107
108    @unittest.skipUnless(get_default_compiler() == 'unix',
109                         'not testing if default compiler is not unix')
110    def test_customize_compiler(self):
111        # Make sure that sysconfig._config_vars is initialized
112        sysconfig.get_config_vars()
113
114        os.environ['AR'] = 'env_ar'
115        os.environ['CC'] = 'env_cc'
116        os.environ['CPP'] = 'env_cpp'
117        os.environ['CXX'] = 'env_cxx --env-cxx-flags'
118        os.environ['LDSHARED'] = 'env_ldshared'
119        os.environ['LDFLAGS'] = '--env-ldflags'
120        os.environ['ARFLAGS'] = '--env-arflags'
121        os.environ['CFLAGS'] = '--env-cflags'
122        os.environ['CPPFLAGS'] = '--env-cppflags'
123
124        comp = self.customize_compiler()
125        self.assertEqual(comp.exes['archiver'],
126                         'env_ar --env-arflags')
127        self.assertEqual(comp.exes['preprocessor'],
128                         'env_cpp --env-cppflags')
129        self.assertEqual(comp.exes['compiler'],
130                         'env_cc --sc-cflags --env-cflags --env-cppflags')
131        self.assertEqual(comp.exes['compiler_so'],
132                         ('env_cc --sc-cflags '
133                          '--env-cflags ''--env-cppflags --sc-ccshared'))
134        self.assertEqual(comp.exes['compiler_cxx'],
135                         'env_cxx --env-cxx-flags')
136        self.assertEqual(comp.exes['linker_exe'],
137                         'env_cc')
138        self.assertEqual(comp.exes['linker_so'],
139                         ('env_ldshared --env-ldflags --env-cflags'
140                          ' --env-cppflags'))
141        self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
142
143        del os.environ['AR']
144        del os.environ['CC']
145        del os.environ['CPP']
146        del os.environ['CXX']
147        del os.environ['LDSHARED']
148        del os.environ['LDFLAGS']
149        del os.environ['ARFLAGS']
150        del os.environ['CFLAGS']
151        del os.environ['CPPFLAGS']
152
153        comp = self.customize_compiler()
154        self.assertEqual(comp.exes['archiver'],
155                         'sc_ar --sc-arflags')
156        self.assertEqual(comp.exes['preprocessor'],
157                         'sc_cc -E')
158        self.assertEqual(comp.exes['compiler'],
159                         'sc_cc --sc-cflags')
160        self.assertEqual(comp.exes['compiler_so'],
161                         'sc_cc --sc-cflags --sc-ccshared')
162        self.assertEqual(comp.exes['compiler_cxx'],
163                         'sc_cxx')
164        self.assertEqual(comp.exes['linker_exe'],
165                         'sc_cc')
166        self.assertEqual(comp.exes['linker_so'],
167                         'sc_ldshared')
168        self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
169
170    def test_parse_makefile_base(self):
171        self.makefile = TESTFN
172        fd = open(self.makefile, 'w')
173        try:
174            fd.write(r"CONFIG_ARGS=  '--arg1=optarg1' 'ENV=LIB'" '\n')
175            fd.write('VAR=$OTHER\nOTHER=foo')
176        finally:
177            fd.close()
178        d = sysconfig.parse_makefile(self.makefile)
179        self.assertEqual(d, {'CONFIG_ARGS': "'--arg1=optarg1' 'ENV=LIB'",
180                             'OTHER': 'foo'})
181
182    def test_parse_makefile_literal_dollar(self):
183        self.makefile = TESTFN
184        fd = open(self.makefile, 'w')
185        try:
186            fd.write(r"CONFIG_ARGS=  '--arg1=optarg1' 'ENV=\$$LIB'" '\n')
187            fd.write('VAR=$OTHER\nOTHER=foo')
188        finally:
189            fd.close()
190        d = sysconfig.parse_makefile(self.makefile)
191        self.assertEqual(d, {'CONFIG_ARGS': r"'--arg1=optarg1' 'ENV=\$LIB'",
192                             'OTHER': 'foo'})
193
194
195    def test_sysconfig_module(self):
196        import sysconfig as global_sysconfig
197        self.assertEqual(global_sysconfig.get_config_var('CFLAGS'),
198                         sysconfig.get_config_var('CFLAGS'))
199        self.assertEqual(global_sysconfig.get_config_var('LDFLAGS'),
200                         sysconfig.get_config_var('LDFLAGS'))
201
202    @unittest.skipIf(sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'),
203                     'compiler flags customized')
204    def test_sysconfig_compiler_vars(self):
205        # On OS X, binary installers support extension module building on
206        # various levels of the operating system with differing Xcode
207        # configurations.  This requires customization of some of the
208        # compiler configuration directives to suit the environment on
209        # the installed machine.  Some of these customizations may require
210        # running external programs and, so, are deferred until needed by
211        # the first extension module build.  With Python 3.3, only
212        # the Distutils version of sysconfig is used for extension module
213        # builds, which happens earlier in the Distutils tests.  This may
214        # cause the following tests to fail since no tests have caused
215        # the global version of sysconfig to call the customization yet.
216        # The solution for now is to simply skip this test in this case.
217        # The longer-term solution is to only have one version of sysconfig.
218
219        import sysconfig as global_sysconfig
220        if sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'):
221            self.skipTest('compiler flags customized')
222        self.assertEqual(global_sysconfig.get_config_var('LDSHARED'),
223                         sysconfig.get_config_var('LDSHARED'))
224        self.assertEqual(global_sysconfig.get_config_var('CC'),
225                         sysconfig.get_config_var('CC'))
226
227    @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None,
228                     'EXT_SUFFIX required for this test')
229    def test_SO_deprecation(self):
230        self.assertWarns(DeprecationWarning,
231                         sysconfig.get_config_var, 'SO')
232
233    @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None,
234                     'EXT_SUFFIX required for this test')
235    def test_SO_value(self):
236        with check_warnings(('', DeprecationWarning)):
237            self.assertEqual(sysconfig.get_config_var('SO'),
238                             sysconfig.get_config_var('EXT_SUFFIX'))
239
240    @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None,
241                     'EXT_SUFFIX required for this test')
242    def test_SO_in_vars(self):
243        vars = sysconfig.get_config_vars()
244        self.assertIsNotNone(vars['SO'])
245        self.assertEqual(vars['SO'], vars['EXT_SUFFIX'])
246
247    def test_customize_compiler_before_get_config_vars(self):
248        # Issue #21923: test that a Distribution compiler
249        # instance can be called without an explicit call to
250        # get_config_vars().
251        with open(TESTFN, 'w') as f:
252            f.writelines(textwrap.dedent('''\
253                from distutils.core import Distribution
254                config = Distribution().get_command_obj('config')
255                # try_compile may pass or it may fail if no compiler
256                # is found but it should not raise an exception.
257                rc = config.try_compile('int x;')
258                '''))
259        p = subprocess.Popen([str(sys.executable), TESTFN],
260                stdout=subprocess.PIPE,
261                stderr=subprocess.STDOUT,
262                universal_newlines=True)
263        outs, errs = p.communicate()
264        self.assertEqual(0, p.returncode, "Subprocess failed: " + outs)
265
266
267def test_suite():
268    suite = unittest.TestSuite()
269    suite.addTest(unittest.makeSuite(SysconfigTestCase))
270    return suite
271
272
273if __name__ == '__main__':
274    run_unittest(test_suite())
275