From 76acdbb9db9c2393f4f40d5ba9978beff1f23b96 Mon Sep 17 00:00:00 2001 From: Daneel Date: Mon, 23 Feb 2026 16:42:32 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20rewrite=20emacs-macos-build=20=E2=80=94?= =?UTF-8?q?=20detailed=20step-by-step,=20no=20tables,=20based=20on=20actua?= =?UTF-8?q?l=20build=20process?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/emacs-macos-build.org | 326 ++++++++++++++++++++++++------------ 1 file changed, 216 insertions(+), 110 deletions(-) diff --git a/notes/emacs-macos-build.org b/notes/emacs-macos-build.org index 31e967f..7d8517d 100644 --- a/notes/emacs-macos-build.org +++ b/notes/emacs-macos-build.org @@ -5,173 +5,279 @@ * Emacs macOS Build s macOS Zoom Accessibility -Návod na buildování GNU Emacs pro macOS s patchem pro =UAZoomChangeFocus=, -který opravuje sledování kurzoru v macOS Zoom "Follow keyboard focus". +Návod na sestavení GNU Emacs pro macOS s patchem, který opravuje sledování +kurzoru při zapnutém macOS Zoom ("Follow keyboard focus"). Postup vychází +z reálné zkušenosti z buildu v únoru 2026. -** Kontext +** Proč je to potřeba -macOS Zoom "Follow keyboard focus" ve vanilla GNU Emacs nefunguje. Root cause: -Emacs nemá implementovanou NSAccessibility pro vlastní NSView a hlavně -nevolá =UAZoomChangeFocus()= z =HIServices/UniversalAccess.h=. +macOS Zoom funguje jako magnifier přes celou obrazovku nebo v okně. Režim +"Follow keyboard focus" by měl automaticky posouvat viewport za textovým +kurzorem. Ve vanilla GNU Emacs to ale nefunguje. -Patch je v repozitáři [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]] -v =patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch=. +Příčina: Emacs má vlastní NSView, který neimplementuje NSAccessibility protokol +a hlavně nevolá =UAZoomChangeFocus()= z =HIServices/UniversalAccess.h=. Tuto funkci +volají iTerm2 (=PTYTextView.m=) i Chromium (=render_widget_host_view_mac.mm=) a +je to jediný spolehlivý způsob, jak Zoom přinutit sledovat kurzor v custom view. -** Prerekvizity +Standardní NSAccessibility notifikace samy o sobě nestačí — Zoom je event-driven +a potřebuje explicitní volání =UAZoomChangeFocus()= s aktuální pozicí kurzoru +v souřadnicích AX obrazovky (origin vlevo nahoře, tzn. y-osa je otočená oproti +Cocoa, kde origin je vlevo dole). + +Patch je uložený v repozitáři =martin/emacs-doom= na Giteě: +=patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch= + +** Krok 1: Prerekvizity + +Nejprve nainstaluj Xcode Command Line Tools (nutné pro kompilaci): #+begin_src sh -# Xcode Command Line Tools xcode-select --install - -# Homebrew závislosti -brew install autoconf libgmp texinfo pkg-config gnutls libxml2 \ - jansson tree-sitter librsvg imagemagick - -# Volitelné ale doporučené -brew install libgccjit # native compilation #+end_src -** Stažení zdrojů +Pak nainstaluj závislosti přes Homebrew: + +#+begin_src sh +brew install autoconf libgmp texinfo pkg-config gnutls libxml2 jansson tree-sitter librsvg imagemagick +#+end_src + +Pro native compilation (volitelné, výrazně rychlejší Emacs): + +#+begin_src sh +brew install libgccjit +#+end_src + +** Krok 2: Stažení zdrojového kódu Emacs #+begin_src sh git clone https://github.com/emacs-mirror/emacs.git cd emacs - -# Doporučená stable větev (aktuálně emacs-31) git checkout emacs-31 #+end_src -** Aplikace accessibility patche +Větev =emacs-31= je aktuálně doporučená stable větev. Až bude k dispozici =emacs-32=, +použij tu. + +** Krok 3: Aplikace accessibility patche + +Stáhni config repozitář s patchem: #+begin_src sh -# Stáhni patch z martin/emacs-doom git clone https://git.apps.sukany.cz/martin/emacs-doom.git /tmp/emacs-doom-config +#+end_src -# Aplikuj patch +Aplikuj patch: + +#+begin_src sh git am /tmp/emacs-doom-config/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch +#+end_src -# Ověř aplikaci +Ověř, že patch byl aplikovaný: + +#+begin_src sh grep "UAZoomChangeFocus" src/nsterm.m | head -3 #+end_src -Patch implementuje: -- =UAZoomChangeFocus()= — přímé volání Zoom API po každém pohybu kurzoru -- =NSAccessibilitySelectedTextChangedNotification= — standardní AX notifikace -- =NSAccessibilityFocusedUIElementChangedNotification= — notifikace při focusu -- =accessibilityBoundsForRange:= — nová NSAccessibilityProtocol API -- =AXBoundsForRange= — starší fallback API -- =NSAccessibilityTextAreaRole= — správná role pro Emacs view +Výsledkem by mělo být několik řádků s voláním =UAZoomChangeFocus=. Pokud grep +nic nevrátí, patch se neaplikoval správně. -** Konfigurace a Build +Co patch přidává do =src/nsterm.m=: + +- Volání =UAZoomChangeFocus()= po každém pohybu kurzoru — koordináty jsou + přepočítány z Cocoa (origin vlevo dole) do AX prostoru (origin vlevo nahoře) + ručním y-flipem: =primaryH - y - height= +- =NSAccessibilitySelectedTextChangedNotification= — notifikace po pohybu kurzoru +- =NSAccessibilityFocusedUIElementChangedNotification= — notifikace při zaměření okna +- =accessibilityBoundsForRange:= — nové API (macOS 10.10+) +- Fallback přes starší =AXBoundsForRange= pro starší verze +- =NSAccessibilityTextAreaRole= pro EmacsView + +** Krok 4: Konfigurace + +Spusť autogen a pak configure. Základní konfigurace (bez native compilation): #+begin_src sh ./autogen.sh +#+end_src +#+begin_src sh ./configure \ - --with-ns \ - --with-tree-sitter \ - --with-gnutls \ - --with-xml2 \ - --with-json \ - --with-imagemagick \ - --with-rsvg \ - --with-mailutils \ - --without-x \ - --without-dbus \ - CFLAGS="-O2 -g3" + --with-ns \ + --with-tree-sitter \ + --with-gnutls \ + --with-xml2 \ + --with-json \ + --with-imagemagick \ + --with-rsvg \ + --with-mailutils \ + --without-x \ + --without-dbus \ + CFLAGS="-O2 -g3" +#+end_src -# Build — -j počet CPU jader +S native compilation (pokud máš libgccjit): + +#+begin_src sh +./configure \ + --with-ns \ + --with-native-compilation=aot \ + --with-tree-sitter \ + --with-gnutls \ + --with-xml2 \ + --with-json \ + --without-x \ + CFLAGS="-O2 -g3" +#+end_src + +** Krok 5: Build + +#+begin_src sh make -j$(sysctl -n hw.ncpu) +#+end_src -# Vytvoří nextstep/Emacs.app +Parametr =-j$(sysctl -n hw.ncpu)= použije všechna dostupná jádra. Build trvá +přibližně 5–15 minut podle hardwaru. + +Po dokončení build vytvoří =nextstep/Emacs.app=: + +#+begin_src sh make install #+end_src -*** Volitelně: s native compilation (rychlejší Emacs) +** Krok 6: Instalace + +Přesuň Emacs.app do /Applications: #+begin_src sh -./configure \ - --with-ns \ - --with-native-compilation=aot \ - --with-tree-sitter \ - --with-gnutls \ - --with-xml2 \ - --with-json \ - --without-x \ - CFLAGS="-O2 -g3" -#+end_src - -** Instalace - -#+begin_src sh -# Přesuň Emacs.app do /Applications cp -r nextstep/Emacs.app /Applications/Emacs.app - -# Vytvoř wrapper script (NE symlink — Emacs nenajde data přes symlink) -sudo tee /usr/local/bin/emacs << 'EOF' -#!/bin/sh -exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@" -EOF -sudo chmod +x /usr/local/bin/emacs - -# Ověření -emacs --version #+end_src -*** Proč wrapper script, ne symlink +Vytvoř wrapper script. Pozor: použij wrapper script, ne symlink. Symlink nefunguje +správně — Emacs počítá cesty k Lisp souborům z =argv[0]=, a přes resolved symlink +je najde špatně. Projeví se to chybami jako: -Symlink (/usr/local/bin/emacs → .../Emacs.app/Contents/MacOS/Emacs) nefunguje -správně. Emacs počítá cesty k Lisp souborům z =argv[0]=, ne přes resolved symlink. -Výsledkem jsou chyby: #+begin_example Warning: arch-dependent data dir 'Contents/MacOS/libexec/': No such file or directory Warning: Lisp directory 'Contents/Resources/lisp': No such file or directory #+end_example -Wrapper script předává správnou cestu. - -** macOS Accessibility nastavení - -Po každém novém buildu (nový binary) je potřeba znovu udělit permission: - -1. System Settings → Privacy & Security → Accessibility -2. Přidat nové =/Applications/Emacs.app= -3. Zapnout toggle - -Bez tohoto kroku =UAZoomChangeFocus()= neovlivní Zoom viewport. - -** Doom Emacs sync +Správné řešení — wrapper script: #+begin_src sh -# Po instalaci -~/.emacs.d/bin/doom sync +sudo tee /usr/local/bin/emacs > /dev/null << 'EOF' +#!/bin/sh +exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@" +EOF +sudo chmod +x /usr/local/bin/emacs +#+end_src -# Pokud doom hledá emacs v jiné cestě -which emacs # musí vrátit /usr/local/bin/emacs +Ověření: + +#+begin_src sh +which emacs emacs --version #+end_src -** Ověření Zoom funkcionality +Výstup =which emacs= musí být =/usr/local/bin/emacs=. -1. System Settings → Accessibility → Zoom → zapnout "Use keyboard shortcut to zoom" -2. Zoom mode: Full Screen nebo Split Screen -3. Advanced → Zoom follows: =Keyboard focus= -4. Otevři Emacs, začni psát -5. Zoom viewport by měl sledovat kurzor +** Krok 7: Accessibility permission -** Časté problémy +Po každém novém buildu (nový binární soubor) je potřeba znovu udělit oprávnění. +Bez toho =UAZoomChangeFocus()= neovlivní Zoom viewport — volání proběhne, ale +macOS ho ignoruje bez Accessibility přístupu. -| Problém | Příčina | Řešení | -|---|---|---| -| doom sync: "emacs not found" | Wrapper script chybí nebo není v PATH | Viz sekce Instalace | -| Zoom nesleduje kurzor | Accessibility permission chybí | Přidat Emacs.app znovu do Privacy & Security | -| Zoom nesleduje kurzor | Patch nebyl aplikován | Ověřit: =grep UAZoomChangeFocus src/nsterm.m= | -| Build selže na nsterm.m | Chybí Xcode CLT nebo závislosti | =xcode-select --install= + brew install | -| "Contents/MacOS/libexec not found" | Symlink místo wrapper scriptu | Nahradit wrapper scriptem | +Postup: +1. Otevři System Settings → Privacy & Security → Accessibility +2. Přidej =/Applications/Emacs.app= +3. Zapni toggle vedle Emacs + +Pokud Emacs v seznamu už je (ze starého buildu), odeber ho a přidej znovu — +macOS identifikuje aplikace i podle binary hash a starý záznam neplatí. + +** Krok 8: Doom Emacs sync + +Pokud používáš Doom Emacs, spusť sync po instalaci nového Emacsu: + +#+begin_src sh +~/.emacs.d/bin/doom sync +#+end_src + +Pokud doom hlásí, že nenajde Emacs, zkontroluj: + +#+begin_src sh +which emacs +#+end_src + +Musí vrátit =/usr/local/bin/emacs=. Pokud vrátí jinou cestu, je problém +s PATH nebo chybí wrapper script. + +** Krok 9: Ověření Zoom funkcionality + +Nastav Zoom v System Settings: +1. System Settings → Accessibility → Zoom +2. Zapni "Use keyboard shortcut to zoom" nebo "Use scroll gesture with modifier keys to zoom" +3. Zoom style: Full Screen nebo Window (obojí funguje) +4. Klikni na "Advanced..." → záložka "Zoom Follows the Cursor" +5. Nastav "Zoom follows: Keyboard focus" + +Otevři Emacs a začni psát. Zoom viewport by měl automaticky sledovat textový +kurzor při každém pohybu (šipky, PageUp/Down, přechod mezi buffery). + +** Řešení problémů + +*Zoom nesleduje kurzor* + +Nejčastější příčiny jsou dvě. Za prvé, chybí Accessibility permission — viz Krok 7. +Za druhé, patch nebyl správně aplikovaný. Ověření: + +#+begin_src sh +grep "UAZoomChangeFocus" /Applications/Emacs.app/Contents/MacOS/../../../src/nsterm.m 2>/dev/null || \ + echo "Zkontroluj zdrojový kód nebo přelož znovu" +#+end_src + +Nebo v build adresáři: + +#+begin_src sh +grep "UAZoomChangeFocus" src/nsterm.m | wc -l +#+end_src + +Pokud výsledek je 0, patch chybí. Aplikuj znovu a přelož. + +*Build selže na nsterm.m* + +Zkontroluj, zda jsou nainstalované Xcode Command Line Tools: + +#+begin_src sh +xcode-select -p +#+end_src + +Pokud cesta neexistuje nebo vrátí chybu, spusť =xcode-select --install= znovu. + +*doom sync hlásí "emacs not found"* + +Zkontroluj wrapper script: + +#+begin_src sh +cat /usr/local/bin/emacs +#+end_src + +Soubor musí existovat a obsahovat =exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@"=. +Pokud neexistuje, viz Krok 6. + +*Chyby "libexec not found" nebo "lisp not found" při startu* + +Příčina je symlink místo wrapper scriptu. Zkontroluj: + +#+begin_src sh +ls -la /usr/local/bin/emacs +#+end_src + +Pokud výstup ukazuje =->= (symlink), smaž ho a vytvoř wrapper script podle Kroku 6. ** Reference -- Patch repo: [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]] -- Ghostty issue (stejný problém): https://github.com/nicowillis/Ghostty/issues/4053 -- iTerm2 implementace: =PTYTextView.m:refreshAccessibility= -- Chromium implementace: =render_widget_host_view_mac.mm:OnSelectionBoundsChanged= +- Patch repozitář: [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]] +- Podobný problém v Ghostty: https://github.com/nicowillis/Ghostty/issues/4053 +- Stejný přístup v iTerm2: =src/PTYTextView.m=, funkce =refreshAccessibility= +- Stejný přístup v Chromium: =render_widget_host_view_mac.mm=, funkce =OnSelectionBoundsChanged=