|
7 | 7 | import string |
8 | 8 | import unittest |
9 | 9 | from pathlib import Path |
| 10 | +from unittest import mock |
10 | 11 |
|
11 | 12 | from test.support import is_android, is_apple_mobile, is_wasm32 |
12 | 13 |
|
@@ -173,6 +174,23 @@ def test_c_api(self): |
173 | 174 | version = sysconfig.get_config_var('VERSION') |
174 | 175 | self.assertTrue(os.path.exists(os.path.join(value['pkgconfig_path'], f'python-{version}.pc'))) |
175 | 176 |
|
| 177 | + @needs_installed_python |
| 178 | + @unittest.skipIf( |
| 179 | + is_android or is_apple_mobile, |
| 180 | + "Android and iOS run tests via a custom testbed method that doesn't ship libpython" |
| 181 | + ) |
| 182 | + def test_libpython_static(self): |
| 183 | + value = self.data.get('libpython', {}) |
| 184 | + if 'static' not in value: |
| 185 | + self.skipTest("No static libpython") |
| 186 | + |
| 187 | + if sysconfig._installation_is_relocated(): |
| 188 | + self.skipTest("Installation is relocated") |
| 189 | + |
| 190 | + # The path must name an installed static library (an 'ar' archive). |
| 191 | + with open(value['static'], 'rb') as f: |
| 192 | + self.assertEqual(f.read(8), b'!<arch>\n') |
| 193 | + |
176 | 194 |
|
177 | 195 | @unittest.skipIf( |
178 | 196 | generate_build_details is None, |
@@ -233,5 +251,61 @@ def test_round_trip(self): |
233 | 251 | self.assertEqual(data_abs_path[part][key], abs_rel_path) |
234 | 252 |
|
235 | 253 |
|
| 254 | +@unittest.skipIf( |
| 255 | + generate_build_details is None, |
| 256 | + "Failed to import generate-build-details" |
| 257 | +) |
| 258 | +@unittest.skipIf(os.name != 'posix', 'Feature only implemented on POSIX') |
| 259 | +@unittest.skipIf(is_wasm32, 'Feature not available on WebAssembly builds') |
| 260 | +class BuildDetailsLibpythonTests(unittest.TestCase): |
| 261 | + LIBDIR = '/prefix/lib' |
| 262 | + LIBPL = '/prefix/lib/python3.X/config-3.X' |
| 263 | + |
| 264 | + def generate_libpython(self, **config_vars): |
| 265 | + """Generate the libpython section with overridden config vars.""" |
| 266 | + config_vars = dict(LIBDIR=self.LIBDIR, LIBPL=self.LIBPL, |
| 267 | + LIBRARY='libpython3.X.a', **config_vars) |
| 268 | + get_config_var = sysconfig.get_config_var |
| 269 | + def patched_get_config_var(name): |
| 270 | + if name in config_vars: |
| 271 | + return config_vars[name] |
| 272 | + return get_config_var(name) |
| 273 | + with mock.patch('sysconfig.get_config_var', patched_get_config_var): |
| 274 | + data = generate_build_details.generate_data(schema_version='1.0') |
| 275 | + return json.loads(json.dumps(data)).get('libpython', {}) |
| 276 | + |
| 277 | + def test_static_only(self): |
| 278 | + libpython = self.generate_libpython( |
| 279 | + LDLIBRARY='libpython3.X.a', STATIC_LIBPYTHON=1, |
| 280 | + PYTHONFRAMEWORK='') |
| 281 | + self.assertNotIn('dynamic', libpython) |
| 282 | + self.assertEqual(libpython['static'], |
| 283 | + os.path.join(self.LIBDIR, 'libpython3.X.a')) |
| 284 | + |
| 285 | + def test_shared_and_static(self): |
| 286 | + # The static library is only installed into LIBPL, not LIBDIR. |
| 287 | + libpython = self.generate_libpython( |
| 288 | + LDLIBRARY='libpython3.X.so', STATIC_LIBPYTHON=1, |
| 289 | + PYTHONFRAMEWORK='') |
| 290 | + self.assertEqual(libpython['dynamic'], |
| 291 | + os.path.join(self.LIBDIR, 'libpython3.X.so')) |
| 292 | + self.assertEqual(libpython['static'], |
| 293 | + os.path.join(self.LIBPL, 'libpython3.X.a')) |
| 294 | + |
| 295 | + def test_shared_without_static(self): |
| 296 | + libpython = self.generate_libpython( |
| 297 | + LDLIBRARY='libpython3.X.so', STATIC_LIBPYTHON=0, |
| 298 | + PYTHONFRAMEWORK='') |
| 299 | + self.assertNotIn('static', libpython) |
| 300 | + |
| 301 | + def test_framework(self): |
| 302 | + # Framework builds don't install the static library. LIBPL contains |
| 303 | + # a libpython3.X.a symlink to the framework's shared library instead. |
| 304 | + libpython = self.generate_libpython( |
| 305 | + LDLIBRARY='Python.framework/Versions/3.X/Python', |
| 306 | + STATIC_LIBPYTHON=1, PYTHONFRAMEWORK='Python') |
| 307 | + self.assertNotIn('static', libpython) |
| 308 | + |
| 309 | + |
236 | 310 | if __name__ == '__main__': |
237 | 311 | unittest.main() |
0 commit comments