-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-41100: ctypes fixes for arm64 Mac OS #21249
bpo-41100: ctypes fixes for arm64 Mac OS #21249
Conversation
This updates setup.py to default to the system libffi on Mac OS 10.15 and forward. It also updates detect_ctypes to prefer finding libffi in the Xcode SDK, rather than /usr/include
On arm64 the calling convention for variardic functions is different than the convention for fixed-arg functions of the same arg types. ctypes needs to use ffi_prep_cif_var to tell libffi which calling convention to use.
0da8223
to
bacf128
Compare
This set of patches includes the following upstream pull requests: - python/cpython#21114 "Support `arm64` in Mac/Tools/pythonw" - python/cpython#21224 "allow python to build for macosx-11.0-arm64" - python/cpython#21249 "ctypes fixes for arm64 Mac OS" Adding the patches before upstream has released them is warranted here because `python@3.8` is widely used as a dependency, and the patch is needed to enable testing dependent formulae on arm64. CC: Sean Molenaar <1484494+SMillerDev@users.noreply.github.com>
@lawrence-danna-apple We currently redistribute |
We also distribute I'm not sure what the status is as to upstreaming, but I'll do a review of it and see if anything necessary is still missing from upstream. Noe that in the changes I'm proposing here, the Mac OS system |
Got it, thanks for clarifying. It looks like there may be some issues in |
Co-authored-by: Arch Oversight <archoversight@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lawrence-danna-apple We currently redistribute
libffi
along with Python to support Mac OS X 10.10 as our deployment target. Your change implies that there were changes made tolibffi
(and the copy that ships with macOS 11) for arm64 macOS. Are these upstreamed and available?
Isn't it possible/save to use the system libffi on 10.9 or later? The 10.9 SDK includes libffi, even if it uses an older API (just like libffi_osx in the CPython tree).
I'd prefer to drop the copy of libffi included with CPython and always use the system libffi, without including a copy of libffi in the installers for macOS.
I'm a bit conflicted about the "variadic" attribute for _FuncPtr. I agree that it is necessary, but this is an API change and as such is a lot harder to back port. |
I'm not sure if this is possible. The libffi prior to 10.15 won't have the APIs we need to support arm64. However, we may be able to use ifdefs and availability to sort it out. I'll try. Do you know why libffi was bundled into cpython in the first place? Do we have reason to believe the libffi on older releases of mac OS was broken in some way? |
This set of patches includes the following upstream pull requests, in this order: - PR 20171, "Fix _tkinter use" python/cpython#20171 (prerequisite for patch #21249 to apply) - PR 21114, "Support `arm64` in Mac/Tools/pythonw" python/cpython#21114 - PR 21224, "allow python to build for macosx-11.0-arm64" python/cpython#21224 - PR 21249, "ctypes fixes for arm64 Mac OS" python/cpython#21249 The patches for 20171 and 21249 have been minimally modified in order to backport them to 3.8.3. Note that these have been successfully tested for `python@3.8` but not for `python@3.7`. The patch directive should be surrounded by an `if Hardware::CPU.arm?` block.
This replaces the three unmerged PR patches with a hosted formula patch. This includes the following upstream pull requests: - python/cpython#20171, "Fix _tkinter use" (prerequisite for 21249) - python/cpython#21114, "Support arm64 in Mac/Tools/pythonw" - python/cpython#21224, "allow python to build for macosx-11.0-arm64" - python/cpython#21249, "ctypes fixes for arm64 Mac OS" See also: - Homebrew/formula-patches#292
Well, it looks like I misread the documentation. It turns out that in the case where a variadic function is called with zero variadic arguments, the two calling conventions coincide. So the flag is not necessary after all. |
I found it is possible to use the system libffi even if the deployment target is set to before 10.15. I've added runtime checks for I've also enabled the system ffi if either the deployment target is 10.15 OR the arm64 is in the target arches. I'm not sure if Mac OS on PPC is still supported by python, but these changes shouldn't break it if it is. The only thing that will not work is to build a super-fat binary that works on ppc, x86 and arm64 at the same time. Should I add a commit deleting |
be472ad
to
aeac14b
Compare
This replaces the three unmerged PR patches with a hosted formula patch. This includes the following upstream pull requests: - python/cpython#20171, "Fix _tkinter use" (prerequisite for 21249) - python/cpython#21114, "Support arm64 in Mac/Tools/pythonw" - python/cpython#21224, "allow python to build for macosx-11.0-arm64" - python/cpython#21249, "ctypes fixes for arm64 Mac OS" See also: - Homebrew/formula-patches#292 Closes #57997. Signed-off-by: Claudia Pellegrino <1239874+claui@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a smoke test, I tried building with --with-system-ffi
on macOS 10.9 and ran into the issue that __builtin_available
is apparently not available until Xcode 9.0
on macOS 10.12
and it is a requirement that we can continue to be built on older systems with their supported Xcode versions. I found a workaround from the curl project that might be usable here if we need to support using the system libffi which would be desirable.
Also we should avoid the potential pragma warnings when building on other platforms.
Modules/_ctypes/callbacks.c
Outdated
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); | ||
#if HAVE_FFI_PREP_CLOSURE_LOC | ||
# if USING_APPLE_OS_LIBFFI | ||
# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__builtin_available
is itself not available with older versions of macOS and Xcode, in particular with macOS 10.9 and Xcode 6, which we currently need to use to build our most common installer variants. And there are other projects like MacPorts that builds Python for older macOS systems. The general review comment has a link for a possible workaround from the curl project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of __builtin_available should be safe, it is within a guard of HAVE_FFI_PREP_CLOSURE_LOC and USING_APPLE_OS_LIBFFI: The system version of libffi does not have ffi_prep_closure_loc in the 10.9 SDK (it is introduced in 10.15).
Modules/_ctypes/callproc.c
Outdated
return -1; | ||
|
||
# if USING_APPLE_OS_LIBFFI | ||
# define HAVE_FFI_PREP_CIF_VAR_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__builtin_available
again
Modules/_ctypes/malloc_closure.c
Outdated
{ | ||
#if USING_APPLE_OS_LIBFFI | ||
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__builtin_available
again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid this needs a configure test, ffi_closure_free is not available at all in older SDKs.
Modules/_ctypes/malloc_closure.c
Outdated
{ | ||
#if USING_APPLE_OS_LIBFFI | ||
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__builtin_available
again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
p, | ||
p->pcl_exec); | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdeprecated-declarations" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdeprecated-declarations" | ||
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); | ||
#pragma clang diagnostic pop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, | ||
p, | ||
p->pcl_exec); | ||
#pragma clang diagnostic push |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid -Wunknown-pragmas
warnings when building on other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some comments, and am finally working on this PR on the DTK.
Modules/_ctypes/callbacks.c
Outdated
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); | ||
#if HAVE_FFI_PREP_CLOSURE_LOC | ||
# if USING_APPLE_OS_LIBFFI | ||
# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of __builtin_available should be safe, it is within a guard of HAVE_FFI_PREP_CLOSURE_LOC and USING_APPLE_OS_LIBFFI: The system version of libffi does not have ffi_prep_closure_loc in the 10.9 SDK (it is introduced in 10.15).
Doc/library/ctypes.rst
Outdated
@@ -2545,4 +2545,3 @@ Arrays and pointers | |||
|
|||
Returns the object to which to pointer points. Assigning to this | |||
attribute changes the pointer to point to the assigned object. | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary removal of a blank line (not important)
Modules/_ctypes/callbacks.c
Outdated
result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); | ||
#if HAVE_FFI_PREP_CLOSURE_LOC | ||
# if USING_APPLE_OS_LIBFFI | ||
# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why test for macOS 11 and not 10.15? According to the header files this API is introduced in 10.15.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right it should be 10.15
Modules/_ctypes/callproc.c
Outdated
return -1; | ||
|
||
# if USING_APPLE_OS_LIBFFI | ||
# define HAVE_FFI_PREP_CIF_VAR_RUNTIME __builtin_available(macos 11, ios 13, watchos 6, tvos 13, *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise: the headers claim this _var variant is present in macOS 10.15.
"ffi_prep_cif failed"); | ||
return -1; | ||
|
||
# if USING_APPLE_OS_LIBFFI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposed change:
#if USING_APPLE_OS_LIBFFI && HAVE_FFI_PREP_CIF_VAR
This way the __builtin_available is not used when building on older macOS versions.
Modules/_ctypes/malloc_closure.c
Outdated
{ | ||
#if USING_APPLE_OS_LIBFFI | ||
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid this needs a configure test, ffi_closure_free is not available at all in older SDKs.
Modules/_ctypes/malloc_closure.c
Outdated
{ | ||
#if USING_APPLE_OS_LIBFFI | ||
if (__builtin_available(macos 11, ios 13, watchos 6, tvos 13, *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
self.use_system_libffi = True | ||
else: | ||
self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to just drop "use_system_libffi" and unconditionally use the system headers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
This is support for ctypes on macOS/arm64 based on PR 21249 by Lawrence D'Anna (Apple). Changes: - changed __builtin_available tests from 11.0 to 10.15 - added test to setup.py for ffi_closure_alloc and use that in malloc_closure.c - Minor change in the code path for ffi_prep_closure_var (coding style change)
I have made the requested changes; please review again |
Thanks for making the requested changes! @ned-deily: please review the changes made to this pull request. |
Your comments have alerted me to a new problem. If I understand you correctly, the way you're doing the official builds for python is to build on an old version of Mac OS, with an old version of Xcode, in order to assure compatibility with a broad range of Mac OS versions. This will work for x86_64, but if you want a universal build that works on both 10.10 and 11.0-arm64, it will not work, becaue the old Xcode doesn't support arm64 for Mac OS On the other hand, if you build with the new Xcode using MACOSX_DEPLOYMENT_TARGET=10.10, that also does not work on 10.10, because autoconf will discover several functions such as |
@lawrence-danna-apple quite right. This has been an issue for us at Dropbox in recent years. Python's official approach for backwards compatibility is not based on setting the deployment target, which is problematic for use in client-side software. We've fixed this internally by patching |
I opened up a new PR to deal with the deployment target issue. |
Thanks for the PR. We are aware of the issues with supporting multiple levels and architectures Being able to weaklink from a build on a newer version to an older version has been desirable but it hasn't been a high priority issue. Actively supporting multiple architectures again (something we haven't had to do since the retirement of PPC :) makes this a higher priority issue and @ronaldoussoren is now working on it. I've added him to the reviewers of the new PR (#21577). |
ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1") | ||
ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please bear in mind that Python may be built against an external libffi on macOS that is not the OS-provided version. In MacPorts we build against our port of libffi 3.3 on all OS versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment by @ronaldoussoren who prefers to unconditionally use the system's libffi. I updated this PR accordingly. Is there any reason not to use the system libffi anymore? I tested going back to 10.10 i think for the other PR adding availability checks. What's the need to support alternative libffi these days?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reasons as any other library: the OS often ships an older version which naturally lacks the features and bug fixes of later versions.
Thanks for the PR. It has been included in and superseded by GH-22855. |
Posted in response to this comment by Ronald #21242 (comment)
This PR would supersede these two, combining because the third commit depends on both
This has three commits:
The first two are from those previous PRs. The third makes
setup.py
probe for those functions by searching libffi's headers.https://bugs.python.org/issue41100