blob: b9f407f401701e55109efda8e40d516fcad26b06 [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)
Benjamin Petersondf0eb952014-09-06 17:24:12 -040034 import site
35 self.old_user_base = site.USER_BASE
36 site.USER_BASE = self.mkdtemp()
37 from distutils.command import build_ext
38 build_ext.USER_BASE = site.USER_BASE
Georg Brandlb533e262008-05-25 18:19:30 +000039
40 def test_build_ext(self):
Christian Heimes3e7e0692008-11-25 21:21:32 +000041 global ALREADY_TESTED
Éric Araujodef15da2011-08-20 06:27:18 +020042 copy_xxmodule_c(self.tmp_dir)
Georg Brandlb533e262008-05-25 18:19:30 +000043 xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
44 xx_ext = Extension('xx', [xx_c])
45 dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
46 dist.package_dir = self.tmp_dir
47 cmd = build_ext(dist)
Éric Araujo6e3ad872011-08-21 17:02:07 +020048 fixup_build_ext(cmd)
Georg Brandlb533e262008-05-25 18:19:30 +000049 cmd.build_lib = self.tmp_dir
50 cmd.build_temp = self.tmp_dir
51
52 old_stdout = sys.stdout
53 if not support.verbose:
54 # silence compiler output
55 sys.stdout = StringIO()
56 try:
57 cmd.ensure_finalized()
58 cmd.run()
59 finally:
60 sys.stdout = old_stdout
61
Christian Heimes3e7e0692008-11-25 21:21:32 +000062 if ALREADY_TESTED:
Serhiy Storchaka3c02ece2013-12-18 16:41:01 +020063 self.skipTest('Already tested in %s' % ALREADY_TESTED)
Christian Heimes3e7e0692008-11-25 21:21:32 +000064 else:
Serhiy Storchaka3c02ece2013-12-18 16:41:01 +020065 ALREADY_TESTED = type(self).__name__
Christian Heimes3e7e0692008-11-25 21:21:32 +000066
Georg Brandlb533e262008-05-25 18:19:30 +000067 import xx
68
69 for attr in ('error', 'foo', 'new', 'roj'):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000070 self.assertTrue(hasattr(xx, attr))
Georg Brandlb533e262008-05-25 18:19:30 +000071
Ezio Melottib3aedd42010-11-20 19:04:17 +000072 self.assertEqual(xx.foo(2, 5), 7)
73 self.assertEqual(xx.foo(13,15), 28)
74 self.assertEqual(xx.new().demo(), None)
Serhiy Storchaka9d0add02013-01-27 19:47:45 +020075 if support.HAVE_DOCSTRINGS:
76 doc = 'This is a template module just for instruction.'
77 self.assertEqual(xx.__doc__, doc)
Serhiy Storchaka39989152013-11-17 00:17:46 +020078 self.assertIsInstance(xx.Null(), xx.Null)
79 self.assertIsInstance(xx.Str(), xx.Str)
Georg Brandlb533e262008-05-25 18:19:30 +000080
Tarek Ziadé36797272010-07-22 12:50:05 +000081 def tearDown(self):
82 # Get everything back to normal
83 support.unload('xx')
84 sys.path = self.sys_path[0]
85 sys.path[:] = self.sys_path[1]
Benjamin Petersondf0eb952014-09-06 17:24:12 -040086 import site
87 site.USER_BASE = self.old_user_base
88 from distutils.command import build_ext
89 build_ext.USER_BASE = self.old_user_base
Tarek Ziadé36797272010-07-22 12:50:05 +000090 super(BuildExtTestCase, self).tearDown()
91
Tarek Ziadé5874ef12009-02-05 22:56:14 +000092 def test_solaris_enable_shared(self):
93 dist = Distribution({'name': 'xx'})
94 cmd = build_ext(dist)
95 old = sys.platform
96
97 sys.platform = 'sunos' # fooling finalize_options
Tarek Ziadé36797272010-07-22 12:50:05 +000098 from distutils.sysconfig import _config_vars
99 old_var = _config_vars.get('Py_ENABLE_SHARED')
100 _config_vars['Py_ENABLE_SHARED'] = 1
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000101 try:
102 cmd.ensure_finalized()
103 finally:
104 sys.platform = old
105 if old_var is None:
Tarek Ziadé36797272010-07-22 12:50:05 +0000106 del _config_vars['Py_ENABLE_SHARED']
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000107 else:
Tarek Ziadé36797272010-07-22 12:50:05 +0000108 _config_vars['Py_ENABLE_SHARED'] = old_var
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000109
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000110 # make sure we get some library dirs under solaris
Serhiy Storchaka39989152013-11-17 00:17:46 +0200111 self.assertGreater(len(cmd.library_dirs), 0)
Tarek Ziadé5874ef12009-02-05 22:56:14 +0000112
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000113 def test_user_site(self):
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000114 import site
115 dist = Distribution({'name': 'xx'})
116 cmd = build_ext(dist)
117
Tarek Ziadébe720e02009-05-09 11:55:12 +0000118 # making sure the user option is there
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000119 options = [name for name, short, lable in
120 cmd.user_options]
Serhiy Storchaka39989152013-11-17 00:17:46 +0200121 self.assertIn('user', options)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000122
123 # setting a value
124 cmd.user = 1
125
126 # setting user based lib and include
127 lib = os.path.join(site.USER_BASE, 'lib')
128 incl = os.path.join(site.USER_BASE, 'include')
129 os.mkdir(lib)
130 os.mkdir(incl)
131
132 # let's run finalize
133 cmd.ensure_finalized()
134
135 # see if include_dirs and library_dirs
136 # were set
Éric Araujo6e3ad872011-08-21 17:02:07 +0200137 self.assertIn(lib, cmd.library_dirs)
138 self.assertIn(lib, cmd.rpath)
139 self.assertIn(incl, cmd.include_dirs)
Tarek Ziadé38e3d512009-02-27 12:58:56 +0000140
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000141 def test_optional_extension(self):
142
143 # this extension will fail, but let's ignore this failure
144 # with the optional argument.
145 modules = [Extension('foo', ['xxx'], optional=False)]
146 dist = Distribution({'name': 'xx', 'ext_modules': modules})
147 cmd = build_ext(dist)
148 cmd.ensure_finalized()
Tarek Ziadé30911292009-03-31 22:50:54 +0000149 self.assertRaises((UnknownFileError, CompileError),
150 cmd.run) # should raise an error
Tarek Ziadéb2e36f12009-03-31 22:37:55 +0000151
152 modules = [Extension('foo', ['xxx'], optional=True)]
153 dist = Distribution({'name': 'xx', 'ext_modules': modules})
154 cmd = build_ext(dist)
155 cmd.ensure_finalized()
156 cmd.run() # should pass
157
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000158 def test_finalize_options(self):
159 # Make sure Python's include directories (for Python.h, pyconfig.h,
160 # etc.) are in the include search path.
161 modules = [Extension('foo', ['xxx'], optional=False)]
162 dist = Distribution({'name': 'xx', 'ext_modules': modules})
163 cmd = build_ext(dist)
164 cmd.finalize_options()
165
Tarek Ziadé36797272010-07-22 12:50:05 +0000166 from distutils import sysconfig
167 py_include = sysconfig.get_python_inc()
Serhiy Storchaka39989152013-11-17 00:17:46 +0200168 self.assertIn(py_include, cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000169
Tarek Ziadé36797272010-07-22 12:50:05 +0000170 plat_py_include = sysconfig.get_python_inc(plat_specific=1)
Serhiy Storchaka39989152013-11-17 00:17:46 +0200171 self.assertIn(plat_py_include, cmd.include_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000172
173 # make sure cmd.libraries is turned into a list
174 # if it's a string
175 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100176 cmd.libraries = 'my_lib, other_lib lastlib'
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000177 cmd.finalize_options()
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100178 self.assertEqual(cmd.libraries, ['my_lib', 'other_lib', 'lastlib'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000179
180 # make sure cmd.library_dirs is turned into a list
181 # if it's a string
182 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100183 cmd.library_dirs = 'my_lib_dir%sother_lib_dir' % os.pathsep
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000184 cmd.finalize_options()
Éric Araujo2a57a362012-02-15 18:12:12 +0100185 self.assertIn('my_lib_dir', cmd.library_dirs)
186 self.assertIn('other_lib_dir', cmd.library_dirs)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000187
188 # make sure rpath is turned into a list
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100189 # if it's a string
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000190 cmd = build_ext(dist)
Éric Araujob2f5c0a2012-02-15 16:44:37 +0100191 cmd.rpath = 'one%stwo' % os.pathsep
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000192 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000193 self.assertEqual(cmd.rpath, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000194
195 # XXX more tests to perform for win32
196
197 # make sure define is turned into 2-tuples
198 # strings if they are ','-separated strings
199 cmd = build_ext(dist)
200 cmd.define = 'one,two'
201 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000202 self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000203
204 # make sure undef is turned into a list of
205 # strings if they are ','-separated strings
206 cmd = build_ext(dist)
207 cmd.undef = 'one,two'
208 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000209 self.assertEqual(cmd.undef, ['one', 'two'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000210
211 # make sure swig_opts is turned into a list
212 cmd = build_ext(dist)
213 cmd.swig_opts = None
214 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000215 self.assertEqual(cmd.swig_opts, [])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000216
217 cmd = build_ext(dist)
218 cmd.swig_opts = '1 2'
219 cmd.finalize_options()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000220 self.assertEqual(cmd.swig_opts, ['1', '2'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000221
222 def test_check_extensions_list(self):
223 dist = Distribution()
224 cmd = build_ext(dist)
225 cmd.finalize_options()
226
227 #'extensions' option must be a list of Extension instances
Barry Warsaw8cf4eae2010-10-16 01:04:07 +0000228 self.assertRaises(DistutilsSetupError,
229 cmd.check_extensions_list, 'foo')
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000230
231 # each element of 'ext_modules' option must be an
232 # Extension instance or 2-tuple
233 exts = [('bar', 'foo', 'bar'), 'foo']
234 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
235
236 # first element of each tuple in 'ext_modules'
237 # must be the extension name (a string) and match
238 # a python dotted-separated name
239 exts = [('foo-bar', '')]
240 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
241
242 # second element of each tuple in 'ext_modules'
243 # must be a ary (build info)
244 exts = [('foo.bar', '')]
245 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
246
247 # ok this one should pass
248 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
249 'some': 'bar'})]
250 cmd.check_extensions_list(exts)
251 ext = exts[0]
Serhiy Storchaka39989152013-11-17 00:17:46 +0200252 self.assertIsInstance(ext, Extension)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000253
254 # check_extensions_list adds in ext the values passed
255 # when they are in ('include_dirs', 'library_dirs', 'libraries'
256 # 'extra_objects', 'extra_compile_args', 'extra_link_args')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000257 self.assertEqual(ext.libraries, 'foo')
Serhiy Storchaka39989152013-11-17 00:17:46 +0200258 self.assertFalse(hasattr(ext, 'some'))
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000259
260 # 'macros' element of build info dict must be 1- or 2-tuple
261 exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
262 'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})]
263 self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
264
265 exts[0][1]['macros'] = [('1', '2'), ('3',)]
266 cmd.check_extensions_list(exts)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000267 self.assertEqual(exts[0].undef_macros, ['3'])
268 self.assertEqual(exts[0].define_macros, [('1', '2')])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000269
270 def test_get_source_files(self):
271 modules = [Extension('foo', ['xxx'], optional=False)]
272 dist = Distribution({'name': 'xx', 'ext_modules': modules})
273 cmd = build_ext(dist)
274 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000275 self.assertEqual(cmd.get_source_files(), ['xxx'])
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000276
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000277 def test_compiler_option(self):
278 # cmd.compiler is an option and
279 # should not be overriden by a compiler instance
280 # when the command is run
281 dist = Distribution()
282 cmd = build_ext(dist)
283 cmd.compiler = 'unix'
284 cmd.ensure_finalized()
285 cmd.run()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000286 self.assertEqual(cmd.compiler, 'unix')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000287
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000288 def test_get_outputs(self):
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000289 tmp_dir = self.mkdtemp()
290 c_file = os.path.join(tmp_dir, 'foo.c')
Victor Stinner3e2b7172010-11-09 09:32:19 +0000291 self.write_file(c_file, 'void PyInit_foo(void) {}\n')
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000292 ext = Extension('foo', [c_file], optional=False)
293 dist = Distribution({'name': 'xx',
294 'ext_modules': [ext]})
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000295 cmd = build_ext(dist)
Éric Araujo6e3ad872011-08-21 17:02:07 +0200296 fixup_build_ext(cmd)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000297 cmd.ensure_finalized()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000298 self.assertEqual(len(cmd.get_outputs()), 1)
Tarek Ziadé06fbee12009-05-10 10:34:01 +0000299
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000300 cmd.build_lib = os.path.join(self.tmp_dir, 'build')
301 cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
302
303 # issue #5977 : distutils build_ext.get_outputs
304 # returns wrong result with --inplace
Tarek Ziadé4210c6e2009-05-14 20:20:47 +0000305 other_tmp_dir = os.path.realpath(self.mkdtemp())
306 old_wd = os.getcwd()
307 os.chdir(other_tmp_dir)
308 try:
309 cmd.inplace = 1
310 cmd.run()
311 so_file = cmd.get_outputs()[0]
312 finally:
313 os.chdir(old_wd)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000314 self.assertTrue(os.path.exists(so_file))
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700315 ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
316 self.assertTrue(so_file.endswith(ext_suffix))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000317 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000318 self.assertEqual(so_dir, other_tmp_dir)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000319
320 cmd.inplace = 0
Tarek Ziadé36797272010-07-22 12:50:05 +0000321 cmd.compiler = None
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000322 cmd.run()
323 so_file = cmd.get_outputs()[0]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000324 self.assertTrue(os.path.exists(so_file))
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700325 self.assertTrue(so_file.endswith(ext_suffix))
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000326 so_dir = os.path.dirname(so_file)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000327 self.assertEqual(so_dir, cmd.build_lib)
Tarek Ziadéff0e5002009-05-12 17:14:01 +0000328
Tarek Ziadé822eb842009-05-19 16:22:57 +0000329 # inplace = 0, cmd.package = 'bar'
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000330 build_py = cmd.get_finalized_command('build_py')
331 build_py.package_dir = {'': 'bar'}
Tarek Ziadé822eb842009-05-19 16:22:57 +0000332 path = cmd.get_ext_fullpath('foo')
Tarek Ziadé0156f912009-06-29 16:19:22 +0000333 # checking that the last directory is the build_dir
Tarek Ziadé822eb842009-05-19 16:22:57 +0000334 path = os.path.split(path)[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000335 self.assertEqual(path, cmd.build_lib)
Tarek Ziadé822eb842009-05-19 16:22:57 +0000336
337 # inplace = 1, cmd.package = 'bar'
338 cmd.inplace = 1
339 other_tmp_dir = os.path.realpath(self.mkdtemp())
340 old_wd = os.getcwd()
341 os.chdir(other_tmp_dir)
342 try:
343 path = cmd.get_ext_fullpath('foo')
344 finally:
345 os.chdir(old_wd)
346 # checking that the last directory is bar
347 path = os.path.split(path)[0]
348 lastdir = os.path.split(path)[-1]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000349 self.assertEqual(lastdir, 'bar')
Tarek Ziadé822eb842009-05-19 16:22:57 +0000350
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000351 def test_ext_fullpath(self):
doko@ubuntu.comd5537d02013-03-21 13:21:49 -0700352 ext = sysconfig.get_config_var('EXT_SUFFIX')
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000353 # building lxml.etree inplace
354 #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
355 #etree_ext = Extension('lxml.etree', [etree_c])
356 #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
357 dist = Distribution()
Tarek Ziadé0156f912009-06-29 16:19:22 +0000358 cmd = build_ext(dist)
359 cmd.inplace = 1
360 cmd.distribution.package_dir = {'': 'src'}
361 cmd.distribution.packages = ['lxml', 'lxml.html']
362 curdir = os.getcwd()
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000363 wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000364 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000365 self.assertEqual(wanted, path)
Tarek Ziadé0156f912009-06-29 16:19:22 +0000366
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000367 # building lxml.etree not inplace
368 cmd.inplace = 0
369 cmd.build_lib = os.path.join(curdir, 'tmpdir')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000370 wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000371 path = cmd.get_ext_fullpath('lxml.etree')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000372 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000373
374 # building twisted.runner.portmap not inplace
375 build_py = cmd.get_finalized_command('build_py')
376 build_py.package_dir = {}
377 cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
378 path = cmd.get_ext_fullpath('twisted.runner.portmap')
379 wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner',
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000380 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000381 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000382
383 # building twisted.runner.portmap inplace
384 cmd.inplace = 1
385 path = cmd.get_ext_fullpath('twisted.runner.portmap')
Tarek Ziadéb7815e32009-07-10 09:14:31 +0000386 wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000387 self.assertEqual(wanted, path)
Tarek Ziadée10d6de2009-07-03 08:33:28 +0000388
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200389
390 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
Ned Deilyd13007f2011-06-28 19:43:15 -0700391 def test_deployment_target_default(self):
392 # Issue 9516: Test that, in the absence of the environment variable,
393 # an extension module is compiled with the same deployment target as
394 # the interpreter.
395 self._try_compile_deployment_target('==', None)
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200396
Ned Deilyd13007f2011-06-28 19:43:15 -0700397 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
398 def test_deployment_target_too_low(self):
399 # Issue 9516: Test that an extension module is not allowed to be
400 # compiled with a deployment target less than that of the interpreter.
401 self.assertRaises(DistutilsPlatformError,
402 self._try_compile_deployment_target, '>', '10.1')
403
404 @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
405 def test_deployment_target_higher_ok(self):
406 # Issue 9516: Test that an extension module can be compiled with a
407 # deployment target higher than that of the interpreter: the ext
408 # module may depend on some newer OS feature.
409 deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
410 if deptarget:
411 # increment the minor version number (i.e. 10.6 -> 10.7)
412 deptarget = [int(x) for x in deptarget.split('.')]
413 deptarget[-1] += 1
414 deptarget = '.'.join(str(i) for i in deptarget)
415 self._try_compile_deployment_target('<', deptarget)
416
417 def _try_compile_deployment_target(self, operator, target):
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200418 orig_environ = os.environ
419 os.environ = orig_environ.copy()
420 self.addCleanup(setattr, os, 'environ', orig_environ)
421
Ned Deilyd13007f2011-06-28 19:43:15 -0700422 if target is None:
423 if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
424 del os.environ['MACOSX_DEPLOYMENT_TARGET']
425 else:
426 os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200427
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200428 deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')
429
430 with open(deptarget_c, 'w') as fp:
431 fp.write(textwrap.dedent('''\
432 #include <AvailabilityMacros.h>
433
434 int dummy;
435
Ned Deilyd13007f2011-06-28 19:43:15 -0700436 #if TARGET %s MAC_OS_X_VERSION_MIN_REQUIRED
437 #else
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200438 #error "Unexpected target"
439 #endif
440
Ned Deilyd13007f2011-06-28 19:43:15 -0700441 ''' % operator))
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200442
Ned Deilyd13007f2011-06-28 19:43:15 -0700443 # get the deployment target that the interpreter was built with
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200444 target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
Ned Deily04cdfa12014-06-25 13:36:14 -0700445 target = tuple(map(int, target.split('.')[0:2]))
446 # format the target value as defined in the Apple
447 # Availability Macros. We can't use the macro names since
448 # at least one value we test with will not exist yet.
449 if target[1] < 10:
450 # for 10.1 through 10.9.x -> "10n0"
451 target = '%02d%01d0' % target
452 else:
453 # for 10.10 and beyond -> "10nn00"
454 target = '%02d%02d00' % target
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200455 deptarget_ext = Extension(
456 'deptarget',
457 [deptarget_c],
458 extra_compile_args=['-DTARGET=%s'%(target,)],
459 )
460 dist = Distribution({
461 'name': 'deptarget',
462 'ext_modules': [deptarget_ext]
463 })
464 dist.package_dir = self.tmp_dir
465 cmd = build_ext(dist)
466 cmd.build_lib = self.tmp_dir
467 cmd.build_temp = self.tmp_dir
468
469 try:
470 old_stdout = sys.stdout
471 if not support.verbose:
472 # silence compiler output
473 sys.stdout = StringIO()
474 try:
475 cmd.ensure_finalized()
476 cmd.run()
477 finally:
478 sys.stdout = old_stdout
479
480 except CompileError:
481 self.fail("Wrong deployment target during compilation")
482
483
Georg Brandlb533e262008-05-25 18:19:30 +0000484def test_suite():
Éric Araujodef15da2011-08-20 06:27:18 +0200485 return unittest.makeSuite(BuildExtTestCase)
Georg Brandlb533e262008-05-25 18:19:30 +0000486
487if __name__ == '__main__':
488 support.run_unittest(test_suite())