]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/distutils/tests/test_build_ext.py
6543965cbb3a4e24bc09cb75b232ef2d48a95e19
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / distutils / tests / test_build_ext.py
1 import sys
2 import os
3 import tempfile
4 import shutil
5 from StringIO import StringIO
6 import textwrap
7
8 from distutils.core import Extension, Distribution
9 from distutils.command.build_ext import build_ext
10 from distutils import sysconfig
11 from distutils.tests import support
12 from distutils.errors import DistutilsSetupError, CompileError
13
14 import unittest
15 from test import test_support
16
17 # http://bugs.python.org/issue4373
18 # Don't load the xx module more than once.
19 ALREADY_TESTED = False
20
21 def _get_source_filename():
22 srcdir = sysconfig.get_config_var('srcdir')
23 if srcdir is None:
24 return os.path.join(sysconfig.project_base, 'Modules', 'xxmodule.c')
25 return os.path.join(srcdir, 'Modules', 'xxmodule.c')
26
27 _XX_MODULE_PATH = _get_source_filename()
28
29 class BuildExtTestCase(support.TempdirManager,
30 support.LoggingSilencer,
31 unittest.TestCase):
32 def setUp(self):
33 # Create a simple test environment
34 # Note that we're making changes to sys.path
35 super(BuildExtTestCase, self).setUp()
36 self.tmp_dir = tempfile.mkdtemp(prefix="pythontest_")
37 if os.path.exists(_XX_MODULE_PATH):
38 self.sys_path = sys.path[:]
39 sys.path.append(self.tmp_dir)
40 shutil.copy(_XX_MODULE_PATH, self.tmp_dir)
41
42 def tearDown(self):
43 # Get everything back to normal
44 if os.path.exists(_XX_MODULE_PATH):
45 test_support.unload('xx')
46 sys.path[:] = self.sys_path
47 # XXX on Windows the test leaves a directory
48 # with xx module in TEMP
49 shutil.rmtree(self.tmp_dir, os.name == 'nt' or
50 sys.platform == 'cygwin')
51 super(BuildExtTestCase, self).tearDown()
52
53 def _fixup_command(self, cmd):
54 # When Python was build with --enable-shared, -L. is not good enough
55 # to find the libpython<blah>.so. This is because regrtest runs it
56 # under a tempdir, not in the top level where the .so lives. By the
57 # time we've gotten here, Python's already been chdir'd to the
58 # tempdir.
59 #
60 # To further add to the fun, we can't just add library_dirs to the
61 # Extension() instance because that doesn't get plumbed through to the
62 # final compiler command.
63 if (sysconfig.get_config_var('Py_ENABLE_SHARED') and
64 not sys.platform.startswith('win')):
65 runshared = sysconfig.get_config_var('RUNSHARED')
66 if runshared is None:
67 cmd.library_dirs = ['.']
68 else:
69 name, equals, value = runshared.partition('=')
70 cmd.library_dirs = value.split(os.pathsep)
71
72 @unittest.skipIf(not os.path.exists(_XX_MODULE_PATH),
73 'xxmodule.c not found')
74 def test_build_ext(self):
75 global ALREADY_TESTED
76 xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
77 xx_ext = Extension('xx', [xx_c])
78 dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
79 dist.package_dir = self.tmp_dir
80 cmd = build_ext(dist)
81 self._fixup_command(cmd)
82 if os.name == "nt":
83 # On Windows, we must build a debug version iff running
84 # a debug build of Python
85 cmd.debug = sys.executable.endswith("_d.exe")
86 cmd.build_lib = self.tmp_dir
87 cmd.build_temp = self.tmp_dir
88
89 old_stdout = sys.stdout
90 if not test_support.verbose:
91 # silence compiler output
92 sys.stdout = StringIO()
93 try:
94 cmd.ensure_finalized()
95 cmd.run()
96 finally:
97 sys.stdout = old_stdout
98
99 if ALREADY_TESTED:
100 return
101 else:
102 ALREADY_TESTED = True
103
104 import xx
105
106 for attr in ('error', 'foo', 'new', 'roj'):
107 self.assertTrue(hasattr(xx, attr))
108
109 self.assertEqual(xx.foo(2, 5), 7)
110 self.assertEqual(xx.foo(13,15), 28)
111 self.assertEqual(xx.new().demo(), None)
112 doc = 'This is a template module just for instruction.'
113 self.assertEqual(xx.__doc__, doc)
114 self.assertTrue(isinstance(xx.Null(), xx.Null))
115 self.assertTrue(isinstance(xx.Str(), xx.Str))
116
117 def test_solaris_enable_shared(self):
118 dist = Distribution({'name': 'xx'})
119 cmd = build_ext(dist)
120 old = sys.platform
121
122 sys.platform = 'sunos' # fooling finalize_options
123 from distutils.sysconfig import _config_vars
124 old_var = _config_vars.get('Py_ENABLE_SHARED')
125 _config_vars['Py_ENABLE_SHARED'] = 1
126 try:
127 cmd.ensure_finalized()
128 finally:
129 sys.platform = old
130 if old_var is None:
131 del _config_vars['Py_ENABLE_SHARED']
132 else:
133 _config_vars['Py_ENABLE_SHARED'] = old_var
134
135 # make sure we get some library dirs under solaris
136 self.assertTrue(len(cmd.library_dirs) > 0)
137
138 def test_finalize_options(self):
139 # Make sure Python's include directories (for Python.h, pyconfig.h,
140 # etc.) are in the include search path.
141 modules = [Extension('foo', ['xxx'])]
142 dist = Distribution({'name': 'xx', 'ext_modules': modules})
143 cmd = build_ext(dist)
144 cmd.finalize_options()
145
146 from distutils import sysconfig
147 py_include = sysconfig.get_python_inc()
148 self.assertTrue(py_include in cmd.include_dirs)
149
150 plat_py_include = sysconfig.get_python_inc(plat_specific=1)
151 self.assertTrue(plat_py_include in cmd.include_dirs)
152
153 # make sure cmd.libraries is turned into a list
154 # if it's a string
155 cmd = build_ext(dist)
156 cmd.libraries = 'my_lib'
157 cmd.finalize_options()
158 self.assertEqual(cmd.libraries, ['my_lib'])
159
160 # make sure cmd.library_dirs is turned into a list
161 # if it's a string
162 cmd = build_ext(dist)
163 cmd.library_dirs = 'my_lib_dir'
164 cmd.finalize_options()
165 self.assertTrue('my_lib_dir' in cmd.library_dirs)
166
167 # make sure rpath is turned into a list
168 # if it's a list of os.pathsep's paths
169 cmd = build_ext(dist)
170 cmd.rpath = os.pathsep.join(['one', 'two'])
171 cmd.finalize_options()
172 self.assertEqual(cmd.rpath, ['one', 'two'])
173
174 # XXX more tests to perform for win32
175
176 # make sure define is turned into 2-tuples
177 # strings if they are ','-separated strings
178 cmd = build_ext(dist)
179 cmd.define = 'one,two'
180 cmd.finalize_options()
181 self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])
182
183 # make sure undef is turned into a list of
184 # strings if they are ','-separated strings
185 cmd = build_ext(dist)
186 cmd.undef = 'one,two'
187 cmd.finalize_options()
188 self.assertEqual(cmd.undef, ['one', 'two'])
189
190 # make sure swig_opts is turned into a list
191 cmd = build_ext(dist)
192 cmd.swig_opts = None
193 cmd.finalize_options()
194 self.assertEqual(cmd.swig_opts, [])
195
196 cmd = build_ext(dist)
197 cmd.swig_opts = '1 2'
198 cmd.finalize_options()
199 self.assertEqual(cmd.swig_opts, ['1', '2'])
200
201 def test_check_extensions_list(self):
202 dist = Distribution()
203 cmd = build_ext(dist)
204 cmd.finalize_options()
205
206 #'extensions' option must be a list of Extension instances
207 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, 'foo')
208
209 # each element of 'ext_modules' option must be an
210 # Extension instance or 2-tuple
211 exts = [('bar', 'foo', 'bar'), 'foo']
212 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
213
214 # first element of each tuple in 'ext_modules'
215 # must be the extension name (a string) and match
216 # a python dotted-separated name
217 exts = [('foo-bar', '')]
218 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
219
220 # second element of each tuple in 'ext_modules'
221 # must be a ary (build info)
222 exts = [('foo.bar', '')]
223 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
224
225 # ok this one should pass
226 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
227 'some': 'bar'})]
228 cmd.check_extensions_list(exts)
229 ext = exts[0]
230 self.assertTrue(isinstance(ext, Extension))
231
232 # check_extensions_list adds in ext the values passed
233 # when they are in ('include_dirs', 'library_dirs', 'libraries'
234 # 'extra_objects', 'extra_compile_args', 'extra_link_args')
235 self.assertEqual(ext.libraries, 'foo')
236 self.assertTrue(not hasattr(ext, 'some'))
237
238 # 'macros' element of build info dict must be 1- or 2-tuple
239 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
240 'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})]
241 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
242
243 exts[0][1]['macros'] = [('1', '2'), ('3',)]
244 cmd.check_extensions_list(exts)
245 self.assertEqual(exts[0].undef_macros, ['3'])
246 self.assertEqual(exts[0].define_macros, [('1', '2')])
247
248 def test_get_source_files(self):
249 modules = [Extension('foo', ['xxx'])]
250 dist = Distribution({'name': 'xx', 'ext_modules': modules})
251 cmd = build_ext(dist)
252 cmd.ensure_finalized()
253 self.assertEqual(cmd.get_source_files(), ['xxx'])
254
255 def test_compiler_option(self):
256 # cmd.compiler is an option and
257 # should not be overriden by a compiler instance
258 # when the command is run
259 dist = Distribution()
260 cmd = build_ext(dist)
261 cmd.compiler = 'unix'
262 cmd.ensure_finalized()
263 cmd.run()
264 self.assertEqual(cmd.compiler, 'unix')
265
266 def test_get_outputs(self):
267 tmp_dir = self.mkdtemp()
268 c_file = os.path.join(tmp_dir, 'foo.c')
269 self.write_file(c_file, 'void initfoo(void) {};\n')
270 ext = Extension('foo', [c_file])
271 dist = Distribution({'name': 'xx',
272 'ext_modules': [ext]})
273 cmd = build_ext(dist)
274 self._fixup_command(cmd)
275 cmd.ensure_finalized()
276 self.assertEqual(len(cmd.get_outputs()), 1)
277
278 if os.name == "nt":
279 cmd.debug = sys.executable.endswith("_d.exe")
280
281 cmd.build_lib = os.path.join(self.tmp_dir, 'build')
282 cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
283
284 # issue #5977 : distutils build_ext.get_outputs
285 # returns wrong result with --inplace
286 other_tmp_dir = os.path.realpath(self.mkdtemp())
287 old_wd = os.getcwd()
288 os.chdir(other_tmp_dir)
289 try:
290 cmd.inplace = 1
291 cmd.run()
292 so_file = cmd.get_outputs()[0]
293 finally:
294 os.chdir(old_wd)
295 self.assertTrue(os.path.exists(so_file))
296 self.assertEqual(os.path.splitext(so_file)[-1],
297 sysconfig.get_config_var('SO'))
298 so_dir = os.path.dirname(so_file)
299 self.assertEqual(so_dir, other_tmp_dir)
300 cmd.compiler = None
301 cmd.inplace = 0
302 cmd.run()
303 so_file = cmd.get_outputs()[0]
304 self.assertTrue(os.path.exists(so_file))
305 self.assertEqual(os.path.splitext(so_file)[-1],
306 sysconfig.get_config_var('SO'))
307 so_dir = os.path.dirname(so_file)
308 self.assertEqual(so_dir, cmd.build_lib)
309
310 # inplace = 0, cmd.package = 'bar'
311 build_py = cmd.get_finalized_command('build_py')
312 build_py.package_dir = {'': 'bar'}
313 path = cmd.get_ext_fullpath('foo')
314 # checking that the last directory is the build_dir
315 path = os.path.split(path)[0]
316 self.assertEqual(path, cmd.build_lib)
317
318 # inplace = 1, cmd.package = 'bar'
319 cmd.inplace = 1
320 other_tmp_dir = os.path.realpath(self.mkdtemp())
321 old_wd = os.getcwd()
322 os.chdir(other_tmp_dir)
323 try:
324 path = cmd.get_ext_fullpath('foo')
325 finally:
326 os.chdir(old_wd)
327 # checking that the last directory is bar
328 path = os.path.split(path)[0]
329 lastdir = os.path.split(path)[-1]
330 self.assertEqual(lastdir, 'bar')
331
332 def test_ext_fullpath(self):
333 ext = sysconfig.get_config_vars()['SO']
334 dist = Distribution()
335 cmd = build_ext(dist)
336 cmd.inplace = 1
337 cmd.distribution.package_dir = {'': 'src'}
338 cmd.distribution.packages = ['lxml', 'lxml.html']
339 curdir = os.getcwd()
340 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
341 path = cmd.get_ext_fullpath('lxml.etree')
342 self.assertEqual(wanted, path)
343
344 # building lxml.etree not inplace
345 cmd.inplace = 0
346 cmd.build_lib = os.path.join(curdir, 'tmpdir')
347 wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
348 path = cmd.get_ext_fullpath('lxml.etree')
349 self.assertEqual(wanted, path)
350
351 # building twisted.runner.portmap not inplace
352 build_py = cmd.get_finalized_command('build_py')
353 build_py.package_dir = {}
354 cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
355 path = cmd.get_ext_fullpath('twisted.runner.portmap')
356 wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner',
357 'portmap' + ext)
358 self.assertEqual(wanted, path)
359
360 # building twisted.runner.portmap inplace
361 cmd.inplace = 1
362 path = cmd.get_ext_fullpath('twisted.runner.portmap')
363 wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
364 self.assertEqual(wanted, path)
365
366 def test_build_ext_inplace(self):
367 etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
368 etree_ext = Extension('lxml.etree', [etree_c])
369 dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
370 cmd = build_ext(dist)
371 cmd.ensure_finalized()
372 cmd.inplace = 1
373 cmd.distribution.package_dir = {'': 'src'}
374 cmd.distribution.packages = ['lxml', 'lxml.html']
375 curdir = os.getcwd()
376 ext = sysconfig.get_config_var("SO")
377 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
378 path = cmd.get_ext_fullpath('lxml.etree')
379 self.assertEqual(wanted, path)
380
381 def test_setuptools_compat(self):
382 import distutils.core, distutils.extension, distutils.command.build_ext
383 saved_ext = distutils.extension.Extension
384 try:
385 # on some platforms, it loads the deprecated "dl" module
386 test_support.import_module('setuptools_build_ext', deprecated=True)
387
388 # theses import patch Distutils' Extension class
389 from setuptools_build_ext import build_ext as setuptools_build_ext
390 from setuptools_extension import Extension
391
392 etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
393 etree_ext = Extension('lxml.etree', [etree_c])
394 dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
395 cmd = setuptools_build_ext(dist)
396 cmd.ensure_finalized()
397 cmd.inplace = 1
398 cmd.distribution.package_dir = {'': 'src'}
399 cmd.distribution.packages = ['lxml', 'lxml.html']
400 curdir = os.getcwd()
401 ext = sysconfig.get_config_var("SO")
402 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
403 path = cmd.get_ext_fullpath('lxml.etree')
404 self.assertEqual(wanted, path)
405 finally:
406 # restoring Distutils' Extension class otherwise its broken
407 distutils.extension.Extension = saved_ext
408 distutils.core.Extension = saved_ext
409 distutils.command.build_ext.Extension = saved_ext
410
411 def test_build_ext_path_with_os_sep(self):
412 dist = Distribution({'name': 'UpdateManager'})
413 cmd = build_ext(dist)
414 cmd.ensure_finalized()
415 ext = sysconfig.get_config_var("SO")
416 ext_name = os.path.join('UpdateManager', 'fdsend')
417 ext_path = cmd.get_ext_fullpath(ext_name)
418 wanted = os.path.join(cmd.build_lib, 'UpdateManager', 'fdsend' + ext)
419 self.assertEqual(ext_path, wanted)
420
421 def test_build_ext_path_cross_platform(self):
422 if sys.platform != 'win32':
423 return
424 dist = Distribution({'name': 'UpdateManager'})
425 cmd = build_ext(dist)
426 cmd.ensure_finalized()
427 ext = sysconfig.get_config_var("SO")
428 # this needs to work even under win32
429 ext_name = 'UpdateManager/fdsend'
430 ext_path = cmd.get_ext_fullpath(ext_name)
431 wanted = os.path.join(cmd.build_lib, 'UpdateManager', 'fdsend' + ext)
432 self.assertEqual(ext_path, wanted)
433
434 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
435 def test_deployment_target(self):
436 self._try_compile_deployment_target()
437
438 orig_environ = os.environ
439 os.environ = orig_environ.copy()
440 self.addCleanup(setattr, os, 'environ', orig_environ)
441
442 os.environ['MACOSX_DEPLOYMENT_TARGET']='10.1'
443 self._try_compile_deployment_target()
444
445
446 def _try_compile_deployment_target(self):
447 deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')
448
449 with open(deptarget_c, 'w') as fp:
450 fp.write(textwrap.dedent('''\
451 #include <AvailabilityMacros.h>
452
453 int dummy;
454
455 #if TARGET != MAC_OS_X_VERSION_MIN_REQUIRED
456 #error "Unexpected target"
457 #endif
458
459 '''))
460
461 target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
462 target = tuple(map(int, target.split('.')))
463 target = '%02d%01d0' % target
464
465 deptarget_ext = Extension(
466 'deptarget',
467 [deptarget_c],
468 extra_compile_args=['-DTARGET=%s'%(target,)],
469 )
470 dist = Distribution({
471 'name': 'deptarget',
472 'ext_modules': [deptarget_ext]
473 })
474 dist.package_dir = self.tmp_dir
475 cmd = build_ext(dist)
476 cmd.build_lib = self.tmp_dir
477 cmd.build_temp = self.tmp_dir
478
479 try:
480 old_stdout = sys.stdout
481 cmd.ensure_finalized()
482 cmd.run()
483
484 except CompileError:
485 self.fail("Wrong deployment target during compilation")
486
487 def test_suite():
488 return unittest.makeSuite(BuildExtTestCase)
489
490 if __name__ == '__main__':
491 test_support.run_unittest(test_suite())