blob: 9853abd4c5bf1473c0db5fb4be12c042ffbe7eff [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,
Éric Araujo6e3ad872011-08-21 17:02:07 +020010 copy_xxmodule_c, fixup_build_ext)
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
41 def test_build_ext(self):
Christian Heimes3e7e0692008-11-25 21:21:32 +000042 global ALREADY_TESTED
Éric Araujodef15da2011-08-20 06:27:18 +020043 copy_xxmodule_c(self.tmp_dir)
Georg Brandlb533e262008-05-25 18:19:30 +000044 xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
45 xx_ext = Extension('xx', [xx_c])
46 dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
47 dist.package_dir = self.tmp_dir
48 cmd = build_ext(dist)
Éric Araujo6e3ad872011-08-21 17:02:07 +020049 fixup_build_ext(cmd)
Georg Brandlb533e262008-05-25 18:19:30 +000050 cmd.build_lib = self.tmp_dir
51 cmd.build_temp = self.tmp_dir
52
53 old_stdout = sys.stdout
54 if not support.verbose:
55 # silence compiler output
56 sys.stdout = StringIO()
57 try:
58 cmd.ensure_finalized()
59 cmd.run()
60 finally:
61 sys.stdout = old_stdout
62
Christian Heimes3e7e0692008-11-25 21:21:32 +000063 if ALREADY_TESTED:
Serhiy Storchaka3c02ece2013-12-18 16:41:01 +020064 self.skipTest('Already tested in %s' % ALREADY_TESTED)
Christian Heimes3e7e0692008-11-25 21:21:32 +000065 else:
Serhiy Storchaka3c02ece2013-12-18 16:41:01 +020066 ALREADY_TESTED = type(self).__name__
Christian Heimes3e7e0692008-11-25 21:21:32 +000067
Georg Brandlb533e262008-05-25 18:19:30 +000068 import xx
69
70 for attr in ('error', 'foo', 'new', 'roj'):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000071 self.assertTrue(hasattr(xx, attr))
Georg Brandlb533e262008-05-25 18:19:30 +000072
Ezio Melottib3aedd42010-11-20 19:04:17 +000073 self.assertEqual(xx.foo(2, 5), 7)
74 self.assertEqual(xx.foo(13,15), 28)
75 self.assertEqual(xx.new().demo(), None)
Serhiy Storchaka9d0add02013-01-27 19:47:45 +020076 if support.HAVE_DOCSTRINGS:
77 doc = 'This is a template module just for instruction.'
78 self.assertEqual(xx.__doc__, doc)
Serhiy Storchaka39989152013-11-17 00:17:46 +020079 self.assertIsInstance(xx.Null(), xx.Null)
80 self.assertIsInstance(xx.Str(), xx.Str)
Georg Brandlb533e262008-05-25 18:19:30 +000081
Tarek Ziadé36797272010-07-22 12:50:05 +000082 def tearDown(self):
83 # Get everything back to normal
84 support.unload('xx')
85 sys.path = self.sys_path[0]
86 sys.path[:] = self.sys_path[1]
87 if sys.version > "2.6":
88 import site
89 site.USER_BASE = self.old_user_base
90 from distutils.command import build_ext
91 build_ext.USER_BASE = self.old_user_base
92 super(BuildExtTestCase, self).tearDown()
93
Tarek Ziadé5874ef12009-02-05 22:56:14 +000094 def test_solaris_enable_shared(self):
95 dist = Distribution({'name': 'xx'})
96 cmd = build_ext(dist)
97 old = sys.platform
98
99 sys.platform = 'sunos' # fooling finalize_options
Tarek Ziadé36797272010-07-22 12:50:05 +0000100 from distutils.sysconfig import _config_vars
101 old_var = _config_vars.get('Py_ENABLE_SHARED')
102 _config_vars['Py_ENABLE_SHARED'] = 1
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000103 try:
104 cmd.ensure_finalized()
105 finally:
106 sys.platform = old
107 if old_var is None:
Tarek Ziadé36797272010-07-22 12:50:05 +0000108 del _config_vars['Py_ENABLE_SHARED']
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000109 else:
Tarek Ziadé36797272010-07-22 12:50:05 +0000110 _config_vars['Py_ENABLE_SHARED'] = old_var
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000111
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000112 # make sure we get some library dirs under solaris
Serhiy Storchaka39989152013-11-17 00:17:46 +0200113 self.assertGreater(len(cmd.library_dirs), 0)
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000114
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000115 def test_user_site(self):
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000116 import site
117 dist = Distribution({'name': 'xx'})
118 cmd = build_ext(dist)
119
Tarek Ziadébe720e02009-05-09 11:55:12 +0000120 # making sure the user option is there
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000121 options = [name for name, short, lable in
122 cmd.user_options]
Serhiy Storchaka39989152013-11-17 00:17:46 +0200123 self.assertIn('user', options)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000124
125 # setting a value
126 cmd.user = 1
127
128 # setting user based lib and include
129 lib = os.path.join(site.USER_BASE, 'lib')
130 incl = os.path.join(site.USER_BASE, 'include')
131 os.mkdir(lib)
132 os.mkdir(incl)
133
134 # let's run finalize
135 cmd.ensure_finalized()
136
137 # see if include_dirs and library_dirs
138 # were set
Éric Araujo6e3ad872011-08-21 17:02:07 +0200139 self.assertIn(lib, cmd.library_dirs)
140 self.assertIn(lib, cmd.rpath)
141 self.assertIn(incl, cmd.include_dirs)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000142
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000143 def test_optional_extension(self):
144
145 # this extension will fail, but let's ignore this failure
146 # with the optional argument.
147 modules = [Extension('foo', ['xxx'], optional=False)]
148 dist = Distribution({'name': 'xx', 'ext_modules': modules})
149 cmd = build_ext(dist)
150 cmd.ensure_finalized()
Tarek Ziadé30911292009-03-31 22:50:54 +0000151 self.assertRaises((UnknownFileError, CompileError),
152 cmd.run) # should raise an error
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000153
154 modules = [Extension('foo', ['xxx'], optional=True)]
155 dist = Distribution({'name': 'xx', 'ext_modules': modules})
156 cmd = build_ext(dist)
157 cmd.ensure_finalized()
158 cmd.run() # should pass
159
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000160 def test_finalize_options(self):
161 # Make sure Python's include directories (for Python.h, pyconfig.h,
162 # etc.) are in the include search path.
163 modules = [Extension('foo', ['xxx'], optional=False)]
164 dist = Distribution({'name': 'xx', 'ext_modules': modules})
165 cmd = build_ext(dist)
166 cmd.finalize_options()
167
Tarek Ziadé36797272010-07-22 12:50:05 +0000168 from distutils import sysconfig
169 py_include = sysconfig.get_python_inc()
Serhiy Storchaka39989152013-11-17 00:17:46 +0200170 self.assertIn(py_include, cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000171
Tarek Ziadé36797272010-07-22 12:50:05 +0000172 plat_py_include = sysconfig.get_python_inc(plat_specific=1)
Serhiy Storchaka39989152013-11-17 00:17:46 +0200173 self.assertIn(plat_py_include, cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000174
175 # make sure cmd.libraries is turned into a list
176 # if it's a string
177 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100178 cmd.libraries = 'my_lib, other_lib lastlib'
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000179 cmd.finalize_options()
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100180 self.assertEqual(cmd.libraries, ['my_lib', 'other_lib', 'lastlib'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000181
182 # make sure cmd.library_dirs is turned into a list
183 # if it's a string
184 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100185 cmd.library_dirs = 'my_lib_dir%sother_lib_dir' % os.pathsep
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000186 cmd.finalize_options()
Éric Araujo2a57a362012-02-15 18:12:12 +0100187 self.assertIn('my_lib_dir', cmd.library_dirs)
188 self.assertIn('other_lib_dir', cmd.library_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000189
190 # make sure rpath is turned into a list
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100191 # if it's a string
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000192 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100193 cmd.rpath = 'one%stwo' % os.pathsep
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000194 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000195 self.assertEqual(cmd.rpath, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000196
197 # XXX more tests to perform for win32
198
199 # make sure define is turned into 2-tuples
200 # strings if they are ','-separated strings
201 cmd = build_ext(dist)
202 cmd.define = 'one,two'
203 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000204 self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000205
206 # make sure undef is turned into a list of
207 # strings if they are ','-separated strings
208 cmd = build_ext(dist)
209 cmd.undef = 'one,two'
210 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000211 self.assertEqual(cmd.undef, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000212
213 # make sure swig_opts is turned into a list
214 cmd = build_ext(dist)
215 cmd.swig_opts = None
216 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000217 self.assertEqual(cmd.swig_opts, [])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000218
219 cmd = build_ext(dist)
220 cmd.swig_opts = '1 2'
221 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000222 self.assertEqual(cmd.swig_opts, ['1', '2'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000223
224 def test_check_extensions_list(self):
225 dist = Distribution()
226 cmd = build_ext(dist)
227 cmd.finalize_options()
228
229 #'extensions' option must be a list of Extension instances
Barry Warsaw8cf4eae2010-10-16 01:04:07 +0000230 self.assertRaises(DistutilsSetupError,
231 cmd.check_extensions_list, 'foo')
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000232
233 # each element of 'ext_modules' option must be an
234 # Extension instance or 2-tuple
235 exts = [('bar', 'foo', 'bar'), 'foo']
236 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
237
238 # first element of each tuple in 'ext_modules'
239 # must be the extension name (a string) and match
240 # a python dotted-separated name
241 exts = [('foo-bar', '')]
242 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
243
244 # second element of each tuple in 'ext_modules'
245 # must be a ary (build info)
246 exts = [('foo.bar', '')]
247 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
248
249 # ok this one should pass
250 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
251 'some': 'bar'})]
252 cmd.check_extensions_list(exts)
253 ext = exts[0]
Serhiy Storchaka39989152013-11-17 00:17:46 +0200254 self.assertIsInstance(ext, Extension)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000255
256 # check_extensions_list adds in ext the values passed
257 # when they are in ('include_dirs', 'library_dirs', 'libraries'
258 # 'extra_objects', 'extra_compile_args', 'extra_link_args')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000259 self.assertEqual(ext.libraries, 'foo')
Serhiy Storchaka39989152013-11-17 00:17:46 +0200260 self.assertFalse(hasattr(ext, 'some'))
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000261
262 # 'macros' element of build info dict must be 1- or 2-tuple
263 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
264 'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})]
265 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
266
267 exts[0][1]['macros'] = [('1', '2'), ('3',)]
268 cmd.check_extensions_list(exts)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000269 self.assertEqual(exts[0].undef_macros, ['3'])
270 self.assertEqual(exts[0].define_macros, [('1', '2')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000271
272 def test_get_source_files(self):
273 modules = [Extension('foo', ['xxx'], optional=False)]
274 dist = Distribution({'name': 'xx', 'ext_modules': modules})
275 cmd = build_ext(dist)
276 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000277 self.assertEqual(cmd.get_source_files(), ['xxx'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000278
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000279 def test_compiler_option(self):
280 # cmd.compiler is an option and
281 # should not be overriden by a compiler instance
282 # when the command is run
283 dist = Distribution()
284 cmd = build_ext(dist)
285 cmd.compiler = 'unix'
286 cmd.ensure_finalized()
287 cmd.run()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000288 self.assertEqual(cmd.compiler, 'unix')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000289
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000290 def test_get_outputs(self):
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000291 tmp_dir = self.mkdtemp()
292 c_file = os.path.join(tmp_dir, 'foo.c')
Victor Stinner3e2b7172010-11-09 09:32:19 +0000293 self.write_file(c_file, 'void PyInit_foo(void) {}\n')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000294 ext = Extension('foo', [c_file], optional=False)
295 dist = Distribution({'name': 'xx',
296 'ext_modules': [ext]})
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000297 cmd = build_ext(dist)
Éric Araujo6e3ad872011-08-21 17:02:07 +0200298 fixup_build_ext(cmd)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000299 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000300 self.assertEqual(len(cmd.get_outputs()), 1)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000301
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000302 cmd.build_lib = os.path.join(self.tmp_dir, 'build')
303 cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
304
305 # issue #5977 : distutils build_ext.get_outputs
306 # returns wrong result with --inplace
Tarek Ziadé4210c6e2009-05-14 20:20:47 +0000307 other_tmp_dir = os.path.realpath(self.mkdtemp())
308 old_wd = os.getcwd()
309 os.chdir(other_tmp_dir)
310 try:
311 cmd.inplace = 1
312 cmd.run()
313 so_file = cmd.get_outputs()[0]
314 finally:
315 os.chdir(old_wd)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000316 self.assertTrue(os.path.exists(so_file))
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700317 ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
318 self.assertTrue(so_file.endswith(ext_suffix))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000319 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000320 self.assertEqual(so_dir, other_tmp_dir)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000321
322 cmd.inplace = 0
Tarek Ziadé36797272010-07-22 12:50:05 +0000323 cmd.compiler = None
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000324 cmd.run()
325 so_file = cmd.get_outputs()[0]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000326 self.assertTrue(os.path.exists(so_file))
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700327 self.assertTrue(so_file.endswith(ext_suffix))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000328 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000329 self.assertEqual(so_dir, cmd.build_lib)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000330
Tarek Ziadé822eb842009-05-19 16:22:57 +0000331 # inplace = 0, cmd.package = 'bar'
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000332 build_py = cmd.get_finalized_command('build_py')
333 build_py.package_dir = {'': 'bar'}
Tarek Ziadé822eb842009-05-19 16:22:57 +0000334 path = cmd.get_ext_fullpath('foo')
Tarek Ziadé0156f912009-06-29 16:19:22 +0000335 # checking that the last directory is the build_dir
Tarek Ziadé822eb842009-05-19 16:22:57 +0000336 path = os.path.split(path)[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000337 self.assertEqual(path, cmd.build_lib)
Tarek Ziadé822eb842009-05-19 16:22:57 +0000338
339 # inplace = 1, cmd.package = 'bar'
340 cmd.inplace = 1
341 other_tmp_dir = os.path.realpath(self.mkdtemp())
342 old_wd = os.getcwd()
343 os.chdir(other_tmp_dir)
344 try:
345 path = cmd.get_ext_fullpath('foo')
346 finally:
347 os.chdir(old_wd)
348 # checking that the last directory is bar
349 path = os.path.split(path)[0]
350 lastdir = os.path.split(path)[-1]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000351 self.assertEqual(lastdir, 'bar')
Tarek Ziadé822eb842009-05-19 16:22:57 +0000352
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000353 def test_ext_fullpath(self):
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700354 ext = sysconfig.get_config_var('EXT_SUFFIX')
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000355 # building lxml.etree inplace
356 #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
357 #etree_ext = Extension('lxml.etree', [etree_c])
358 #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
359 dist = Distribution()
Tarek Ziadé0156f912009-06-29 16:19:22 +0000360 cmd = build_ext(dist)
361 cmd.inplace = 1
362 cmd.distribution.package_dir = {'': 'src'}
363 cmd.distribution.packages = ['lxml', 'lxml.html']
364 curdir = os.getcwd()
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000365 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000366 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000367 self.assertEqual(wanted, path)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000368
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000369 # building lxml.etree not inplace
370 cmd.inplace = 0
371 cmd.build_lib = os.path.join(curdir, 'tmpdir')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000372 wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000373 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000374 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000375
376 # building twisted.runner.portmap not inplace
377 build_py = cmd.get_finalized_command('build_py')
378 build_py.package_dir = {}
379 cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
380 path = cmd.get_ext_fullpath('twisted.runner.portmap')
381 wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner',
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000382 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000383 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000384
385 # building twisted.runner.portmap inplace
386 cmd.inplace = 1
387 path = cmd.get_ext_fullpath('twisted.runner.portmap')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000388 wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000389 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000390
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200391
392 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
Ned Deilyd13007f2011-06-28 19:43:15 -0700393 def test_deployment_target_default(self):
394 # Issue 9516: Test that, in the absence of the environment variable,
395 # an extension module is compiled with the same deployment target as
396 # the interpreter.
397 self._try_compile_deployment_target('==', None)
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200398
Ned Deilyd13007f2011-06-28 19:43:15 -0700399 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
400 def test_deployment_target_too_low(self):
401 # Issue 9516: Test that an extension module is not allowed to be
402 # compiled with a deployment target less than that of the interpreter.
403 self.assertRaises(DistutilsPlatformError,
404 self._try_compile_deployment_target, '>', '10.1')
405
406 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
407 def test_deployment_target_higher_ok(self):
408 # Issue 9516: Test that an extension module can be compiled with a
409 # deployment target higher than that of the interpreter: the ext
410 # module may depend on some newer OS feature.
411 deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
412 if deptarget:
413 # increment the minor version number (i.e. 10.6 -> 10.7)
414 deptarget = [int(x) for x in deptarget.split('.')]
415 deptarget[-1] += 1
416 deptarget = '.'.join(str(i) for i in deptarget)
417 self._try_compile_deployment_target('<', deptarget)
418
419 def _try_compile_deployment_target(self, operator, target):
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200420 orig_environ = os.environ
421 os.environ = orig_environ.copy()
422 self.addCleanup(setattr, os, 'environ', orig_environ)
423
Ned Deilyd13007f2011-06-28 19:43:15 -0700424 if target is None:
425 if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
426 del os.environ['MACOSX_DEPLOYMENT_TARGET']
427 else:
428 os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200429
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200430 deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')
431
432 with open(deptarget_c, 'w') as fp:
433 fp.write(textwrap.dedent('''\
434 #include <AvailabilityMacros.h>
435
436 int dummy;
437
Ned Deilyd13007f2011-06-28 19:43:15 -0700438 #if TARGET %s MAC_OS_X_VERSION_MIN_REQUIRED
439 #else
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200440 #error "Unexpected target"
441 #endif
442
Ned Deilyd13007f2011-06-28 19:43:15 -0700443 ''' % operator))
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200444
Ned Deilyd13007f2011-06-28 19:43:15 -0700445 # get the deployment target that the interpreter was built with
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200446 target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
447 target = tuple(map(int, target.split('.')))
448 target = '%02d%01d0' % target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200449 deptarget_ext = Extension(
450 'deptarget',
451 [deptarget_c],
452 extra_compile_args=['-DTARGET=%s'%(target,)],
453 )
454 dist = Distribution({
455 'name': 'deptarget',
456 'ext_modules': [deptarget_ext]
457 })
458 dist.package_dir = self.tmp_dir
459 cmd = build_ext(dist)
460 cmd.build_lib = self.tmp_dir
461 cmd.build_temp = self.tmp_dir
462
463 try:
464 old_stdout = sys.stdout
465 if not support.verbose:
466 # silence compiler output
467 sys.stdout = StringIO()
468 try:
469 cmd.ensure_finalized()
470 cmd.run()
471 finally:
472 sys.stdout = old_stdout
473
474 except CompileError:
475 self.fail("Wrong deployment target during compilation")
476
477
Georg Brandlb533e262008-05-25 18:19:30 +0000478def test_suite():
Éric Araujodef15da2011-08-20 06:27:18 +0200479 return unittest.makeSuite(BuildExtTestCase)
Georg Brandlb533e262008-05-25 18:19:30 +0000480
481if __name__ == '__main__':
482 support.run_unittest(test_suite())