blob: de53afb1c3bd4b43ca0812aaff29bb5aa25d9e7b [file] [log] [blame]
Georg Brandlb533e262008-05-25 18:19:30 +00001import sys
2import os
Georg Brandlb533e262008-05-25 18:19:30 +00003from io import StringIO
Ronald Oussoren222e89a2011-05-15 16:46:11 +02004import textwrap
Georg Brandlb533e262008-05-25 18:19:30 +00005
Barry Warsaw8cf4eae2010-10-16 01:04:07 +00006from distutils.core import Distribution
Georg Brandlb533e262008-05-25 18:19:30 +00007from distutils.command.build_ext import build_ext
Tarek Ziadé36797272010-07-22 12:50:05 +00008from distutils import sysconfig
Éric Araujodef15da2011-08-20 06:27:18 +02009from distutils.tests.support import (TempdirManager, LoggingSilencer,
10 copy_xxmodule_c)
Tarek Ziadéb2e36f12009-03-31 22:37:55 +000011from distutils.extension import Extension
Barry Warsaw8cf4eae2010-10-16 01:04:07 +000012from distutils.errors import (
Ned Deilyd13007f2011-06-28 19:43:15 -070013 CompileError, DistutilsPlatformError, DistutilsSetupError,
14 UnknownFileError)
Georg Brandlb533e262008-05-25 18:19:30 +000015
16import unittest
17from test import support
18
Christian Heimes3e7e0692008-11-25 21:21:32 +000019# http://bugs.python.org/issue4373
20# Don't load the xx module more than once.
21ALREADY_TESTED = False
22
Neil Schemenauerd8f63bb2009-02-06 21:42:05 +000023
Tarek Ziadé36797272010-07-22 12:50:05 +000024class BuildExtTestCase(TempdirManager,
25 LoggingSilencer,
26 unittest.TestCase):
Georg Brandlb533e262008-05-25 18:19:30 +000027 def setUp(self):
28 # Create a simple test environment
29 # Note that we're making changes to sys.path
Tarek Ziadé38e3d512009-02-27 12:58:56 +000030 super(BuildExtTestCase, self).setUp()
Tarek Ziadéc1375d52009-02-14 14:35:51 +000031 self.tmp_dir = self.mkdtemp()
Tarek Ziadé36797272010-07-22 12:50:05 +000032 self.sys_path = sys.path, sys.path[:]
33 sys.path.append(self.tmp_dir)
Tarek Ziadé38e3d512009-02-27 12:58:56 +000034 if sys.version > "2.6":
35 import site
36 self.old_user_base = site.USER_BASE
37 site.USER_BASE = self.mkdtemp()
38 from distutils.command import build_ext
39 build_ext.USER_BASE = site.USER_BASE
Georg Brandlb533e262008-05-25 18:19:30 +000040
Barry Warsaw8cf4eae2010-10-16 01:04:07 +000041 def _fixup_command(self, cmd):
42 # When Python was build with --enable-shared, -L. is not good enough
43 # to find the libpython<blah>.so. This is because regrtest runs it
44 # under a tempdir, not in the top level where the .so lives. By the
45 # time we've gotten here, Python's already been chdir'd to the
46 # tempdir.
47 #
48 # To further add to the fun, we can't just add library_dirs to the
49 # Extension() instance because that doesn't get plumbed through to the
50 # final compiler command.
Barry Warsaw4ebfdf02010-10-22 17:17:51 +000051 if (sysconfig.get_config_var('Py_ENABLE_SHARED') and
52 not sys.platform.startswith('win')):
Éric Araujo68fc9aa2010-10-21 23:02:07 +000053 runshared = sysconfig.get_config_var('RUNSHARED')
54 if runshared is None:
55 cmd.library_dirs = ['.']
56 else:
57 name, equals, value = runshared.partition('=')
58 cmd.library_dirs = value.split(os.pathsep)
Barry Warsaw8cf4eae2010-10-16 01:04:07 +000059
Georg Brandlb533e262008-05-25 18:19:30 +000060 def test_build_ext(self):
Christian Heimes3e7e0692008-11-25 21:21:32 +000061 global ALREADY_TESTED
Éric Araujodef15da2011-08-20 06:27:18 +020062 copy_xxmodule_c(self.tmp_dir)
Georg Brandlb533e262008-05-25 18:19:30 +000063 xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
64 xx_ext = Extension('xx', [xx_c])
65 dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
66 dist.package_dir = self.tmp_dir
67 cmd = build_ext(dist)
Barry Warsaw8cf4eae2010-10-16 01:04:07 +000068 self._fixup_command(cmd)
Thomas Heller84b7f0c2008-05-26 11:51:44 +000069 if os.name == "nt":
70 # On Windows, we must build a debug version iff running
71 # a debug build of Python
72 cmd.debug = sys.executable.endswith("_d.exe")
Georg Brandlb533e262008-05-25 18:19:30 +000073 cmd.build_lib = self.tmp_dir
74 cmd.build_temp = self.tmp_dir
75
76 old_stdout = sys.stdout
77 if not support.verbose:
78 # silence compiler output
79 sys.stdout = StringIO()
80 try:
81 cmd.ensure_finalized()
82 cmd.run()
83 finally:
84 sys.stdout = old_stdout
85
Christian Heimes3e7e0692008-11-25 21:21:32 +000086 if ALREADY_TESTED:
87 return
88 else:
89 ALREADY_TESTED = True
90
Georg Brandlb533e262008-05-25 18:19:30 +000091 import xx
92
93 for attr in ('error', 'foo', 'new', 'roj'):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000094 self.assertTrue(hasattr(xx, attr))
Georg Brandlb533e262008-05-25 18:19:30 +000095
Ezio Melottib3aedd42010-11-20 19:04:17 +000096 self.assertEqual(xx.foo(2, 5), 7)
97 self.assertEqual(xx.foo(13,15), 28)
98 self.assertEqual(xx.new().demo(), None)
Georg Brandlb533e262008-05-25 18:19:30 +000099 doc = 'This is a template module just for instruction.'
Ezio Melottib3aedd42010-11-20 19:04:17 +0000100 self.assertEqual(xx.__doc__, doc)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000101 self.assertTrue(isinstance(xx.Null(), xx.Null))
102 self.assertTrue(isinstance(xx.Str(), xx.Str))
Georg Brandlb533e262008-05-25 18:19:30 +0000103
Tarek Ziadé36797272010-07-22 12:50:05 +0000104 def tearDown(self):
105 # Get everything back to normal
106 support.unload('xx')
107 sys.path = self.sys_path[0]
108 sys.path[:] = self.sys_path[1]
109 if sys.version > "2.6":
110 import site
111 site.USER_BASE = self.old_user_base
112 from distutils.command import build_ext
113 build_ext.USER_BASE = self.old_user_base
114 super(BuildExtTestCase, self).tearDown()
115
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000116 def test_solaris_enable_shared(self):
117 dist = Distribution({'name': 'xx'})
118 cmd = build_ext(dist)
119 old = sys.platform
120
121 sys.platform = 'sunos' # fooling finalize_options
Tarek Ziadé36797272010-07-22 12:50:05 +0000122 from distutils.sysconfig import _config_vars
123 old_var = _config_vars.get('Py_ENABLE_SHARED')
124 _config_vars['Py_ENABLE_SHARED'] = 1
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000125 try:
126 cmd.ensure_finalized()
127 finally:
128 sys.platform = old
129 if old_var is None:
Tarek Ziadé36797272010-07-22 12:50:05 +0000130 del _config_vars['Py_ENABLE_SHARED']
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000131 else:
Tarek Ziadé36797272010-07-22 12:50:05 +0000132 _config_vars['Py_ENABLE_SHARED'] = old_var
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000133
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000134 # make sure we get some library dirs under solaris
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000135 self.assertTrue(len(cmd.library_dirs) > 0)
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000136
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000137 def test_user_site(self):
138 # site.USER_SITE was introduced in 2.6
139 if sys.version < '2.6':
140 return
141
142 import site
143 dist = Distribution({'name': 'xx'})
144 cmd = build_ext(dist)
145
Tarek Ziadébe720e02009-05-09 11:55:12 +0000146 # making sure the user option is there
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000147 options = [name for name, short, lable in
148 cmd.user_options]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000149 self.assertTrue('user' in options)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000150
151 # setting a value
152 cmd.user = 1
153
154 # setting user based lib and include
155 lib = os.path.join(site.USER_BASE, 'lib')
156 incl = os.path.join(site.USER_BASE, 'include')
157 os.mkdir(lib)
158 os.mkdir(incl)
159
160 # let's run finalize
161 cmd.ensure_finalized()
162
163 # see if include_dirs and library_dirs
164 # were set
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000165 self.assertTrue(lib in cmd.library_dirs)
166 self.assertTrue(lib in cmd.rpath)
167 self.assertTrue(incl in cmd.include_dirs)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000168
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000169 def test_optional_extension(self):
170
171 # this extension will fail, but let's ignore this failure
172 # with the optional argument.
173 modules = [Extension('foo', ['xxx'], optional=False)]
174 dist = Distribution({'name': 'xx', 'ext_modules': modules})
175 cmd = build_ext(dist)
176 cmd.ensure_finalized()
Tarek Ziadé30911292009-03-31 22:50:54 +0000177 self.assertRaises((UnknownFileError, CompileError),
178 cmd.run) # should raise an error
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000179
180 modules = [Extension('foo', ['xxx'], optional=True)]
181 dist = Distribution({'name': 'xx', 'ext_modules': modules})
182 cmd = build_ext(dist)
183 cmd.ensure_finalized()
184 cmd.run() # should pass
185
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000186 def test_finalize_options(self):
187 # Make sure Python's include directories (for Python.h, pyconfig.h,
188 # etc.) are in the include search path.
189 modules = [Extension('foo', ['xxx'], optional=False)]
190 dist = Distribution({'name': 'xx', 'ext_modules': modules})
191 cmd = build_ext(dist)
192 cmd.finalize_options()
193
Tarek Ziadé36797272010-07-22 12:50:05 +0000194 from distutils import sysconfig
195 py_include = sysconfig.get_python_inc()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000196 self.assertTrue(py_include in cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000197
Tarek Ziadé36797272010-07-22 12:50:05 +0000198 plat_py_include = sysconfig.get_python_inc(plat_specific=1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000199 self.assertTrue(plat_py_include in cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000200
201 # make sure cmd.libraries is turned into a list
202 # if it's a string
203 cmd = build_ext(dist)
204 cmd.libraries = 'my_lib'
205 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000206 self.assertEqual(cmd.libraries, ['my_lib'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000207
208 # make sure cmd.library_dirs is turned into a list
209 # if it's a string
210 cmd = build_ext(dist)
211 cmd.library_dirs = 'my_lib_dir'
212 cmd.finalize_options()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000213 self.assertTrue('my_lib_dir' in cmd.library_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000214
215 # make sure rpath is turned into a list
216 # if it's a list of os.pathsep's paths
217 cmd = build_ext(dist)
218 cmd.rpath = os.pathsep.join(['one', 'two'])
219 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000220 self.assertEqual(cmd.rpath, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000221
222 # XXX more tests to perform for win32
223
224 # make sure define is turned into 2-tuples
225 # strings if they are ','-separated strings
226 cmd = build_ext(dist)
227 cmd.define = 'one,two'
228 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000229 self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000230
231 # make sure undef is turned into a list of
232 # strings if they are ','-separated strings
233 cmd = build_ext(dist)
234 cmd.undef = 'one,two'
235 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000236 self.assertEqual(cmd.undef, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000237
238 # make sure swig_opts is turned into a list
239 cmd = build_ext(dist)
240 cmd.swig_opts = None
241 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000242 self.assertEqual(cmd.swig_opts, [])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000243
244 cmd = build_ext(dist)
245 cmd.swig_opts = '1 2'
246 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000247 self.assertEqual(cmd.swig_opts, ['1', '2'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000248
249 def test_check_extensions_list(self):
250 dist = Distribution()
251 cmd = build_ext(dist)
252 cmd.finalize_options()
253
254 #'extensions' option must be a list of Extension instances
Barry Warsaw8cf4eae2010-10-16 01:04:07 +0000255 self.assertRaises(DistutilsSetupError,
256 cmd.check_extensions_list, 'foo')
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000257
258 # each element of 'ext_modules' option must be an
259 # Extension instance or 2-tuple
260 exts = [('bar', 'foo', 'bar'), 'foo']
261 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
262
263 # first element of each tuple in 'ext_modules'
264 # must be the extension name (a string) and match
265 # a python dotted-separated name
266 exts = [('foo-bar', '')]
267 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
268
269 # second element of each tuple in 'ext_modules'
270 # must be a ary (build info)
271 exts = [('foo.bar', '')]
272 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
273
274 # ok this one should pass
275 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
276 'some': 'bar'})]
277 cmd.check_extensions_list(exts)
278 ext = exts[0]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000279 self.assertTrue(isinstance(ext, Extension))
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000280
281 # check_extensions_list adds in ext the values passed
282 # when they are in ('include_dirs', 'library_dirs', 'libraries'
283 # 'extra_objects', 'extra_compile_args', 'extra_link_args')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000284 self.assertEqual(ext.libraries, 'foo')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000285 self.assertTrue(not hasattr(ext, 'some'))
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000286
287 # 'macros' element of build info dict must be 1- or 2-tuple
288 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
289 'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})]
290 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
291
292 exts[0][1]['macros'] = [('1', '2'), ('3',)]
293 cmd.check_extensions_list(exts)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000294 self.assertEqual(exts[0].undef_macros, ['3'])
295 self.assertEqual(exts[0].define_macros, [('1', '2')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000296
297 def test_get_source_files(self):
298 modules = [Extension('foo', ['xxx'], optional=False)]
299 dist = Distribution({'name': 'xx', 'ext_modules': modules})
300 cmd = build_ext(dist)
301 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000302 self.assertEqual(cmd.get_source_files(), ['xxx'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000303
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000304 def test_compiler_option(self):
305 # cmd.compiler is an option and
306 # should not be overriden by a compiler instance
307 # when the command is run
308 dist = Distribution()
309 cmd = build_ext(dist)
310 cmd.compiler = 'unix'
311 cmd.ensure_finalized()
312 cmd.run()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000313 self.assertEqual(cmd.compiler, 'unix')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000314
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000315 def test_get_outputs(self):
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000316 tmp_dir = self.mkdtemp()
317 c_file = os.path.join(tmp_dir, 'foo.c')
Victor Stinner3e2b7172010-11-09 09:32:19 +0000318 self.write_file(c_file, 'void PyInit_foo(void) {}\n')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000319 ext = Extension('foo', [c_file], optional=False)
320 dist = Distribution({'name': 'xx',
321 'ext_modules': [ext]})
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000322 cmd = build_ext(dist)
Barry Warsaw8cf4eae2010-10-16 01:04:07 +0000323 self._fixup_command(cmd)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000324 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000325 self.assertEqual(len(cmd.get_outputs()), 1)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000326
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000327 if os.name == "nt":
328 cmd.debug = sys.executable.endswith("_d.exe")
329
330 cmd.build_lib = os.path.join(self.tmp_dir, 'build')
331 cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
332
333 # issue #5977 : distutils build_ext.get_outputs
334 # returns wrong result with --inplace
Tarek Ziadé4210c6e2009-05-14 20:20:47 +0000335 other_tmp_dir = os.path.realpath(self.mkdtemp())
336 old_wd = os.getcwd()
337 os.chdir(other_tmp_dir)
338 try:
339 cmd.inplace = 1
340 cmd.run()
341 so_file = cmd.get_outputs()[0]
342 finally:
343 os.chdir(old_wd)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000344 self.assertTrue(os.path.exists(so_file))
Barry Warsaw35f3a2c2010-09-03 18:30:30 +0000345 so_ext = sysconfig.get_config_var('SO')
346 self.assertTrue(so_file.endswith(so_ext))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000347 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000348 self.assertEqual(so_dir, other_tmp_dir)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000349
350 cmd.inplace = 0
Tarek Ziadé36797272010-07-22 12:50:05 +0000351 cmd.compiler = None
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000352 cmd.run()
353 so_file = cmd.get_outputs()[0]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000354 self.assertTrue(os.path.exists(so_file))
Barry Warsaw35f3a2c2010-09-03 18:30:30 +0000355 self.assertTrue(so_file.endswith(so_ext))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000356 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000357 self.assertEqual(so_dir, cmd.build_lib)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000358
Tarek Ziadé822eb842009-05-19 16:22:57 +0000359 # inplace = 0, cmd.package = 'bar'
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000360 build_py = cmd.get_finalized_command('build_py')
361 build_py.package_dir = {'': 'bar'}
Tarek Ziadé822eb842009-05-19 16:22:57 +0000362 path = cmd.get_ext_fullpath('foo')
Tarek Ziadé0156f912009-06-29 16:19:22 +0000363 # checking that the last directory is the build_dir
Tarek Ziadé822eb842009-05-19 16:22:57 +0000364 path = os.path.split(path)[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000365 self.assertEqual(path, cmd.build_lib)
Tarek Ziadé822eb842009-05-19 16:22:57 +0000366
367 # inplace = 1, cmd.package = 'bar'
368 cmd.inplace = 1
369 other_tmp_dir = os.path.realpath(self.mkdtemp())
370 old_wd = os.getcwd()
371 os.chdir(other_tmp_dir)
372 try:
373 path = cmd.get_ext_fullpath('foo')
374 finally:
375 os.chdir(old_wd)
376 # checking that the last directory is bar
377 path = os.path.split(path)[0]
378 lastdir = os.path.split(path)[-1]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000379 self.assertEqual(lastdir, 'bar')
Tarek Ziadé822eb842009-05-19 16:22:57 +0000380
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000381 def test_ext_fullpath(self):
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000382 ext = sysconfig.get_config_vars()['SO']
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000383 # building lxml.etree inplace
384 #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
385 #etree_ext = Extension('lxml.etree', [etree_c])
386 #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
387 dist = Distribution()
Tarek Ziadé0156f912009-06-29 16:19:22 +0000388 cmd = build_ext(dist)
389 cmd.inplace = 1
390 cmd.distribution.package_dir = {'': 'src'}
391 cmd.distribution.packages = ['lxml', 'lxml.html']
392 curdir = os.getcwd()
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000393 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000394 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000395 self.assertEqual(wanted, path)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000396
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000397 # building lxml.etree not inplace
398 cmd.inplace = 0
399 cmd.build_lib = os.path.join(curdir, 'tmpdir')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000400 wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000401 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000402 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000403
404 # building twisted.runner.portmap not inplace
405 build_py = cmd.get_finalized_command('build_py')
406 build_py.package_dir = {}
407 cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
408 path = cmd.get_ext_fullpath('twisted.runner.portmap')
409 wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner',
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000410 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000411 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000412
413 # building twisted.runner.portmap inplace
414 cmd.inplace = 1
415 path = cmd.get_ext_fullpath('twisted.runner.portmap')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000416 wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000417 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000418
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200419
420 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
Ned Deilyd13007f2011-06-28 19:43:15 -0700421 def test_deployment_target_default(self):
422 # Issue 9516: Test that, in the absence of the environment variable,
423 # an extension module is compiled with the same deployment target as
424 # the interpreter.
425 self._try_compile_deployment_target('==', None)
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200426
Ned Deilyd13007f2011-06-28 19:43:15 -0700427 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
428 def test_deployment_target_too_low(self):
429 # Issue 9516: Test that an extension module is not allowed to be
430 # compiled with a deployment target less than that of the interpreter.
431 self.assertRaises(DistutilsPlatformError,
432 self._try_compile_deployment_target, '>', '10.1')
433
434 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
435 def test_deployment_target_higher_ok(self):
436 # Issue 9516: Test that an extension module can be compiled with a
437 # deployment target higher than that of the interpreter: the ext
438 # module may depend on some newer OS feature.
439 deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
440 if deptarget:
441 # increment the minor version number (i.e. 10.6 -> 10.7)
442 deptarget = [int(x) for x in deptarget.split('.')]
443 deptarget[-1] += 1
444 deptarget = '.'.join(str(i) for i in deptarget)
445 self._try_compile_deployment_target('<', deptarget)
446
447 def _try_compile_deployment_target(self, operator, target):
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200448 orig_environ = os.environ
449 os.environ = orig_environ.copy()
450 self.addCleanup(setattr, os, 'environ', orig_environ)
451
Ned Deilyd13007f2011-06-28 19:43:15 -0700452 if target is None:
453 if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
454 del os.environ['MACOSX_DEPLOYMENT_TARGET']
455 else:
456 os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200457
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200458 deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')
459
460 with open(deptarget_c, 'w') as fp:
461 fp.write(textwrap.dedent('''\
462 #include <AvailabilityMacros.h>
463
464 int dummy;
465
Ned Deilyd13007f2011-06-28 19:43:15 -0700466 #if TARGET %s MAC_OS_X_VERSION_MIN_REQUIRED
467 #else
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200468 #error "Unexpected target"
469 #endif
470
Ned Deilyd13007f2011-06-28 19:43:15 -0700471 ''' % operator))
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200472
Ned Deilyd13007f2011-06-28 19:43:15 -0700473 # get the deployment target that the interpreter was built with
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200474 target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
475 target = tuple(map(int, target.split('.')))
476 target = '%02d%01d0' % target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200477 deptarget_ext = Extension(
478 'deptarget',
479 [deptarget_c],
480 extra_compile_args=['-DTARGET=%s'%(target,)],
481 )
482 dist = Distribution({
483 'name': 'deptarget',
484 'ext_modules': [deptarget_ext]
485 })
486 dist.package_dir = self.tmp_dir
487 cmd = build_ext(dist)
488 cmd.build_lib = self.tmp_dir
489 cmd.build_temp = self.tmp_dir
490
491 try:
492 old_stdout = sys.stdout
493 if not support.verbose:
494 # silence compiler output
495 sys.stdout = StringIO()
496 try:
497 cmd.ensure_finalized()
498 cmd.run()
499 finally:
500 sys.stdout = old_stdout
501
502 except CompileError:
503 self.fail("Wrong deployment target during compilation")
504
505
Georg Brandlb533e262008-05-25 18:19:30 +0000506def test_suite():
Éric Araujodef15da2011-08-20 06:27:18 +0200507 return unittest.makeSuite(BuildExtTestCase)
Georg Brandlb533e262008-05-25 18:19:30 +0000508
509if __name__ == '__main__':
510 support.run_unittest(test_suite())