[3.9] bpo-41100: Support macOS 11 and Apple Silicon (GH-22855) (GH-23295)

* [3.9] bpo-41100: Support macOS 11 and Apple Silicon (GH-22855)

Co-authored-by:  Lawrence D’Anna <lawrence_danna@apple.com>

* Add support for macOS 11 and Apple Silicon (aka arm64)

  As a side effect of this work use the system copy of libffi on macOS, and remove the vendored copy

* Support building on recent versions of macOS while deploying to older versions

  This allows building installers on macOS 11 while still supporting macOS 10.9..
(cherry picked from commit 41761933c1)

Co-authored-by: Ronald Oussoren <ronaldoussoren@mac.com>

* Back port of changes to _decimal to support arm64

* temp_dir is in test.support in 3.9
This commit is contained in:
Ronald Oussoren 2020-11-22 11:18:40 +01:00 committed by GitHub
parent 0aab3522b2
commit e8b1c038b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1659 additions and 413 deletions

View file

@ -1905,6 +1905,233 @@ class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin):
assert_python_ok(*args, PATH=path)
@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS")
class TestPosixWeaklinking(unittest.TestCase):
# These test cases verify that weak linking support on macOS works
# as expected. These cases only test new behaviour introduced by weak linking,
# regular behaviour is tested by the normal test cases.
#
# See the section on Weak Linking in Mac/README.txt for more information.
def setUp(self):
import sysconfig
import platform
config_vars = sysconfig.get_config_vars()
self.available = { nm for nm in config_vars if nm.startswith("HAVE_") and config_vars[nm] }
self.mac_ver = tuple(int(part) for part in platform.mac_ver()[0].split("."))
def _verify_available(self, name):
if name not in self.available:
raise unittest.SkipTest(f"{name} not weak-linked")
def test_pwritev(self):
self._verify_available("HAVE_PWRITEV")
if self.mac_ver >= (10, 16):
self.assertTrue(hasattr(os, "pwritev"), "os.pwritev is not available")
self.assertTrue(hasattr(os, "preadv"), "os.readv is not available")
else:
self.assertFalse(hasattr(os, "pwritev"), "os.pwritev is available")
self.assertFalse(hasattr(os, "preadv"), "os.readv is available")
def test_stat(self):
self._verify_available("HAVE_FSTATAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_FSTATAT", posix._have_functions)
else:
self.assertNotIn("HAVE_FSTATAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.stat("file", dir_fd=0)
def test_access(self):
self._verify_available("HAVE_FACCESSAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_FACCESSAT", posix._have_functions)
else:
self.assertNotIn("HAVE_FACCESSAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.access("file", os.R_OK, dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "follow_symlinks unavailable"):
os.access("file", os.R_OK, follow_symlinks=False)
with self.assertRaisesRegex(NotImplementedError, "effective_ids unavailable"):
os.access("file", os.R_OK, effective_ids=True)
def test_chmod(self):
self._verify_available("HAVE_FCHMODAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_FCHMODAT", posix._have_functions)
else:
self.assertNotIn("HAVE_FCHMODAT", posix._have_functions)
self.assertIn("HAVE_LCHMOD", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.chmod("file", 0o644, dir_fd=0)
def test_chown(self):
self._verify_available("HAVE_FCHOWNAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_FCHOWNAT", posix._have_functions)
else:
self.assertNotIn("HAVE_FCHOWNAT", posix._have_functions)
self.assertIn("HAVE_LCHOWN", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.chown("file", 0, 0, dir_fd=0)
def test_link(self):
self._verify_available("HAVE_LINKAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_LINKAT", posix._have_functions)
else:
self.assertNotIn("HAVE_LINKAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"):
os.link("source", "target", src_dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "dst_dir_fd unavailable"):
os.link("source", "target", dst_dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"):
os.link("source", "target", src_dir_fd=0, dst_dir_fd=0)
# issue 41355: !HAVE_LINKAT code path ignores the follow_symlinks flag
with support.temp_dir() as base_path:
link_path = os.path.join(base_path, "link")
target_path = os.path.join(base_path, "target")
source_path = os.path.join(base_path, "source")
with open(source_path, "w") as fp:
fp.write("data")
os.symlink("target", link_path)
# Calling os.link should fail in the link(2) call, and
# should not reject *follow_symlinks* (to match the
# behaviour you'd get when building on a platform without
# linkat)
with self.assertRaises(FileExistsError):
os.link(source_path, link_path, follow_symlinks=True)
with self.assertRaises(FileExistsError):
os.link(source_path, link_path, follow_symlinks=False)
def test_listdir_scandir(self):
self._verify_available("HAVE_FDOPENDIR")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_FDOPENDIR", posix._have_functions)
else:
self.assertNotIn("HAVE_FDOPENDIR", posix._have_functions)
with self.assertRaisesRegex(TypeError, "listdir: path should be string, bytes, os.PathLike or None, not int"):
os.listdir(0)
with self.assertRaisesRegex(TypeError, "scandir: path should be string, bytes, os.PathLike or None, not int"):
os.scandir(0)
def test_mkdir(self):
self._verify_available("HAVE_MKDIRAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_MKDIRAT", posix._have_functions)
else:
self.assertNotIn("HAVE_MKDIRAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.mkdir("dir", dir_fd=0)
def test_rename_replace(self):
self._verify_available("HAVE_RENAMEAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_RENAMEAT", posix._have_functions)
else:
self.assertNotIn("HAVE_RENAMEAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
os.rename("a", "b", src_dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
os.rename("a", "b", dst_dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
os.replace("a", "b", src_dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
os.replace("a", "b", dst_dir_fd=0)
def test_unlink_rmdir(self):
self._verify_available("HAVE_UNLINKAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_UNLINKAT", posix._have_functions)
else:
self.assertNotIn("HAVE_UNLINKAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.unlink("path", dir_fd=0)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.rmdir("path", dir_fd=0)
def test_open(self):
self._verify_available("HAVE_OPENAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_OPENAT", posix._have_functions)
else:
self.assertNotIn("HAVE_OPENAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.open("path", os.O_RDONLY, dir_fd=0)
def test_readlink(self):
self._verify_available("HAVE_READLINKAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_READLINKAT", posix._have_functions)
else:
self.assertNotIn("HAVE_READLINKAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.readlink("path", dir_fd=0)
def test_symlink(self):
self._verify_available("HAVE_SYMLINKAT")
if self.mac_ver >= (10, 10):
self.assertIn("HAVE_SYMLINKAT", posix._have_functions)
else:
self.assertNotIn("HAVE_SYMLINKAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.symlink("a", "b", dir_fd=0)
def test_utime(self):
self._verify_available("HAVE_FUTIMENS")
self._verify_available("HAVE_UTIMENSAT")
if self.mac_ver >= (10, 13):
self.assertIn("HAVE_FUTIMENS", posix._have_functions)
self.assertIn("HAVE_UTIMENSAT", posix._have_functions)
else:
self.assertNotIn("HAVE_FUTIMENS", posix._have_functions)
self.assertNotIn("HAVE_UTIMENSAT", posix._have_functions)
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.utime("path", dir_fd=0)
def test_main():
try:
support.run_unittest(
@ -1912,6 +2139,7 @@ def test_main():
PosixGroupsTester,
TestPosixSpawn,
TestPosixSpawnP,
TestPosixWeaklinking
)
finally:
support.reap_children()