Files
build-emacs-for-macos/README.md
Jim Myhrberg b46e5aa7cb fix(native_comp): ensure builds work after recent changes to eln cache locations
As detailed in Update 11 (https://akrl.sdf.org/gccemacs.html#org4b11ea1)
the `*.eln` cache location has been changed, which initially broke
builds.

This fixes those issues, and also simplifies usage of the build-script
by:

- Auto-detecting native-comp support if not explicitly enabled/disabled
  with CLI flags.
- Auto-detecting number of logical CPU cores on your machine, and
  defaulting the `-j` option to said number to ensure fast builds.
- Enable XWidgets by default, only skip if `configure` script doesn't
  support it (Emacs 26.x and earlier).
2020-08-19 00:58:31 +01:00

202 lines
7.3 KiB
Markdown

# build-emacs-for-macos
My personal hacked together script for building a completely self-contained
Emacs.app application on macOS, from any git branch, tag, or ref.
Use this script at your own risk.
## Why?
- To use new features available from master or branches, which have not made it
into a official stable release yet.
- Homebrew builds of Emacs are not self-contained applications, making it very
difficult when doing HEAD builds and you need to rollback to a earlier
version.
- Both Homebrew HEAD builds, and nightly builds from emacsformacosx.com are
built from the `master` branch. This script allows you to choose any branch,
tag, or git ref you want.
## Status
As of writing (2020-08-19) it works for me on my machine. Your luck may vary.
I have successfully built:
- `emacs-27.1` release git tag
- `master` branch (Emacs 28.x)
- `feature/native-comp` branch (Emacs 28.x)
For reference, my machine is:
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
- macOS 10.15.6 (19G2021)
- Xcode 11.6
## Limitations
The build produced does have some limitations:
- It is not a universal application. The CPU architecture of the built
application will be that of the machine it was built on.
- The minimum required macOS version of the built application will be the same
as that of the machine it was built on.
- The application is not signed, so running it on machines other than the one
that built the application will yield warnings. If you want to make a signed
Emacs.app, google is you friend for finding signing instructions.
## Requirements
- [Xcode](https://apps.apple.com/gb/app/xcode/id497799835?mt=12)
- [Homebrew](https://brew.sh/)
- All Homebrew formula listed in the `Brewfile`, which can all easily be
installed by running:
```
brew bundle
```
## Usage
```
Usage: ./build-emacs-for-macos [options] <branch/tag/sha>
Branch, tag, and SHA are from the emacs-mirror/emacs/emacs Github repo,
available here: https://github.com/emacs-mirror/emacs
-j, --parallel COUNT Compile using COUNT parallel processes (detected: 8)
--[no-]xwidgets Enable/disable XWidgets (default: enabled)
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
--[no-]native-fast-boot Enable/disable NATIVE_FAST_BOOT (default: enabled if native-comp supported)
```
Resulting applications are saved to the `builds` directory in a bzip2 compressed
tarball.
If you don't want the build process to eat all your CPU cores, pass in a `-j`
value of how many CPU cores you want it to use.
### Examples
To download a tarball of the `master` branch (Emacs 28.x) and build Emacs.app
from it:
```
./build-emacs-for-macos
```
To build the stable `emacs-27.1` release git tag run:
```
./build-emacs-for-macos emacs-27.1
```
## Native-Comp
To build a Emacs.app with native-comp support
([gccemacs](https://akrl.sdf.org/gccemacs.html)) from the `feature/native-comp`
branch, you will need to install a patched version of Homebrew's `gcc` formula
that includes libgccjit.
The patch itself is in `./Formula/gcc.rb.patch`, and comes from
[this](https://gist.github.com/mikroskeem/0a5c909c1880408adf732ceba6d3f9ab#1-gcc-with-libgccjit-enabled)
gist.
You can install the patched formula by running the helper script:
```
./install-patched-gcc
```
The helper script will copy your local `gcc.rb` Forumla from Homebrew to
`./Formula`, and apply the `./Formula/gcc.rb.patch` to it. After which it then
proceed to install the patched gcc formula which includes libgccjit.
As it requires installing and compiling GCC from source, it can take anywhere
between 30-60 minutes or more depending on your machine.
And finally to build a Emacs.app with native compilation enabled, run:
```
./build-emacs-for-macos feature/native-comp
```
By default `NATIVE_FAST_BOOT` is enabled which ensures a fast build by native
compiling as few lisp source files as possible to build the app. Any remaining
lisp files will be dynamically compiled in the background the first time you use
them.
On my machine it takes around 10-15 minutes to build Emacs.app with
`NATIVE_FAST_BOOT` enabled. With it disabled it takes around 25 minutes.
### Configuration
Add the following near the top of your `early-init.el` or `init.el`:
```elisp
(setq comp-speed 2)
```
By default natively compiled `*.eln` files will be cached in
`~/.emacs.d/eln-cache/`. If you want to customize that, simply add a new path as
the first element to the `comp-eln-load-path` variable. The path string must end
with a `/`.
For example, to cache them into `cache/eln-cache` within your Emacs
configuration directory, you can do something like this:
```elisp
(when (boundp 'comp-eln-load-path)
(add-to-list 'comp-eln-load-path
(expand-file-name "cache/eln-cache/" user-emacs-directory)))
```
### Issues (as of 2020-08-19)
After the changes in [Update 11](https://akrl.sdf.org/gccemacs.html#org4b11ea1)
to gccemacs, the native `*.eln` files are cached with a hash. This hash seems to
be in part based on the absolute file path of the lisp file in question. As
Emacs.app is self-contained, the absolute path as build time and will not be the
same as once it's installed into `/Applications`.
This means that all the natively compiled `*.eln` files bundled into Emacs.app
will not be used, and instead all lisp sources will be natively compiled and
cached in the the user cache (`~/.emacs.d/eln-cache/` by default). Native
compilation status can be viewed in the `*Async-native-compile-log*` buffer.
Because of this, `NATIVE_FAST_BOOT` is enabled by default ensuring as fast a
build as possible, with as little native compilation as possible on build time.
## Credits
- I've borrowed some ideas from [David Caldwell](https://github.com/caldwell)'s
excellent [build-emacs](https://github.com/caldwell/build-emacs) project,
which produces all builds for
[emacsformacosx.com](https://emacsformacosx.com).
- Patches applied are pulled from
[emacs-plus](https://github.com/d12frosted/homebrew-emacs-plus), which is an
excellent Homebrew formula with lots of options not available elsewhere.
- The following sources were extremely useful in figuring out how get get the
`feature/native-comp` branch building on macOS:
- https://gist.github.com/mikroskeem/0a5c909c1880408adf732ceba6d3f9ab#1-gcc-with-libgccjit-enabled
- https://github.com/shshkn/emacs.d/blob/master/docs/nativecomp.md
- https://gist.github.com/AllenDang/f019593e65572a8e0aefc96058a2d23e
## Internals
The script downloads the source code as a gzipped tar archive from the
[GitHub mirror](https://github.com/emacs-mirror/emacs) repository, as it makes
it very easy to get a tarball of any given git reference.
It then runs `./configure` with a various options, including copying various
dynamic libraries into the application itself. So the built application should
in theory run on a macOS install that does not have Homebrew, or does not have
the relevant Homebrew formulas installed.
Code quality of the script itself, is well, non-existent. The build script
started life a super-quick hack back in 2013, and now it's even more of a dirty
hack. I might clean it up and add unit tests if I end up relying on this script
for a prolonged period of time. For now I plan to use it at least until
native-comp lands in a stable Emacs release for macOS.
## License
[CC0 1.0 Universal](http://creativecommons.org/publicdomain/zero/1.0/)