Skip to content

ci: Bump all the macOS builder images - #32372

Open
QuLogic wants to merge 1 commit into
matplotlib:mainfrom
QuLogic:ci-macos
Open

QuLogic wants to merge 1 commit into
matplotlib:mainfrom
QuLogic:ci-macos

Conversation

@QuLogic

@QuLogic QuLogic commented Sep 18, 2026

Copy link
Copy Markdown
Member

PR summary

Since macOS 14 seems to no longer be supported, Homebrew has been dropping pre-built packages for it as they are updated. Based on statistics from Pillow (which is one of our dependencies), 10.14 and below just barely summed to 0.1% of usage in December 2024, so we should be safe to stop testing on it.

Fixes #32339

AI Disclosure

None

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • New and changed code is tested
  • [n/a] Plotting related features are demonstrated in an example
  • [n/a] New features and API changes have release notes
  • [n/a] Documentation complies with general and docstring guidelines

Since macOS 14 seems to no longer be supported, Homebrew has been
dropping pre-built packages for it as they are updated. Based on
statistics from Pillow (which is one of our dependencies), 10.14 and
below just barely summed to 0.1% of usage, so we should be safe to stop
testing on it.

Fixes matplotlib#32339
@QuLogic QuLogic added CI: Run cibuildwheel Run wheel building tests on a PR CI: testing CI configuration and testing labels Sep 18, 2026
@QuLogic

QuLogic commented Sep 18, 2026

Copy link
Copy Markdown
Member Author

Hmm, it looks like Qt is crashing on macOS 26 for some reason.

@iccir

iccir commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Attaching crash log. Working on a solution.

qt_crash_log.txt

@iccir

iccir commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

I'm still investigating. It would appear that using CTFontCollectionCreateFromAvailableFonts() exposes a bug in __NSGetSystemFontVariants.

When AppKit creates a window, it calls +[NSFont monospacedDigitSystemFontOfSize:weight:], which calls __NSGetSystemFontVariants and we hit the bug. This occurs on the first launch of matplotlib using an interactive framework in macOS Tahoe 26.5.2 (and possibly earlier/later).

As far as I can tell, our usage of CTFontCollectionCreateFromAvailableFonts() in mpl_get_available_fonts is 100% correct. We are correctly getting the font list and building the font cache.

I need to call it for the night, but I'll investigate a workaround/fix tomorrow.

@iccir

iccir commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Our usage of CTFontCollectionCreateFromAvailableFonts() is correct. The issue is related to the order we load frameworks and how the runtime sets up toll-free bridging between CTFont and NSFont.

Consider the following example:

example.py
import ctypes
from ctypes import c_void_p, c_double

LOAD_APPKIT_FIRST = False

appkit = None
if LOAD_APPKIT_FIRST:
    appkit = ctypes.CDLL("/System/Library/Frameworks/AppKit.framework/AppKit")

objc = ctypes.CDLL("/usr/lib/libobjc.A.dylib")
coretext = ctypes.CDLL("/System/Library/Frameworks/CoreText.framework/CoreText")

CTFontCollectionCreateFromAvailableFonts = (
    coretext.CTFontCollectionCreateFromAvailableFonts
)
CTFontCollectionCreateFromAvailableFonts.argtypes = [c_void_p]
CTFontCollectionCreateFromAvailableFonts.restype = c_void_p

collection = CTFontCollectionCreateFromAvailableFonts(None)

objc_getClass = objc.objc_getClass
objc_getClass.argtypes = [ctypes.c_char_p]
objc_getClass.restype = c_void_p

sel_registerName = objc.sel_registerName
sel_registerName.argtypes = [ctypes.c_char_p]
sel_registerName.restype = c_void_p

objc_msgSend = ctypes.cast(
    objc.objc_msgSend,
    ctypes.CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_double, c_double)
)

if not appkit:
    appkit = ctypes.CDLL("/System/Library/Frameworks/AppKit.framework/AppKit")

NSFont = objc_getClass(b"NSFont")
selector = sel_registerName(b"monospacedSystemFontOfSize:weight:")

font = objc_msgSend(NSFont, selector, 0, 400.0)

If LOAD_APPKIT_FIRST is True, we will load AppKit before our call to CTFontCollectionCreateFromAvailableFonts(). This sets up bridging and allows later calls in AppKit that assume a NSFont object to instead operate on a CTFont object.

If LOAD_APPKIT_FIRST is False, AppKit will later try to send an Obj-C message to a CTFont object and we will get an exception. I'm not 100% sure of the exact details here. I could find out, but it would require a few hours of decompiling AppKit code.

I can make the above example reproduce on all versions of macOS; however, the bug in matplotlib only reproduces in macOS 26+. On 15-, I assume that something else is loading AppKit into memory before we use CoreText.

There are two possible solutions:

  1. Load AppKit explicitly in mpl_get_available_fonts()
  2. Use multiprocessing to call mpl_get_available_fonts() in a subprocess.

1 is the simpler choice for now. 2 could be used in the future if we encounter more "run this in a separate process to work around an OS bug" situations.

@iccir iccir left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved once #32376 lands.

@iccir

iccir commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

10.14 and below just barely summed to 0.1% of usage in December 2024, so we should be safe to stop testing on it.

To be clear: macOS 10.14 and macOS 14 are not the same version. We haven't tested on 10.14 in a very long time.

macOS 10.14 Mojave was released in 2018 and last updated in 2021.
macOS 14 Sonoma was released in 2023 and last updated in 2026.

Yes, macOS version numbers are confusing, especially with the jump from macOS 15 to macOS 26.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI: Run cibuildwheel Run wheel building tests on a PR CI: testing CI configuration and testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MNT]: Old macOS CI is failing to install

2 participants