docs: rewrite emacs-macos-build — detailed step-by-step, no tables, based on actual build process
This commit is contained in:
@@ -5,173 +5,279 @@
|
|||||||
|
|
||||||
* Emacs macOS Build s macOS Zoom Accessibility
|
* Emacs macOS Build s macOS Zoom Accessibility
|
||||||
|
|
||||||
Návod na buildování GNU Emacs pro macOS s patchem pro =UAZoomChangeFocus=,
|
Návod na sestavení GNU Emacs pro macOS s patchem, který opravuje sledování
|
||||||
který opravuje sledování kurzoru v macOS Zoom "Follow keyboard focus".
|
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:
|
macOS Zoom funguje jako magnifier přes celou obrazovku nebo v okně. Režim
|
||||||
Emacs nemá implementovanou NSAccessibility pro vlastní NSView a hlavně
|
"Follow keyboard focus" by měl automaticky posouvat viewport za textovým
|
||||||
nevolá =UAZoomChangeFocus()= z =HIServices/UniversalAccess.h=.
|
kurzorem. Ve vanilla GNU Emacs to ale nefunguje.
|
||||||
|
|
||||||
Patch je v repozitáři [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]]
|
Příčina: Emacs má vlastní NSView, který neimplementuje NSAccessibility protokol
|
||||||
v =patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch=.
|
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
|
#+begin_src sh
|
||||||
# Xcode Command Line Tools
|
|
||||||
xcode-select --install
|
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
|
#+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
|
#+begin_src sh
|
||||||
git clone https://github.com/emacs-mirror/emacs.git
|
git clone https://github.com/emacs-mirror/emacs.git
|
||||||
cd emacs
|
cd emacs
|
||||||
|
|
||||||
# Doporučená stable větev (aktuálně emacs-31)
|
|
||||||
git checkout emacs-31
|
git checkout emacs-31
|
||||||
#+end_src
|
#+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
|
#+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
|
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
|
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
|
grep "UAZoomChangeFocus" src/nsterm.m | head -3
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Patch implementuje:
|
Výsledkem by mělo být několik řádků s voláním =UAZoomChangeFocus=. Pokud grep
|
||||||
- =UAZoomChangeFocus()= — přímé volání Zoom API po každém pohybu kurzoru
|
nic nevrátí, patch se neaplikoval správně.
|
||||||
- =NSAccessibilitySelectedTextChangedNotification= — standardní AX notifikace
|
|
||||||
- =NSAccessibilityFocusedUIElementChangedNotification= — notifikace při focusu
|
|
||||||
- =accessibilityBoundsForRange:= — nová NSAccessibilityProtocol API
|
|
||||||
- =AXBoundsForRange= — starší fallback API
|
|
||||||
- =NSAccessibilityTextAreaRole= — správná role pro Emacs view
|
|
||||||
|
|
||||||
** 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
|
#+begin_src sh
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src sh
|
||||||
./configure \
|
./configure \
|
||||||
--with-ns \
|
--with-ns \
|
||||||
--with-tree-sitter \
|
--with-tree-sitter \
|
||||||
--with-gnutls \
|
--with-gnutls \
|
||||||
--with-xml2 \
|
--with-xml2 \
|
||||||
--with-json \
|
--with-json \
|
||||||
--with-imagemagick \
|
--with-imagemagick \
|
||||||
--with-rsvg \
|
--with-rsvg \
|
||||||
--with-mailutils \
|
--with-mailutils \
|
||||||
--without-x \
|
--without-x \
|
||||||
--without-dbus \
|
--without-dbus \
|
||||||
CFLAGS="-O2 -g3"
|
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)
|
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
|
make install
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
*** Volitelně: s native compilation (rychlejší Emacs)
|
** Krok 6: Instalace
|
||||||
|
|
||||||
|
Přesuň Emacs.app do /Applications:
|
||||||
|
|
||||||
#+begin_src sh
|
#+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
|
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
|
#+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
|
#+begin_example
|
||||||
Warning: arch-dependent data dir 'Contents/MacOS/libexec/': No such file or directory
|
Warning: arch-dependent data dir 'Contents/MacOS/libexec/': No such file or directory
|
||||||
Warning: Lisp directory 'Contents/Resources/lisp': No such file or directory
|
Warning: Lisp directory 'Contents/Resources/lisp': No such file or directory
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
Wrapper script předává správnou cestu.
|
Správné řešení — wrapper script:
|
||||||
|
|
||||||
** 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
|
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
# Po instalaci
|
sudo tee /usr/local/bin/emacs > /dev/null << 'EOF'
|
||||||
~/.emacs.d/bin/doom sync
|
#!/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ě
|
Ověření:
|
||||||
which emacs # musí vrátit /usr/local/bin/emacs
|
|
||||||
|
#+begin_src sh
|
||||||
|
which emacs
|
||||||
emacs --version
|
emacs --version
|
||||||
#+end_src
|
#+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"
|
** Krok 7: Accessibility permission
|
||||||
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
|
|
||||||
|
|
||||||
** Č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í |
|
Postup:
|
||||||
|---|---|---|
|
1. Otevři System Settings → Privacy & Security → Accessibility
|
||||||
| doom sync: "emacs not found" | Wrapper script chybí nebo není v PATH | Viz sekce Instalace |
|
2. Přidej =/Applications/Emacs.app=
|
||||||
| Zoom nesleduje kurzor | Accessibility permission chybí | Přidat Emacs.app znovu do Privacy & Security |
|
3. Zapni toggle vedle Emacs
|
||||||
| 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 |
|
Pokud Emacs v seznamu už je (ze starého buildu), odeber ho a přidej znovu —
|
||||||
| "Contents/MacOS/libexec not found" | Symlink místo wrapper scriptu | Nahradit wrapper scriptem |
|
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
|
** Reference
|
||||||
|
|
||||||
- Patch repo: [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]]
|
- Patch repozitář: [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]]
|
||||||
- Ghostty issue (stejný problém): https://github.com/nicowillis/Ghostty/issues/4053
|
- Podobný problém v Ghostty: https://github.com/nicowillis/Ghostty/issues/4053
|
||||||
- iTerm2 implementace: =PTYTextView.m:refreshAccessibility=
|
- Stejný přístup v iTerm2: =src/PTYTextView.m=, funkce =refreshAccessibility=
|
||||||
- Chromium implementace: =render_widget_host_view_mac.mm:OnSelectionBoundsChanged=
|
- Stejný přístup v Chromium: =render_widget_host_view_mac.mm=, funkce =OnSelectionBoundsChanged=
|
||||||
|
|||||||
Reference in New Issue
Block a user