emacs-mac differs substantially from the main Emacs builds, including the official NS/NextStep build that supports Mac (see README-mac for more details).
This document chronicles experiences merging upstream emacs into emacs-mac, beginning with Emacs v30.1, which was released in Feb, 2025. While most elisp changes typically merge smoothly, underlying Mac-specific C and ObjC code as well as build system details sometimes need more significant updates as the main project continues to evolve.
<2025-03-06 Thu>
Merged from the upstream emacs-30 branch into the emacs-mac work branch, which at the time of merge was based on upstream’s v29.4.
A number of issues were encountered:
- This is the first Emacs version supporting Android, which caused numerous conflicts in places where systems are differentiated. Many conflicts were resolved by adding various flags or symbols such as:
HAVE_MACGUIordefined(HAVE_MACGUI).- Referencing the
macdirectory in build configuration. (featurep 'mac-win)for e.g. mouse events.[frame]-~type~macandwindow-systemmacin various locations, e.g. forframep-on-displayandewwbrowser.- Mac-related doc entries that had been update or mangled.
docviewhas some special code forimage-iosupport (untested) which had been updated.- Mouse events have been simplified to only
wheel-up/down/left/righton most systems (including emacs-mac). Makefilebuild flags like$(MAC_OBJ)needed to be re-included.- An updated file function
sys_faccessatis now used. - Restore build flags like
MAC_SELF_CONTAINED. - Restore
funcall_subr. - Including structure entries like:
struct mac_output *mac; /* From macterm.h. */ struct mac_display_info *mac; /* macterm.h */ image.chas lots of changes, including releasing images, masks, color processing,image_iosupport that needed restoring, and _2x file processing. Needs testing.- Care was taken to to re-incorporate
FRAME_OBSCURED_Pinxdisp. macfont.mhas new font metrics for different weights.- Restore stipple support in
xfaces.c(untested).
After the merge, additional issues were uncovered that prevented compilation from completing:
- There were missing build config options like
mac/Makefileand theMAC_OBJC_OBJmakevariable. - Major updates to the underlying hash table API have appeared in v30 which required addressing. These include:
- a new
hash_hash_ttype - removal of size and threshold arguments for
make_hash_table - new separate
hash_lookup_get_hashandhash_lookupfunctions - etc.
- a new
- Toolbars: unusually, this build enables both
HAVE_EXT_TOOL_BARandHAVE_INT_TOOL_BAR, which are both required to have access to e.g.fset_tool_bar_window. Updated pre-processor tests made this combination fail, and required correction. - Some commands have changed arguments (e.g. to accommodate Android builds), like
openp,compute_image_size, andwindow_from_coordinates. - Some constants changed names, e.g.
FACE_UNDERLINE_*. - The compiler complained about a number of constants not being declared
static.
From Dec, 2019 post to emacs-devel by Yamamoto-san:
NS port-specific Obj-C files and LOC (as of Emacs 26.3):
1514 nsfont.m 197 nsgui.h 513 nsimage.m 1893 nsmenu.m 511 nsselect.m 1323 nsterm.h 9460 nsterm.m 18754 total
Mac port-specific C/Obj-C files and LOC (as of Emacs 26.3 Mac 7.8):
3237 mac.c 1436 macappkit.h 17097 macappkit.m 5434 macfns.c 279 macgui.h 896 macmenu.c 1141 macselect.c 6326 macterm.c 793 macterm.h 36639 total
Currently (as of v30.1) this is quite similar:
1765 nsfont.m 143 nsgui.h 610 nsimage.m 2039 nsmenu.m 825 nsselect.m 1387 nsterm.h 11261 nsterm.m 18030 total
3149 mac.c 1236 macappkit.h 17226 macappkit.m 5510 macfns.c 254 macgui.h 869 macmenu.c 1171 macselect.c 6242 macterm.c 819 macterm.h 36476 total
- Invoke
makeviaM-x compileso you canC-x `and directly visit errors. consult-rgmakes quick work of finding the parent function declaration.- From there,
magit-blamecan be used to quickly identify the recent commit which changed the calling convention, etc. - This commit often includes many examples of fixing code elsewhere to conform to the new conventions. These can be used as a guide to update affected code (usually in
macwin,macterm, etc).
Just disable stdio:
process launch -n -- -Q -l ~/code/emacs/test/inline-image-motion-bugs.el
By default, lldb works well from Terminal.app to run debug-builds of Emacs, but not Emacs itself.
In principle, you can launch one (non-debug) emacs, and use realgud or gud via M-x lldb to run another, but you get the dreaded:
Process 13127 exited with status = 5 (0x00000005) Terminated due to signal 5
error (also from eshell, etc.). This relates to SIGTRAP not being allowed via the launching code, which is used to attach to the debug interface. So you must add to the controlling application’s “entitlements”, using a self-signed process.
Create a file entitlements.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>that adds in particular cs.debugger support. Then attach it like:
codesign -fs - --entitlements entitlements.xml /Applications/Emacs_Carbon.appor whatever is the path to the Emacs you’ll be using to run lldb via.
You may get some errors about resource fork, etc., or “bundle format unrecognized, invalid, or unsuitable”. To solve this, temporarily move out the Frameworks and libexec folders from Emacs.app/Contents. Sign as above, then move them back in place. You should now be able to launch a subordinate debug version of emacs via lldb (e.g. in eshell).
Update: this doesn’t work reliably. Instead, I had to disable -debug SIP restrictions using csrutil. Then it can work via, e.g. DAPE.
CoreGraphics does not (as yet) support SVG natively (despite the existence of PrivateFrameworks/CoreSVG.framework). Right now, SVG display is fairly convoluted, and works as follows:
- Image-IO (which drives core graphics) is mapped to an
image-iotype in emacs-mac. Theimagemagicktype is aliased to it as well, unless imagemagick is explicitly compiled in. This allows direct image manipulation (scaling, etc.). image_io_loadis used to load either type of svg file.- For images of type
svg,svg_loadis registered ifRSVGsupport is compiled in. - There is also a
native-imagetype, which also just displays viaimage-io. - When looking up an image type, if it can use the
native_apiand has no library compiled explicitly to support it, it does so. - If and when we land in
image-io(e.g. because we don’t haveRSVGandsvg_load, or becauseimage-modehas created an:imagemagicktype image):- If the object is not directly loadable by Core Graphics (as indicated by its UTI not being on the
CGImageSourceCopyTypeIdentifiersreturn list, or being ansvgtype), it creates anEmacsDocumentRef - It adds a style sheet (with CSS!), and then calls
mac_document_create_with_dataormac_document_create_with_url. - The latter two look through the list of “document types”:
EmacsPDFDocument.classEmacsSVGDocument.classEmacsDocumentRasterizer.class
attempting to create a class of type
EmacsDocumentRasterizer(using either theURLorDataof the SVG file), and taking the first one that returns a valid document (running it in the main GUI thread if necessary).
- If the object is not directly loadable by Core Graphics (as indicated by its UTI not being on the
- Meanwhile, back in
EmacsSVGDocument, we see if we haveUSE_WK_APIset, and if so, we create aWKWebView(vs. a plainWebView). - In stock emacs-mac, we do have
USE_WK_APIset. It used to test:#if WK_API_ENABLED && MAC_OS_X_VERSION_MIN_REQUIRED >= 101300but now tests:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 || (WK_API_ENABLED && MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)(since
WK_API_ENABLEDwas removed as a compiler var in MacOS v10.15). - With
USE_WK_API, we set up some fancy webkit webview (cached to avoid constantly recreating). - We then create a literal giant string of JavaScript (!), which turns a bunch of CSS and bounding box stuff into a JSON string, via JavaScript!
- The data is loaded into the WebView, and a JSON object is encoded from the string, simply to ask it for the bounding box, width, and height.
- And then, yet more JavaScript, creating an SVG and replacing the root node with it.
To summarize:
- For file-based images (what you get if you just
find-fileon.svg), the JS+WKWebView route is used. - For inline svg image (
:type svg, as created with, e.g. withsvg-image), we can display directly, ifRSVGis compiled and available. - If
RSVGis not available,UTI_SVGis returned frommac_get_uti_from_image_type, indicating that emacs-mac can display them natively, using theimage-iosvg chicanery above.
Compiled a debug build, using lldb to debug. Found that a wide glyph on the first line has its pixel_width incorrectly reported (or not, just has issues with where the line is wrapped and is off by one char, which can be a wide glyph).
In macOS 15, the Window menu allows MacOS keybindings for windows management to work in emacs. See https://support.apple.com/en-is/guide/mac-help/mchl9674d0b0/mac.
To support this feature:
In mac-win.el, we’ve added a “Window” menu-bar. This menu holds MacOS’s native Windows Menu Items, along with all native tab commands. See mac-window-menu-map.
In macappkit.m, we look for the “Window” menu-item defined in mac-win.el and bind it to the mac app via [NSApp setWindowsMenu]