2022-09-02 23:03:43 +00:00
#+title : Installing Emacs on MacOS
#+author : Howard X. Abrams
#+date : 2022-09-02 September
2023-12-03 18:57:36 +00:00
#+tags : emacs macos readme
2022-09-02 23:03:43 +00:00
These instructions originally came from [[https://jherrlin.github.io/posts/emacs-on-macos-monterey/ ][this essay ]], as it runs Emacs as dæmon with LaunchAgent. Also fetch mails periodically with =mbsync= via LaunchAgent.
* Install
2024-02-22 00:28:57 +00:00
Since I’ ve been having difficulties installing Emacs from source on a Mac, I’ m now taking advantage of[[https://github.com/jimeh/emacs-builds ][Jim Myhrberg's Emacs Build project ]], and it is must nicer to simply, download a pre-built binary with all the bells and whistles.
First, install the Homebrew cask:
#+begin_src sh
brew tap jimeh/emacs-builds
#+end_src
And then, install Emacs:
#+begin_src sh
brew install --cask emacs-app
#+end_src
* Install from Source
If we can’ t install a binary, we build from source.
** Emacs Plus
2022-10-02 05:05:17 +00:00
No longer need to install [[https://apps.apple.com/us/app/xcode/id497799835?mt=12 ][Apple XCode ]], as these instructions require [[https://brew.sh ][Homebrew ]].
2024-02-22 00:28:57 +00:00
If I want to build from source (and not build from Homebrew), install all the dependencies first, by running:
#+begin_src sh
2024-10-19 20:34:01 +00:00
brew install pkg-config automake texinfo jpeg giflib\
libtiff jansson libpng librsvg gnutls cmake
2024-02-22 00:28:57 +00:00
#+end_src
2022-10-02 05:05:17 +00:00
To get the native compilation for Emacs working, install:
#+begin_src sh
brew install libgccjit
#+end_src
2024-02-22 00:28:57 +00:00
2022-10-02 05:05:17 +00:00
Oh, and if we are still building with [[https://imagemagick.org/ ][ImageMagick ]], install that first:
#+begin_src sh
brew install imagemagick
#+end_src
Best success comes from using the [[https://github.com/d12frosted/homebrew-emacs-plus ][emacs-plus ]] installation. To begin, add the /cask/ :
2022-09-02 23:03:43 +00:00
#+begin_src sh
brew tap d12frosted/emacs-plus
#+end_src
2022-10-02 05:05:17 +00:00
2023-05-25 17:36:55 +00:00
I find that I need to … at least, on my work computer, install two different versions of Emacs that I use to distinguish one for “work” and the other for other activities, like IRC and [[file:ha-feed-reader.org ][elfeed ]]. To that end, I run the following command to install Emacs:
2022-09-02 23:03:43 +00:00
#+begin_src sh
2023-05-25 17:36:55 +00:00
brew install emacs-plus@29 --with-native-comp --with-mailutils --with-savchenkovaleriy-big-sur-icon --with-no-frame-refocus --debug
2022-09-02 23:03:43 +00:00
#+end_src
2023-05-25 17:36:55 +00:00
And if it fails, choose =shell= and type:
2022-09-02 23:03:43 +00:00
#+begin_src sh
2023-05-25 17:36:55 +00:00
make bootstrap
2022-09-02 23:03:43 +00:00
#+end_src
2024-02-22 00:28:57 +00:00
** Build from Scratch
The failures that I often get from installing the Emacs Plus with Libgccjit, means that we might want to build from soure:
#+begin_src sh
mkdir -p ~/src
git clone https://git.savannah.gnu.org/git/emacs.git ~/src/emacs
cd ~/src/emacs
./autogen.sh
#+end_src
And we can issue the same sort of configure we used for
#+begin_src sh
./configure --disable-dependency-tracking --disable-silent-rules \
--enable-locallisppath=/opt/homebrew/share/emacs/site-lisp \
--infodir=/opt/homebrew/Cellar/emacs-plus@29/29.2/share/info/emacs \
--prefix=/opt/homebrew/Cellar/emacs-plus@29/29.2 \
--with-xml2 --with-gnutls --with-native-compilation --without-compress-install \
--without-dbus --without-imagemagick --with-modules --with-rsvg --without-pop \
--with-ns --disable-ns-self-contained
#+end_src
Or to install/build into =/usr/local= :
#+begin_src sh
LDFLAGS=-L/opt/homebrew/opt/libgccjit/lib -L/opt/homebrew/opt/xz/lib
CPPFLAGS=-I/opt/homebrew/opt/libgccjit/include -I/opt/homebrew/opt/xz/include
export LDFLAGS CPPFLAGS
./configure --disable-dependency-tracking --disable-silent-rules \
--prefix=/usr/local \
--with-xml2 --with-gnutls --with-native-compilation --without-compress-install \
--without-dbus --without-imagemagick --with-modules --with-rsvg --without-pop \
--with-ns --disable-ns-self-contained
#+end_src
Assuming that either works, then build it with:
#+begin_src sh
make -j4
#+end_src
2022-10-02 05:05:17 +00:00
** Ouchie
Sometimes get the following error:
#+begin_example
ld: symbol(s) not found for architecture x86_64
#+end_example
2023-02-22 01:26:51 +00:00
And [[https://duckduckgo.com/?q=brew+ld%3A+symbol(s)+not+found+for+architecture+x86_64&t=ffab&ia=web ][web searches ]] yield mixed results. To solve, first /re-touch/ the environment (as it appears the problem is that some dependent library is now out-of-date compared to operating system installation):
#+begin_src sh
brew update
brew upgrade
#+end_src
Next make sure that all the dependencies are /reinstalled/ with the current operating system:
#+begin_src sh
brew reinstall $(brew deps emacs-plus@29)
#+end_src
Then reinstall the =libgccjit= (as it doesn’ t seem to get picked up with the /deps/ listing):
#+begin_src sh
2023-05-25 17:36:55 +00:00
brew uninstall libgccjit gcc
brew uninstall emacs-plus@29
brew install libgccjit gcc
#+end_src
And then reinstall Emacs above.
And if that doesn’ t work, then we need to delete all packages installed by brew, and essentially start all over to see what sub-sub-sub-package got rebuilt without =libgccjit= . Painful and time-consuming, but I basically let it run all night.
#+begin_src sh
PKG_FILE=$(mktemp --suffix= .txt)
brew list --formula > ${PKG_FILE}
while read PACKAGE
do
brew uninstall ${PACKAGE}
done < ${PKG_FILE}
brew install libgccjit gcc
# No, it doesn't seem that reinstall actuall works.
while read PACKAGE
do
brew install ${PACKAGE}
done < ${PKG_FILE}
echo "Good luck rebuilding Emacs."
2023-02-22 01:26:51 +00:00
#+end_src
2023-11-06 17:36:06 +00:00
* Afterwards
After Emacs is /kinda/ working, make sure you install *all* the fonts, that is:
#+begin_example
M-x all-the-icons-install-fonts
#+end_example
And to get the Doom Modeline working:
#+begin_example
M-x nerd-icons-install-fonts
#+end_example
Everything golden?
#+begin_example
M-x straight-freeze-versions
#+end_example
Before we can build a Telegram server for [[file:ha-aux-apps.org::*Telega ][Telega ]], we need to install the /latest/ version:
#+begin_src sh
brew unlink tdlib # optional
brew install tdlib --HEAD
#+end_src
2022-09-02 23:03:43 +00:00
* Supporting Packages
Now install all the extras:
#+begin_src sh
2022-10-02 05:05:17 +00:00
brew install git-delta
brew install libvterm
2022-09-02 23:03:43 +00:00
brew install mu
brew install isync
brew install gpg
#+end_src
** Mu4a
See [[file:ha-email.org ][ha-email ]] for better instructions.
#+begin_src sh
mkdir -p ~/.mail/work ~ /.mail/gmail
2023-12-03 18:57:36 +00:00
mu init --maildir=~/.mail mu index
2022-09-02 23:03:43 +00:00
mbsync -Va
mu index
#+end_src
** Mbsync config
See [[file:ha-email.org ][ha-email ]] for better instructions.
#+begin_src sh
cat ~/.mbsyncrc
#+end_src
Basic configuration, that I actually supersede.
#+begin_src conf
# ========== Gmail = =========
IMAPAccount gmail
Host imap.gmail.com
User username@gmail.com
PassCmd "/opt/homebrew/bin/gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/ .password-store/mbsync/gmail.gpg"
AuthMechs LOGIN
SSLType IMAPS
IMAPStore gmail-remote
Account gmail
MaildirStore gmail-local
Subfolders Verbatim
Path ~/.mail/gmail/
Inbox ~/.mail/gmail/Inbox
Channel gmail
Far :gmail-remote:
Near :gmail-local:
Patterns * ![Gmail]* "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail"
Expunge None
CopyArrivalDate yes
Sync All
Create Near
SyncState *
# ========== Gmail = =========
#+end_src
* Dæmon Processes
On the Mac, =cron= has been removed and replaced with =LaunchAgent= . I find my [[file:ha-capturing-notes.org::*Push MacOS-Specific Content ][ICanHazShortcut ]] process pretty simple to start Emacs, so I’ m not sure about this dæmon, but …
** Emacs dæmon via LaunchAgent
Notice that =UserName= section should be your =$USER= value.
#+begin_src xml :tangle ~/Library/LaunchAgents/gnu.emacs.plist
<?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 >KeepAlive</key >
<true/ >
<key >Label</key >
<string >gnu.emacs</string >
<key >ProgramArguments</key >
<array >
<string >/opt/homebrew/bin/emacs</string >
<string >--fg-dæmon</string >
</array >
<key >RunAtLoad</key >
<true/ >
<key >StandardErrorPath</key >
<string >/tmp/gnu-emacs-dæmon.log</string >
<key >StandardOutPath</key >
<string >/tmp/gnu-emacs-dæmon.log</string >
<key >UserName</key >
<string >howard</string >
</dict >
</plist >
#+end_src
Verify that the plist file is correct.
#+begin_src sh
plutil -lint ~/Library/LaunchAgents/gnu.emacs.plist
#+end_src
Start, stop and list service.
#+begin_src sh
launchctl load -w /Users/USERNAME/Library/LaunchAgents/gnu.emacs.plist
launchctl unload /Users/USERNAME/Library/LaunchAgents/gnu.emacs.plist
launchctl list
#+end_src
** Fetch mails periodically
Let’ s make another dæmon for fetching mail. Again, replace =UserName= with your user account name.
#+begin_src xml :tangle ~/Library/LaunchAgents/periodic.mbsync.plist
<?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 >KeepAlive</key >
<true/ >
<key >Label</key >
<string >periodic.mbsync</string >
<key >ProgramArguments</key >
<array >
<string >/Users/USERNAME/ .bin/mbsync-task</string >
</array >
<key >StandardOutPath</key >
<string >/tmp/mbsync-task.log</string >
<key >StandardErrorPath</key >
<string >/tmp/mbsync-task.log</string >
<key >ThrottleInterval</key >
<integer >180</integer >
<key >RunAtLoad</key >
<true/ >
<key >UserName</key >
<string >howard</string >
</dict >
</plist >
#+end_src
Verify that the plist file is correct.
#+begin_src sh
plutil -lint ~/Library/LaunchAgents/periodic.mbsync.plist
#+end_src
Start, stop and list service.
#+begin_src sh
launchctl load -w /Users/USERNAME/Library/LaunchAgents/periodic.mbsync.plist
launchctl unload /Users/USERNAME/Library/LaunchAgents/periodic.mbsync.plist
launchctl list
#+end_src
Script that fetches mails and updates the mail index.
#+begin_src sh :tangle ~/.bin/mbsync-task :shebang #!/bin/bash
echo ""
echo "Running $(date +"%Y-%m-%d %H:%M")"
/opt/homebrew/bin/mbsync -Va
echo "Exit code:"
echo $?
/opt/homebrew/bin/emacsclient -e '(mu4e-update-index)'
echo "Exit code:"
echo $?
#+end_src
* Emacsclient
Simple /Automator/ script that's wrapped into an application and placed in the =Applications= folder. Select *New Document* , then select *Application* . Open the *Library* , and drag the *Run Shell Script* to the /workflow/ . In the box, add this:
#+begin_src sh
2023-11-06 17:36:06 +00:00
/opt/homebrew/bin/emacsclient -nc --socket-name work $*
2022-09-02 23:03:43 +00:00
#+end_src
Change the *Pass Input* to =as arguments= .
Select to *Save* as =Emacsclient= into the *Applications* folder.
** Utils
Convert a plist XML file into a JSON file. Not sure why this is important to know…
#+begin_src sh
plutil -convert json -r ~/Library/LaunchAgents/gnu.emacs.plist
#+end_src
Which should look a bit like:
#+begin_src js
{
"KeepAlive" : true,
"Label" : "gnu.emacs",
"ProgramArguments" : [
"\/opt\/homebrew\/bin\/emacs",
"--fg-dæmon"
],
"RunAtLoad" : true,
"StandardErrorPath" : "\/tmp\/gnu-emacs-dæmon.log",
"StandardOutPath" : "\/tmp\/gnu-emacs-dæmon.log",
"UserName" : "USERNAME"
}
#+end_src
Convert it back to XML
#+begin_src sh
plutil -convert xml1 ~/Library/LaunchAgents/gnu.emacs.plist
#+end_src
** Resources
#+begin_src sh
man launchd
man launchctl
man launchd.plist
man plutil
man plist
#+end_src
2024-03-07 04:02:25 +00:00
#+description : A literate programming file for installing a dæmon version of Emacs on MacOS.
2022-09-02 23:03:43 +00:00
2024-03-07 04:02:25 +00:00
#+property : header-args:sh :tangle no
#+property : header-args:emacs-lisp :tangle no
#+property : header-args :results none :eval no-export :comments no
2022-09-02 23:03:43 +00:00
2024-03-07 04:02:25 +00:00
#+options : num:nil toc:t todo:nil tasks:nil tags:nil date:nil
#+options : skip:nil author:nil email:nil creator:nil timestamp:nil
#+infojs_opt : view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js