Files
emacs-org/notes/emacs-macos-build.org
Martin Sukany f81e1e8f0d update
2026-02-23 22:39:12 +01:00

279 lines
7.8 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
* Emacs macOS Build s macOS Zoom Accessibility
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.
** Proč je to potřeba
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.
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.
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-select --install
#+end_src
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
git checkout emacs-31
#+end_src
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
git clone https://git.apps.sukany.cz/martin/emacs-doom.git /tmp/emacs-doom-config
#+end_src
Aplikuj patch:
#+begin_src sh
git am /tmp/emacs-doom-config/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch
#+end_src
Ověř, že patch byl aplikovaný:
#+begin_src sh
grep "UAZoomChangeFocus" src/nsterm.m | head -3
#+end_src
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ě.
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"
#+end_src
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
Parametr =-j$(sysctl -n hw.ncpu)= použije všechna dostupná jádra. Build trvá
přibližně 515 minut podle hardwaru.
Po dokončení build vytvoří =nextstep/Emacs.app=:
#+begin_src sh
make install
#+end_src
** Krok 6: Instalace
Přesuň Emacs.app do /Applications:
#+begin_src sh
cp -r nextstep/Emacs.app /Applications/Emacs.app
#+end_src
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:
#+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
Správné řešení — wrapper script:
#+begin_src sh
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
Ověření:
#+begin_src sh
which emacs
emacs --version
#+end_src
Výstup =which emacs= musí být =/usr/local/bin/emacs=.
** Krok 7: Accessibility permission
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.
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 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=