188e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlimport sys
288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlimport os
388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlfrom StringIO import StringIO
4a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussorenimport textwrap
588e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
688e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlfrom distutils.core import Extension, Distribution
788e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlfrom distutils.command.build_ext import build_ext
8b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadéfrom distutils import sysconfig
91369900619d943d05342e7b781f1f3fb45ece4c9Tarek Ziadéfrom distutils.tests import support
10053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deilyfrom distutils.errors import (DistutilsSetupError, CompileError,
11053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily                              DistutilsPlatformError)
1288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
1388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlimport unittest
1488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlfrom test import test_support
1588e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
166f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé# http://bugs.python.org/issue4373
176f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé# Don't load the xx module more than once.
186f1d93149505c5b69578549a440175c5b32942b7Tarek ZiadéALREADY_TESTED = False
196f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé
20a52f1c62eb8cce9fb7f78687b854d1d8c4dbe39fNeil Schemenauer
219e47ce49a06075adbc391e04b4457707fa3892a7Tarek Ziadéclass BuildExtTestCase(support.TempdirManager,
229e47ce49a06075adbc391e04b4457707fa3892a7Tarek Ziadé                       support.LoggingSilencer,
239e47ce49a06075adbc391e04b4457707fa3892a7Tarek Ziadé                       unittest.TestCase):
2488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl    def setUp(self):
25dda92f7f02dbc0de94112599129d9d93192278d9Tarek Ziadé        super(BuildExtTestCase, self).setUp()
2604612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        self.tmp_dir = self.mkdtemp()
2704612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        self.xx_created = False
2804612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        sys.path.append(self.tmp_dir)
2904612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        self.addCleanup(sys.path.remove, self.tmp_dir)
30c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        if sys.version > "2.6":
31c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo            import site
32c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo            self.old_user_base = site.USER_BASE
33c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo            site.USER_BASE = self.mkdtemp()
34c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo            from distutils.command import build_ext
35c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo            build_ext.USER_BASE = site.USER_BASE
36ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé
37ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé    def tearDown(self):
3804612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        if self.xx_created:
39ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé            test_support.unload('xx')
40ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé            # XXX on Windows the test leaves a directory
41ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé            # with xx module in TEMP
42ef253ac84e6fd11770ff78c56015a0e61c991fc4Tarek Ziadé        super(BuildExtTestCase, self).tearDown()
4388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
4488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl    def test_build_ext(self):
456f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé        global ALREADY_TESTED
4604612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        support.copy_xxmodule_c(self.tmp_dir)
4704612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        self.xx_created = True
4888e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
4988e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        xx_ext = Extension('xx', [xx_c])
5088e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
5188e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        dist.package_dir = self.tmp_dir
5288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        cmd = build_ext(dist)
5304612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        support.fixup_build_ext(cmd)
5488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        cmd.build_lib = self.tmp_dir
5588e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        cmd.build_temp = self.tmp_dir
5688e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
5788e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        old_stdout = sys.stdout
5888e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        if not test_support.verbose:
5988e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl            # silence compiler output
6088e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl            sys.stdout = StringIO()
6188e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        try:
6288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl            cmd.ensure_finalized()
6388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl            cmd.run()
6488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        finally:
6588e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl            sys.stdout = old_stdout
6688e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
676f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé        if ALREADY_TESTED:
6857bc6da7c4327aa870fbf5292c1b05a9ac3bfe19Serhiy Storchaka            self.skipTest('Already tested in %s' % ALREADY_TESTED)
696f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé        else:
7057bc6da7c4327aa870fbf5292c1b05a9ac3bfe19Serhiy Storchaka            ALREADY_TESTED = type(self).__name__
716f1d93149505c5b69578549a440175c5b32942b7Tarek Ziadé
7288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        import xx
7388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
7488e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl        for attr in ('error', 'foo', 'new', 'roj'):
752623a37852153363335956afab010cb0beb7e74eEzio Melotti            self.assertTrue(hasattr(xx, attr))
7688e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
772623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(xx.foo(2, 5), 7)
782623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(xx.foo(13,15), 28)
792623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(xx.new().demo(), None)
8072121c6c302d0e177d3f738f51685e0664343cccSerhiy Storchaka        if test_support.HAVE_DOCSTRINGS:
8172121c6c302d0e177d3f738f51685e0664343cccSerhiy Storchaka            doc = 'This is a template module just for instruction.'
8272121c6c302d0e177d3f738f51685e0664343cccSerhiy Storchaka            self.assertEqual(xx.__doc__, doc)
8325a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertIsInstance(xx.Null(), xx.Null)
8425a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertIsInstance(xx.Str(), xx.Str)
8588e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
860d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé    def test_solaris_enable_shared(self):
870d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        dist = Distribution({'name': 'xx'})
880d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        cmd = build_ext(dist)
890d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        old = sys.platform
900d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé
910d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        sys.platform = 'sunos' # fooling finalize_options
92b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        from distutils.sysconfig import  _config_vars
93b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        old_var = _config_vars.get('Py_ENABLE_SHARED')
94b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        _config_vars['Py_ENABLE_SHARED'] = 1
950d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        try:
960d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé            cmd.ensure_finalized()
970d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé        finally:
980d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé            sys.platform = old
990d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé            if old_var is None:
100b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé                del _config_vars['Py_ENABLE_SHARED']
1010d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé            else:
102b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé                _config_vars['Py_ENABLE_SHARED'] = old_var
1030d4fd3493eb95a49ac0dee5c8607b1426432ab83Tarek Ziadé
104972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        # make sure we get some library dirs under solaris
10525a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertGreater(len(cmd.library_dirs), 0)
1069e47ce49a06075adbc391e04b4457707fa3892a7Tarek Ziadé
10757bc6da7c4327aa870fbf5292c1b05a9ac3bfe19Serhiy Storchaka    @unittest.skipIf(sys.version < '2.6',
10857bc6da7c4327aa870fbf5292c1b05a9ac3bfe19Serhiy Storchaka                     'site.USER_SITE was introduced in 2.6')
109c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo    def test_user_site(self):
110c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        import site
111c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        dist = Distribution({'name': 'xx'})
112c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        cmd = build_ext(dist)
113c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
114c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        # making sure the user option is there
115c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        options = [name for name, short, label in
116c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo                   cmd.user_options]
117c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        self.assertIn('user', options)
118c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
119c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        # setting a value
120c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        cmd.user = 1
121c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
122c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        # setting user based lib and include
123c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        lib = os.path.join(site.USER_BASE, 'lib')
124c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        incl = os.path.join(site.USER_BASE, 'include')
125c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        os.mkdir(lib)
126c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        os.mkdir(incl)
127c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
128c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        cmd.ensure_finalized()
129c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
130c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        # see if include_dirs and library_dirs were set
131c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        self.assertIn(lib, cmd.library_dirs)
132c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        self.assertIn(lib, cmd.rpath)
133c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo        self.assertIn(incl, cmd.include_dirs)
134c811fb2d56e3c5847ac5c5a6d59bbc8b75e8effaÉric Araujo
135d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé    def test_finalize_options(self):
136d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # Make sure Python's include directories (for Python.h, pyconfig.h,
137d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # etc.) are in the include search path.
138b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        modules = [Extension('foo', ['xxx'])]
139d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        dist = Distribution({'name': 'xx', 'ext_modules': modules})
140d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
141d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
142d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
143b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        py_include = sysconfig.get_python_inc()
14425a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertIn(py_include, cmd.include_dirs)
145d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
146b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        plat_py_include = sysconfig.get_python_inc(plat_specific=1)
14725a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertIn(plat_py_include, cmd.include_dirs)
148d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
149d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure cmd.libraries is turned into a list
150d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # if it's a string
151d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
152e897a7472ded10a29ffcf046d021cd7fdc1ac94eÉric Araujo        cmd.libraries = 'my_lib, other_lib lastlib'
153d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
154e897a7472ded10a29ffcf046d021cd7fdc1ac94eÉric Araujo        self.assertEqual(cmd.libraries, ['my_lib', 'other_lib', 'lastlib'])
155d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
156d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure cmd.library_dirs is turned into a list
157d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # if it's a string
158d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
159e897a7472ded10a29ffcf046d021cd7fdc1ac94eÉric Araujo        cmd.library_dirs = 'my_lib_dir%sother_lib_dir' % os.pathsep
160d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
161c82da813c1406bc7e3878bf1d960d4765bcb0d89Éric Araujo        self.assertIn('my_lib_dir', cmd.library_dirs)
162c82da813c1406bc7e3878bf1d960d4765bcb0d89Éric Araujo        self.assertIn('other_lib_dir', cmd.library_dirs)
163d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
164d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure rpath is turned into a list
165e897a7472ded10a29ffcf046d021cd7fdc1ac94eÉric Araujo        # if it's a string
166d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
167e897a7472ded10a29ffcf046d021cd7fdc1ac94eÉric Araujo        cmd.rpath = 'one%stwo' % os.pathsep
168d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
1692623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.rpath, ['one', 'two'])
170d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
171846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        # make sure cmd.link_objects is turned into a list
172846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        # if it's a string
173846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        cmd = build_ext(dist)
174846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        cmd.link_objects = 'one two,three'
175846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        cmd.finalize_options()
176846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson        self.assertEqual(cmd.link_objects, ['one', 'two', 'three'])
177846466d2a67532c05a0acbf2a8d8a4e930f07b8dBenjamin Peterson
178d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # XXX more tests to perform for win32
179d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
180d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure define is turned into 2-tuples
181d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # strings if they are ','-separated strings
182d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
183d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.define = 'one,two'
184d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
1852623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])
186d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
187d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure undef is turned into a list of
188d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # strings if they are ','-separated strings
189d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
190d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.undef = 'one,two'
191d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
1922623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.undef, ['one', 'two'])
193d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
194d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # make sure swig_opts is turned into a list
195d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
196d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.swig_opts = None
197d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
1982623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.swig_opts, [])
199d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
200d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
201d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.swig_opts = '1 2'
202d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
2032623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.swig_opts, ['1', '2'])
204d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
205d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé    def test_check_extensions_list(self):
206d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        dist = Distribution()
207d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
208d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.finalize_options()
209d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
210d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        #'extensions' option must be a list of Extension instances
211d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, 'foo')
212d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
213d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # each element of 'ext_modules' option must be an
214d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # Extension instance or 2-tuple
215d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts = [('bar', 'foo', 'bar'), 'foo']
216d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
217d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
218d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # first element of each tuple in 'ext_modules'
219d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # must be the extension name (a string) and match
220d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # a python dotted-separated name
221d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts = [('foo-bar', '')]
222d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
223d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
224d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # second element of each tuple in 'ext_modules'
225bf2dca96fbda4193552a56f7f1258ba5d16f2a60Martin Panter        # must be a dictionary (build info)
226d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts = [('foo.bar', '')]
227d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
228d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
229d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # ok this one should pass
230d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
231d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé                             'some': 'bar'})]
232d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.check_extensions_list(exts)
233d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        ext = exts[0]
23425a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertIsInstance(ext, Extension)
235d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
236d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # check_extensions_list adds in ext the values passed
237d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # when they are in ('include_dirs', 'library_dirs', 'libraries'
238d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # 'extra_objects', 'extra_compile_args', 'extra_link_args')
2392623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(ext.libraries, 'foo')
24025a23efcda0dc3e245eefa8c9a3f96b4baee6303Serhiy Storchaka        self.assertFalse(hasattr(ext, 'some'))
241d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
242d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        # 'macros' element of build info dict must be 1- or 2-tuple
243d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts = [('foo.bar', {'sources': [''], 'libraries': 'foo',
244d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé                'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})]
245d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
246d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
247d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        exts[0][1]['macros'] = [('1', '2'), ('3',)]
248d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.check_extensions_list(exts)
2492623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(exts[0].undef_macros, ['3'])
2502623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(exts[0].define_macros, [('1', '2')])
251d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
252d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé    def test_get_source_files(self):
253b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        modules = [Extension('foo', ['xxx'])]
254d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        dist = Distribution({'name': 'xx', 'ext_modules': modules})
255d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
256d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.ensure_finalized()
2572623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.get_source_files(), ['xxx'])
258d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
259972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé    def test_compiler_option(self):
260972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        # cmd.compiler is an option and
2618d496add74530767cad3aa8b5b371b9a7f0b8498Martin Panter        # should not be overridden by a compiler instance
262972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        # when the command is run
263972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        dist = Distribution()
264972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd = build_ext(dist)
265972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.compiler = 'unix'
266972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.ensure_finalized()
267972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.run()
2682623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(cmd.compiler, 'unix')
269972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé
270d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé    def test_get_outputs(self):
271972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        tmp_dir = self.mkdtemp()
272972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        c_file = os.path.join(tmp_dir, 'foo.c')
2736633a6606b935fa1160293029f59eb892e7aed4fHirokazu Yamamoto        self.write_file(c_file, 'void initfoo(void) {};\n')
274b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext = Extension('foo', [c_file])
275972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        dist = Distribution({'name': 'xx',
276972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé                             'ext_modules': [ext]})
277d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd = build_ext(dist)
27804612d60929d5cda8d4cd215dfa2fc050d20b530Éric Araujo        support.fixup_build_ext(cmd)
279d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé        cmd.ensure_finalized()
2802623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(len(cmd.get_outputs()), 1)
281d5d83424d235783ddaa1a98a82278805d05c437bTarek Ziadé
282972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.build_lib = os.path.join(self.tmp_dir, 'build')
283972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
284972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé
285972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        # issue #5977 : distutils build_ext.get_outputs
286972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        # returns wrong result with --inplace
287cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé        other_tmp_dir = os.path.realpath(self.mkdtemp())
288cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé        old_wd = os.getcwd()
289cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé        os.chdir(other_tmp_dir)
290cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé        try:
291cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé            cmd.inplace = 1
292cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé            cmd.run()
293cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé            so_file = cmd.get_outputs()[0]
294cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé        finally:
295cbb4f9ef58ec7673f7c64b16496879b914b0972aTarek Ziadé            os.chdir(old_wd)
2962623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertTrue(os.path.exists(so_file))
2972623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(os.path.splitext(so_file)[-1],
2982623a37852153363335956afab010cb0beb7e74eEzio Melotti                         sysconfig.get_config_var('SO'))
299972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        so_dir = os.path.dirname(so_file)
3002623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(so_dir, other_tmp_dir)
301b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.compiler = None
302972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.inplace = 0
303972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        cmd.run()
304972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        so_file = cmd.get_outputs()[0]
3052623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertTrue(os.path.exists(so_file))
3062623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(os.path.splitext(so_file)[-1],
3072623a37852153363335956afab010cb0beb7e74eEzio Melotti                         sysconfig.get_config_var('SO'))
308972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé        so_dir = os.path.dirname(so_file)
3092623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(so_dir, cmd.build_lib)
310972480d999b83f5d245cb4662122e9d25c54701eTarek Ziadé
3117d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        # inplace = 0, cmd.package = 'bar'
31265ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        build_py = cmd.get_finalized_command('build_py')
31365ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        build_py.package_dir = {'': 'bar'}
3147d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        path = cmd.get_ext_fullpath('foo')
3153fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        # checking that the last directory is the build_dir
3167d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        path = os.path.split(path)[0]
3172623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(path, cmd.build_lib)
3187d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé
3197d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        # inplace = 1, cmd.package = 'bar'
3207d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        cmd.inplace = 1
3217d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        other_tmp_dir = os.path.realpath(self.mkdtemp())
3227d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        old_wd = os.getcwd()
3237d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        os.chdir(other_tmp_dir)
3247d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        try:
3257d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé            path = cmd.get_ext_fullpath('foo')
3267d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        finally:
3277d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé            os.chdir(old_wd)
3287d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        # checking that the last directory is bar
3297d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        path = os.path.split(path)[0]
3307d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé        lastdir = os.path.split(path)[-1]
3312623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(lastdir, 'bar')
3327d7127dd84189bf9325ef3fc5f3c18359fa34f30Tarek Ziadé
33365ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé    def test_ext_fullpath(self):
3348c40001175f354b6e05d38a7f403afb5686c6013Tarek Ziadé        ext = sysconfig.get_config_vars()['SO']
33565ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        dist = Distribution()
3363fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        cmd = build_ext(dist)
3373fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        cmd.inplace = 1
3383fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        cmd.distribution.package_dir = {'': 'src'}
3393fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        cmd.distribution.packages = ['lxml', 'lxml.html']
3403fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        curdir = os.getcwd()
3418c40001175f354b6e05d38a7f403afb5686c6013Tarek Ziadé        wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
3423fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé        path = cmd.get_ext_fullpath('lxml.etree')
3432623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(wanted, path)
3443fbcc60eb859b00f4310e028da0ba6edba35f7c8Tarek Ziadé
34565ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        # building lxml.etree not inplace
34665ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        cmd.inplace = 0
34765ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        cmd.build_lib = os.path.join(curdir, 'tmpdir')
3488c40001175f354b6e05d38a7f403afb5686c6013Tarek Ziadé        wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
34965ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        path = cmd.get_ext_fullpath('lxml.etree')
3502623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(wanted, path)
35165ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé
35265ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        # building twisted.runner.portmap not inplace
35365ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        build_py = cmd.get_finalized_command('build_py')
35465ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        build_py.package_dir = {}
35565ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
35665ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        path = cmd.get_ext_fullpath('twisted.runner.portmap')
35765ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner',
3588c40001175f354b6e05d38a7f403afb5686c6013Tarek Ziadé                              'portmap' + ext)
3592623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(wanted, path)
36065ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé
36165ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        # building twisted.runner.portmap inplace
36265ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        cmd.inplace = 1
36365ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé        path = cmd.get_ext_fullpath('twisted.runner.portmap')
3648c40001175f354b6e05d38a7f403afb5686c6013Tarek Ziadé        wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
3652623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(wanted, path)
36665ec61ed06d7b28da05fa834c65ffa7c13005d2bTarek Ziadé
367b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé    def test_build_ext_inplace(self):
368b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
369b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        etree_ext = Extension('lxml.etree', [etree_c])
370b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
371e670e5ad5b7ef6b464fb264b688d96b9b9f71b53Tarek Ziadé        cmd = build_ext(dist)
372b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.ensure_finalized()
373b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.inplace = 1
374b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.distribution.package_dir = {'': 'src'}
375b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.distribution.packages = ['lxml', 'lxml.html']
376b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        curdir = os.getcwd()
377b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext = sysconfig.get_config_var("SO")
378b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
379b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        path = cmd.get_ext_fullpath('lxml.etree')
3802623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(wanted, path)
381b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé
382b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé    def test_setuptools_compat(self):
3835501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé        import distutils.core, distutils.extension, distutils.command.build_ext
3845501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé        saved_ext = distutils.extension.Extension
3855501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé        try:
3863f5d146323fe306de7ddccb2506a7161554cc330Florent Xicluna            # on some platforms, it loads the deprecated "dl" module
3873f5d146323fe306de7ddccb2506a7161554cc330Florent Xicluna            test_support.import_module('setuptools_build_ext', deprecated=True)
3883f5d146323fe306de7ddccb2506a7161554cc330Florent Xicluna
3895501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            # theses import patch Distutils' Extension class
3905501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            from setuptools_build_ext import build_ext as setuptools_build_ext
3915501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            from setuptools_extension import Extension
3925501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé
3935501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
3945501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            etree_ext = Extension('lxml.etree', [etree_c])
3955501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
3965501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            cmd = setuptools_build_ext(dist)
3975501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            cmd.ensure_finalized()
3985501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            cmd.inplace = 1
3995501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            cmd.distribution.package_dir = {'': 'src'}
4005501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            cmd.distribution.packages = ['lxml', 'lxml.html']
4015501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            curdir = os.getcwd()
4025501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            ext = sysconfig.get_config_var("SO")
4035501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
4045501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            path = cmd.get_ext_fullpath('lxml.etree')
4052623a37852153363335956afab010cb0beb7e74eEzio Melotti            self.assertEqual(wanted, path)
4065501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé        finally:
4075501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            # restoring Distutils' Extension class otherwise its broken
4085501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            distutils.extension.Extension = saved_ext
4095501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            distutils.core.Extension = saved_ext
4105501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé            distutils.command.build_ext.Extension = saved_ext
411b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé
412b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé    def test_build_ext_path_with_os_sep(self):
413b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        dist = Distribution({'name': 'UpdateManager'})
414b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd = build_ext(dist)
415b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.ensure_finalized()
416b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext = sysconfig.get_config_var("SO")
417b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext_name = os.path.join('UpdateManager', 'fdsend')
418b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext_path = cmd.get_ext_fullpath(ext_name)
419b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        wanted = os.path.join(cmd.build_lib, 'UpdateManager', 'fdsend' + ext)
4202623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(ext_path, wanted)
421b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé
42257bc6da7c4327aa870fbf5292c1b05a9ac3bfe19Serhiy Storchaka    @unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows')
423b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé    def test_build_ext_path_cross_platform(self):
424b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        dist = Distribution({'name': 'UpdateManager'})
425b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd = build_ext(dist)
426b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        cmd.ensure_finalized()
427b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext = sysconfig.get_config_var("SO")
428b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        # this needs to work even under win32
429b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext_name = 'UpdateManager/fdsend'
430b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        ext_path = cmd.get_ext_fullpath(ext_name)
431b30868a391b85d24b7d1abe41c137a9d75bfcebcTarek Ziadé        wanted = os.path.join(cmd.build_lib, 'UpdateManager', 'fdsend' + ext)
4322623a37852153363335956afab010cb0beb7e74eEzio Melotti        self.assertEqual(ext_path, wanted)
433e670e5ad5b7ef6b464fb264b688d96b9b9f71b53Tarek Ziadé
434a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren    @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
435053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    def test_deployment_target_default(self):
436053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # Issue 9516: Test that, in the absence of the environment variable,
437053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # an extension module is compiled with the same deployment target as
438053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        #  the interpreter.
439053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        self._try_compile_deployment_target('==', None)
440a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
441053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
442053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    def test_deployment_target_too_low(self):
443053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # Issue 9516: Test that an extension module is not allowed to be
444053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # compiled with a deployment target less than that of the interpreter.
445053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        self.assertRaises(DistutilsPlatformError,
446053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            self._try_compile_deployment_target, '>', '10.1')
447053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily
448053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX')
449053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    def test_deployment_target_higher_ok(self):
450053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # Issue 9516: Test that an extension module can be compiled with a
451053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # deployment target higher than that of the interpreter: the ext
452053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # module may depend on some newer OS feature.
453053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
454053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        if deptarget:
455053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            # increment the minor version number (i.e. 10.6 -> 10.7)
456053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            deptarget = [int(x) for x in deptarget.split('.')]
457053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            deptarget[-1] += 1
458053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            deptarget = '.'.join(str(i) for i in deptarget)
459053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            self._try_compile_deployment_target('<', deptarget)
460053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily
461053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily    def _try_compile_deployment_target(self, operator, target):
462a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        orig_environ = os.environ
463a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        os.environ = orig_environ.copy()
464a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        self.addCleanup(setattr, os, 'environ', orig_environ)
465a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
466053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        if target is None:
467053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
468053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily                del os.environ['MACOSX_DEPLOYMENT_TARGET']
469053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        else:
470053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
471a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
472a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')
473a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
474a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        with open(deptarget_c, 'w') as fp:
475a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            fp.write(textwrap.dedent('''\
476a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren                #include <AvailabilityMacros.h>
477a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
478a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren                int dummy;
479a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
480053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily                #if TARGET %s MAC_OS_X_VERSION_MIN_REQUIRED
481053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily                #else
482a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren                #error "Unexpected target"
483053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily                #endif
484a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
485053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily            ''' % operator))
486a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
487053c6ad6b7ee88d9076a91f47aa53dc7155d00ceNed Deily        # get the deployment target that the interpreter was built with
488a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
4891f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        target = tuple(map(int, target.split('.')[0:2]))
4901f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        # format the target value as defined in the Apple
4911f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        # Availability Macros.  We can't use the macro names since
4921f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        # at least one value we test with will not exist yet.
4931f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        if target[1] < 10:
4941f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily            # for 10.1 through 10.9.x -> "10n0"
4951f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily            target = '%02d%01d0' % target
4961f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily        else:
4971f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily            # for 10.10 and beyond -> "10nn00"
4981f70b878c4b890c66bdb90d8c9ddb59dee0b48dfNed Deily            target = '%02d%02d00' % target
499a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        deptarget_ext = Extension(
500a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            'deptarget',
501a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            [deptarget_c],
502a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            extra_compile_args=['-DTARGET=%s'%(target,)],
503a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        )
504a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        dist = Distribution({
505a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            'name': 'deptarget',
506a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            'ext_modules': [deptarget_ext]
507a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        })
508a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        dist.package_dir = self.tmp_dir
509a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        cmd = build_ext(dist)
510a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        cmd.build_lib = self.tmp_dir
511a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        cmd.build_temp = self.tmp_dir
512a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
513a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        try:
514a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            cmd.ensure_finalized()
515a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            cmd.run()
516a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren        except CompileError:
517a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren            self.fail("Wrong deployment target during compilation")
518a70286b71d6b98c14275c26f6ca1f0507c1bc56bRonald Oussoren
51988e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandldef test_suite():
5205501e6a7da371a851478a939d974ecebbc84e2ddTarek Ziadé    return unittest.makeSuite(BuildExtTestCase)
52188e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl
52288e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandlif __name__ == '__main__':
52388e2acf038b717199655d8206e4a5deaa0a0eb1aGeorg Brandl    test_support.run_unittest(test_suite())
524