hamacs/README-MacOS.org
Howard Abrams 6d92980311 Migration from ~/other to ~/src
Why was it any other way?
2024-10-19 13:34:01 -07:00

12 KiB
Raw Blame History

Installing Emacs on MacOS

These instructions originally came from this essay, as it runs Emacs as dæmon with LaunchAgent. Also fetch mails periodically with mbsync via LaunchAgent.

Install

Since Ive been having difficulties installing Emacs from source on a Mac, Im now taking advantage ofJim 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:

  brew tap jimeh/emacs-builds

And then, install Emacs:

  brew install --cask emacs-app

Install from Source

If we cant install a binary, we build from source.

Emacs Plus

No longer need to install Apple XCode, as these instructions require Homebrew.

If I want to build from source (and not build from Homebrew), install all the dependencies first, by running:

  brew install pkg-config automake texinfo jpeg giflib\
    libtiff jansson libpng librsvg gnutls cmake

To get the native compilation for Emacs working, install:

  brew install libgccjit

Oh, and if we are still building with ImageMagick, install that first:

  brew install imagemagick

Best success comes from using the emacs-plus installation. To begin, add the cask:

  brew tap d12frosted/emacs-plus

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 elfeed. To that end, I run the following command to install Emacs:

  brew install emacs-plus@29 --with-native-comp --with-mailutils  --with-savchenkovaleriy-big-sur-icon --with-no-frame-refocus --debug

And if it fails, choose shell and type:

  make bootstrap

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:

mkdir -p ~/src
git clone https://git.savannah.gnu.org/git/emacs.git ~/src/emacs
cd ~/src/emacs
./autogen.sh

And we can issue the same sort of configure we used for

./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

Or to install/build into /usr/local:

  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

Assuming that either works, then build it with:

  make -j4

Ouchie

Sometimes get the following error:

  ld: symbol(s) not found for architecture x86_64

And 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):

  brew update
  brew upgrade

Next make sure that all the dependencies are reinstalled with the current operating system:

  brew reinstall $(brew deps emacs-plus@29)

Then reinstall the libgccjit (as it doesnt seem to get picked up with the deps listing):

  brew uninstall libgccjit gcc
  brew uninstall emacs-plus@29
  brew install libgccjit gcc

And then reinstall Emacs above.

And if that doesnt 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.

  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."

Afterwards

After Emacs is kinda working, make sure you install all the fonts, that is:

M-x all-the-icons-install-fonts

And to get the Doom Modeline working:

M-x nerd-icons-install-fonts

Everything golden?

M-x straight-freeze-versions

Before we can build a Telegram server for Telega, we need to install the latest version:

  brew unlink tdlib  # optional
  brew install tdlib --HEAD

Supporting Packages

Now install all the extras:

  brew install git-delta
  brew install libvterm
  brew install mu
  brew install isync
  brew install gpg

Mu4a

See ha-email for better instructions.

  mkdir -p ~/.mail/work ~/.mail/gmail
  mu init --maildir=~/.mail   mu index
  mbsync -Va
  mu index

Mbsync config

See ha-email for better instructions.

  cat ~/.mbsyncrc

Basic configuration, that I actually supersede.

  # ========== 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 ==========

Dæmon Processes

On the Mac, cron has been removed and replaced with LaunchAgent. I find my ICanHazShortcut process pretty simple to start Emacs, so Im not sure about this dæmon, but …

Emacs dæmon via LaunchAgent

Notice that UserName section should be your $USER value.

  <?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>

Verify that the plist file is correct.

  plutil -lint ~/Library/LaunchAgents/gnu.emacs.plist

Start, stop and list service.

  launchctl load -w /Users/USERNAME/Library/LaunchAgents/gnu.emacs.plist
  launchctl unload /Users/USERNAME/Library/LaunchAgents/gnu.emacs.plist
  launchctl list

Fetch mails periodically

Lets make another dæmon for fetching mail. Again, replace UserName with your user account name.

  <?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>

Verify that the plist file is correct.

  plutil -lint ~/Library/LaunchAgents/periodic.mbsync.plist

Start, stop and list service.

  launchctl load -w /Users/USERNAME/Library/LaunchAgents/periodic.mbsync.plist
  launchctl unload /Users/USERNAME/Library/LaunchAgents/periodic.mbsync.plist
  launchctl list

Script that fetches mails and updates the mail index.

  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 $?

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:

  /opt/homebrew/bin/emacsclient -nc --socket-name work $*

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…

  plutil -convert json -r ~/Library/LaunchAgents/gnu.emacs.plist

Which should look a bit like:

  {
      "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"
  }

Convert it back to XML

  plutil -convert xml1 ~/Library/LaunchAgents/gnu.emacs.plist

Resources

  man launchd
  man launchctl
  man launchd.plist
  man plutil
  man plist