mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
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).
This commit is contained in:
96
README.md
96
README.md
@@ -18,7 +18,7 @@ Use this script at your own risk.
|
||||
|
||||
## Status
|
||||
|
||||
As of writing (2020-08-18) it works for me on my machine. Your luck may vary.
|
||||
As of writing (2020-08-19) it works for me on my machine. Your luck may vary.
|
||||
|
||||
I have successfully built:
|
||||
|
||||
@@ -28,8 +28,7 @@ I have successfully built:
|
||||
|
||||
For reference, my machine is:
|
||||
|
||||
- 13-inch MacBook Pro (2020)
|
||||
- 10th Gen i7, 2.3 GHz 4-core/8-thread CPU
|
||||
- 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
|
||||
|
||||
@@ -60,34 +59,33 @@ The build produced does have some limitations:
|
||||
```
|
||||
Usage: ./build-emacs-for-macos [options] <branch/tag/sha>
|
||||
|
||||
Branch, tag, and SHA are from the mirrors/emacs Github repo,
|
||||
available here: https://github.com/mirrors/emacs
|
||||
-j, --parallel PROCS Compile in parallel using PROCS processes
|
||||
-x, --xwidgets Apply XWidgets patch for Emacs 27
|
||||
--native-comp Enable native-comp
|
||||
--native-fast-boot Only relevant with --native-comp
|
||||
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.
|
||||
|
||||
I would typically recommend to pass a `-j` value equal to the number of CPU
|
||||
threads your machine has to ensure a fast build. In the below examples I'll be
|
||||
using `-j 4`.
|
||||
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), build Emacs.app from
|
||||
it:
|
||||
To download a tarball of the `master` branch (Emacs 28.x) and build Emacs.app
|
||||
from it:
|
||||
|
||||
```
|
||||
./build-emacs-for-macos -j 4
|
||||
./build-emacs-for-macos
|
||||
```
|
||||
|
||||
To build the stable `emacs-27.1` release git tag, with XWidgets support, run:
|
||||
To build the stable `emacs-27.1` release git tag run:
|
||||
|
||||
```
|
||||
./build-emacs-for-macos -j 4 --xwidgets emacs-27.1
|
||||
./build-emacs-for-macos emacs-27.1
|
||||
```
|
||||
|
||||
## Native-Comp
|
||||
@@ -117,28 +115,66 @@ 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 -j 4 --native-comp feature/native-comp
|
||||
./build-emacs-for-macos feature/native-comp
|
||||
```
|
||||
|
||||
On my machine with `-j 8` this takes around 20-25 minutes. The increased build
|
||||
time is cause all lisp files in the app are compiled to native `*.eln` files.
|
||||
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.
|
||||
|
||||
The build time can be sped up by using `--native-fast-boot`, which compiles a
|
||||
minimal required set of lisp files to native code during build, and will compile
|
||||
the rest dynamically in the background as they get loaded while you're using
|
||||
Emacs.
|
||||
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 and in general used
|
||||
[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).
|
||||
- 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 gists were all extremely useful in figuring out how get get
|
||||
native-comp building on macOS:
|
||||
- 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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'date'
|
||||
require 'etc'
|
||||
require 'fileutils'
|
||||
require 'json'
|
||||
require 'optparse'
|
||||
@@ -112,13 +113,31 @@ class Build
|
||||
target
|
||||
end
|
||||
|
||||
def configure_help
|
||||
@configure_help ||= `./configure --help`
|
||||
end
|
||||
|
||||
def supports_native_comp?
|
||||
@supports_native_comp ||= configure_help.match?(/\s+--with-nativecomp\s+/)
|
||||
end
|
||||
|
||||
def supports_xwidgets?
|
||||
@supports_xwidgets ||= configure_help.match?(/\s+--with-xwidgets\s+/)
|
||||
end
|
||||
|
||||
def detect_native_comp
|
||||
return if `./configure --help | grep -- '--with-nativecomp'`.strip != ''
|
||||
print 'Detecting native-comp support: '
|
||||
options[:native_comp] = supports_native_comp?
|
||||
puts options[:native_comp] ? 'Supported' : 'Not supported'
|
||||
end
|
||||
|
||||
def verify_native_comp
|
||||
return if supports_native_comp?
|
||||
|
||||
err 'This emacs source tree does not support native-comp'
|
||||
end
|
||||
|
||||
def detect_libgccjit
|
||||
def verify_libgccjit
|
||||
err 'gcc not installed' unless Dir.exist?(gcc_dir)
|
||||
|
||||
return if Dir["#{gcc_dir}/lib/**/libgccjit.so*"].any?
|
||||
@@ -146,9 +165,11 @@ class Build
|
||||
run_cmd './autogen.sh'
|
||||
end
|
||||
|
||||
detect_native_comp if options[:native_comp].nil?
|
||||
if options[:native_comp]
|
||||
detect_native_comp
|
||||
detect_libgccjit
|
||||
puts 'Compiling with native-comp enabled'
|
||||
verify_native_comp
|
||||
verify_libgccjit
|
||||
|
||||
ENV['NATIVE_FAST_BOOT'] = '1' if options[:native_fast_boot]
|
||||
ENV['CFLAGS'] = [
|
||||
@@ -194,14 +215,11 @@ class Build
|
||||
'/Library/Application Support/Emacs/${version}/site-lisp:' \
|
||||
'/Library/Application Support/Emacs/site-lisp'
|
||||
]
|
||||
configure_flags << '--with-xwidgets' if options[:xwidgets]
|
||||
configure_flags << '--with-xwidgets' if supports_xwidgets?
|
||||
configure_flags << '--with-nativecomp' if options[:native_comp]
|
||||
|
||||
make_flags = []
|
||||
make_flags += ['-j', options[:parallel]] if options[:parallel]
|
||||
if options[:native_comp]
|
||||
make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'"
|
||||
end
|
||||
make_flags += ['-j', options[:parallel].to_s] if options[:parallel]
|
||||
|
||||
run_cmd './configure', *configure_flags
|
||||
|
||||
@@ -212,12 +230,24 @@ class Build
|
||||
disable_alligned_alloc
|
||||
end
|
||||
|
||||
if options[:native_comp]
|
||||
make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'"
|
||||
end
|
||||
|
||||
run_cmd 'make', *make_flags
|
||||
run_cmd 'make', 'install'
|
||||
end
|
||||
|
||||
err 'Build failed.' unless File.exist?(emacs_app)
|
||||
|
||||
if options[:native_comp]
|
||||
FileUtils.cd(File.join(emacs_app, 'Contents')) do
|
||||
FileUtils.ln_s('Resources/lisp', 'lisp')
|
||||
dir = Dir['MacOS/libexec/emacs/**/eln-cache'].first
|
||||
FileUtils.ln_s(dir, 'eln-cache')
|
||||
end
|
||||
end
|
||||
|
||||
emacs_app
|
||||
end
|
||||
|
||||
@@ -299,8 +329,8 @@ class Build
|
||||
system(*args) || exit($CHILD_STATUS.exitstatus)
|
||||
end
|
||||
|
||||
def patch_version
|
||||
@patch_version ||= begin
|
||||
def effective_version
|
||||
@effective_version ||= begin
|
||||
case ref
|
||||
when /^emacs-27.*/
|
||||
'emacs-27'
|
||||
@@ -313,21 +343,21 @@ class Build
|
||||
def patches(opts = {})
|
||||
p = []
|
||||
|
||||
if patch_version
|
||||
if opts[:xwidgets] && patch_version == 'emacs-27'
|
||||
if effective_version
|
||||
if opts[:xwidgets] && effective_version == 'emacs-27'
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{patch_version}/xwidgets_webkit_in_cocoa.patch"
|
||||
"patches/#{effective_version}/xwidgets_webkit_in_cocoa.patch"
|
||||
}
|
||||
end
|
||||
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{patch_version}/fix-window-role.patch"
|
||||
"patches/#{effective_version}/fix-window-role.patch"
|
||||
}
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{patch_version}/system-appearance.patch"
|
||||
"patches/#{effective_version}/system-appearance.patch"
|
||||
}
|
||||
end
|
||||
|
||||
@@ -492,30 +522,42 @@ class LibEmbedder
|
||||
end
|
||||
|
||||
if __FILE__ == $PROGRAM_NAME
|
||||
cli_options = {}
|
||||
cli_options = {
|
||||
native_fast_boot: true,
|
||||
parallel: Etc.nprocessors,
|
||||
xwidgets: true
|
||||
}
|
||||
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = <<~DOC
|
||||
Usage: ./build-emacs-for-macos [options] <branch/tag/sha>
|
||||
|
||||
Branch, tag, and SHA are from the mirrors/emacs Github repo,
|
||||
available here: https://github.com/mirrors/emacs
|
||||
Branch, tag, and SHA are from the emacs-mirror/emacs/emacs Github repo,
|
||||
available here: https://github.com/emacs-mirror/emacs
|
||||
DOC
|
||||
|
||||
opts.on('-j', '--parallel PROCS',
|
||||
'Compile in parallel using PROCS processes') do |v|
|
||||
opts.on('-j', '--parallel COUNT',
|
||||
'Compile using COUNT parallel processes ' \
|
||||
"(detected: #{cli_options[:parallel]})") do |v|
|
||||
cli_options[:parallel] = v
|
||||
end
|
||||
|
||||
opts.on('-x', '--xwidgets', 'Apply XWidgets patch for Emacs 27') do
|
||||
cli_options[:xwidgets] = true
|
||||
opts.on('--[no-]xwidgets',
|
||||
'Enable/disable XWidgets ' \
|
||||
'(default: enabled)') do |v|
|
||||
cli_options[:xwidgets] = v
|
||||
end
|
||||
|
||||
opts.on('--native-comp', 'Enable native-comp') do
|
||||
cli_options[:native_comp] = true
|
||||
opts.on('--[no-]native-comp',
|
||||
'Enable/disable native-comp ' \
|
||||
'(default: enabled if supported)') do |v|
|
||||
cli_options[:native_comp] = v
|
||||
end
|
||||
|
||||
opts.on('--native-fast-boot', 'Only relevant with --native-comp') do
|
||||
cli_options[:native_fast_boot] = true
|
||||
opts.on('--[no-]native-fast-boot',
|
||||
'Enable/disable NATIVE_FAST_BOOT ' \
|
||||
'(default: enabled if native-comp supported)') do |v|
|
||||
cli_options[:native_fast_boot] = v
|
||||
end
|
||||
end.parse!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user