Compare commits

...

4 Commits
0.3.0 ... 0.4.0

Author SHA1 Message Date
be8e04e7a5 chore(release): 0.4.0 2020-10-04 16:15:11 +01:00
aadf32cbbe Merge pull request #17 from jimeh/support-libgccjit-homebrew-formula
feat(native_comp)!: use new libgccjit Homebrew formula
2020-10-04 16:14:38 +01:00
d8bbcb72b3 feat(native_comp)!: use new libgccjit Homebrew formula
The new libgccjit Homebrew formula negates the need to install a custom
patched gcc formula from source to get libgccjit.

As it's a separate formula, the file structure is a bit different
though, requiring some changes to the script. This means it is no longer
compatible libgccjit from the custom gcc formula. If you already have
the custom patched gcc formula installed, you can replace it with the
standard gcc formula by running:

    brew reinstall gcc

In theory though, it should work even with the patched gcc formula, as
long as libgccjit is installed too. But it will probably produce a
Emacs.app that's around 35MB larger than it needs to, thanks to
duplicating the libgccjit.so.0.0.1 file within the final application.

BREAKING CHANGE: Standard Homewbrew `gcc` and `libgccjit` formula are now required for native-comp, instead of the custom patched gcc formula.
2020-10-04 15:12:41 +01:00
d6f11b5459 docs(readme): update usage section 2020-09-23 00:49:14 +01:00
7 changed files with 74 additions and 99 deletions

View File

@@ -3,11 +3,13 @@
brew 'coreutils' brew 'coreutils'
brew 'curl' brew 'curl'
brew 'expat' brew 'expat'
brew 'gcc'
brew 'gmp' brew 'gmp'
brew 'gnu-sed' brew 'gnu-sed'
brew 'gnutls' brew 'gnutls'
brew 'jansson' brew 'jansson'
brew 'libffi' brew 'libffi'
brew 'libgccjit'
brew 'libiconv' brew 'libiconv'
brew 'librsvg' brew 'librsvg'
brew 'libtasn1' brew 'libtasn1'

View File

@@ -2,6 +2,17 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [0.4.0](https://github.com/jimeh/build-emacs-for-macos/compare/0.3.0...0.4.0) (2020-10-04)
### ⚠ BREAKING CHANGES
* **native_comp:** Standard Homewbrew `gcc` and `libgccjit` formula are now required for native-comp, instead of the custom patched gcc formula.
### Features
* **native_comp:** use new libgccjit Homebrew formula ([d8bbcb7](https://github.com/jimeh/build-emacs-for-macos/commit/d8bbcb72b33f6bde8678c9d37548217ffdf3d641))
## [0.3.0](https://github.com/jimeh/build-emacs-for-macos/compare/0.2.0...0.3.0) (2020-09-22) ## [0.3.0](https://github.com/jimeh/build-emacs-for-macos/compare/0.2.0...0.3.0) (2020-09-22)

View File

@@ -1,21 +0,0 @@
diff --git a/Formula/gcc.rb b/Formula/gcc.rb
index 1bd636d496..03ad124218 100644
--- a/Formula/gcc.rb
+++ b/Formula/gcc.rb
@@ -53,7 +53,7 @@ class Gcc < Formula
# - Ada, which requires a pre-existing GCC Ada compiler to bootstrap
# - Go, currently not supported on macOS
# - BRIG
- languages = %w[c c++ objc obj-c++ fortran]
+ languages = %w[c c++ objc obj-c++ fortran jit]
osmajor = `uname -r`.split(".").first
pkgversion = "Homebrew GCC #{pkg_version} #{build.used_options*" "}".strip
@@ -73,6 +73,7 @@ class Gcc < Formula
--with-system-zlib
--with-pkgversion=#{pkgversion}
--with-bugurl=https://github.com/Homebrew/homebrew-core/issues
+ --enable-host-shared
]
# Xcode 10 dropped 32-bit support

View File

@@ -18,7 +18,7 @@ Use this script at your own risk.
## Status ## Status
As of writing (2020-08-19) it works for me on my machine. Your luck may vary. As of writing (2020-10-04) it works for me on my machine. Your luck may vary.
I have successfully built: I have successfully built:
@@ -30,7 +30,7 @@ For reference, my machine is:
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t) - 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
- macOS 10.15.6 (19G2021) - macOS 10.15.6 (19G2021)
- Xcode 11.7 - Xcode 12.0
## Limitations ## Limitations
@@ -76,11 +76,11 @@ Options:
--[no-]native-full-aot Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation (default: disabled) --[no-]native-full-aot Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation (default: disabled)
--[no-]native-comp-macos-fixes --[no-]native-comp-macos-fixes
Enable/disable fix based on feature/native-comp-macos-fixes branch (default: enabled if native-comp supported) Enable/disable fix based on feature/native-comp-macos-fixes branch (default: enabled if native-comp supported)
--[no-]launcher Enable/disable embedded launcher script (default: enabled if native-comp is enabled)
--rsvg Enable SVG image support via librsvg, can yield a unstable build (default: disabled) --rsvg Enable SVG image support via librsvg, can yield a unstable build (default: disabled)
--no-titlebar Apply no-titlebar patch (default: disabled) --no-titlebar Apply no-titlebar patch (default: disabled)
--no-frame-refocus Apply no-frame-refocus patch (default: disabled) --no-frame-refocus Apply no-frame-refocus patch (default: disabled)
--[no-]native-fast-boot DEPRECATED: use --[no-]native-full-aot instead --[no-]native-fast-boot DEPRECATED: use --[no-]native-full-aot instead
--[no-]launcher DEPRECATED: Launcher script is no longer used.
``` ```
Resulting applications are saved to the `builds` directory in a bzip2 compressed Resulting applications are saved to the `builds` directory in a bzip2 compressed
@@ -89,6 +89,9 @@ tarball.
If you don't want the build process to eat all your CPU cores, pass in a `-j` 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. value of how many CPU cores you want it to use.
Re-building the same Git SHA again can yield weird results unless you first
trash the corresponding directory from the `sources` directory.
### Examples ### Examples
To download a tarball of the `master` branch (Emacs 28.x as of writing) and To download a tarball of the `master` branch (Emacs 28.x as of writing) and
@@ -111,29 +114,16 @@ repository.
## Native-Comp ## Native-Comp
To build a Emacs.app with native-comp support Building a Emacs.app with native-comp support
([gccemacs](https://akrl.sdf.org/gccemacs.html)) from the `feature/native-comp` ([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 branch is now supported without much hassle thanks to the newly released
that includes libgccjit. `libgccjit` Homebrew formula.
The patch itself is in `./Formula/gcc.rb.patch`, and comes from Changes from the `feature/native-comp-macos-fixes` branch are also applied
[this](https://gist.github.com/mikroskeem/0a5c909c1880408adf732ceba6d3f9ab#1-gcc-with-libgccjit-enabled) through a custom patch process which should be more future-proof compared to a
gist. regular git diff patch.
You can install the patched formula by running the helper script: To build a Emacs.app with native compilation enabled, simply run:
```
./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 ./build-emacs-for-macos feature/native-comp
@@ -142,7 +132,7 @@ And finally to build a Emacs.app with native compilation enabled, run:
By default `NATIVE_FULL_AOT` is disabled which ensures a fast build by native By default `NATIVE_FULL_AOT` is disabled which ensures a fast build by native
compiling as few lisp source files as possible to build the app. Any remaining 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 lisp files will be dynamically compiled in the background the first time you use
them. them. To enable native full AoT, pass in the `--native-full-aot` option.
On my machine it takes around 10 minutes to build Emacs.app with On my machine it takes around 10 minutes to build Emacs.app with
`NATIVE_FULL_AOT` disabled. With it enabled it takes around 20-25 minutes. `NATIVE_FULL_AOT` disabled. With it enabled it takes around 20-25 minutes.

View File

@@ -99,7 +99,7 @@ class Build
symlink_internals(app) symlink_internals(app)
LibEmbedder.new(app, brew_dir, extra_libs).embed LibEmbedder.new(app, brew_dir, extra_libs).embed
LibGccJitEmbedder.new(app, gcc_dir).embed if options[:native_comp] GccLibEmbedder.new(app, gcc_dir).embed if options[:native_comp]
archive_app(app) archive_app(app)
end end
@@ -126,6 +126,10 @@ class Build
@gcc_dir ||= `brew --prefix gcc`.chomp @gcc_dir ||= `brew --prefix gcc`.chomp
end end
def libgccjit_dir
@libgccjit_dir ||= `brew --prefix libgccjit`.chomp
end
def extra_libs def extra_libs
@extra_libs ||= [ @extra_libs ||= [
"#{brew_dir}/opt/expat/lib/libexpat.1.dylib", "#{brew_dir}/opt/expat/lib/libexpat.1.dylib",
@@ -139,7 +143,7 @@ class Build
url = (DOWNLOAD_URL % sha) url = (DOWNLOAD_URL % sha)
filename = "emacs-mirror-emacs-#{sha[0..6]}.tgz" filename = "emacs-mirror-emacs-#{sha[0..6]}.tgz"
target = File.join(tarballs_dir, filename) target = File.join(tarballs_dir, filename)
if File.exist?(target) if File.exist?(target)
info "#{filename} already exists locally, attempting to use." info "#{filename} already exists locally, attempting to use."
@@ -204,17 +208,25 @@ class Build
def verify_libgccjit def verify_libgccjit
err 'gcc not installed' unless Dir.exist?(gcc_dir) err 'gcc not installed' unless Dir.exist?(gcc_dir)
err 'libgccjit not installed' unless Dir.exist?(libgccjit_dir)
return if Dir["#{gcc_dir}/lib/**/libgccjit.so*"].any? if Dir["#{libgccjit_dir}/lib/**/libgccjit.so*"].empty?
err "Detected libgccjit (#{libgccjit_dir}) does not have any " \
'libgccjit.so* files. Please try reinstalling libgccjit: ' \
'brew reinstall libgccjit'
end
err "Detected GCC (#{gcc_dir}) does not have libgccjit. Ensure patched " \ dirs = Dir["{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*"]
'gcc brew formula has been installed via ./install-patched-gcc' return if dirs.map { |dir| File.basename(dir) }.uniq == %w[10]
err 'Detected gcc and libgccjit library paths do not belong to the ' \
"same major version. Detected paths:\n - #{dirs.join(' - ')}"
end end
def gcc_library_paths def gcc_library_paths
@gcc_library_paths ||= Dir[ @gcc_library_paths ||= Dir[
"#{gcc_dir}/lib/gcc/*", "{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*",
"#{gcc_dir}/lib/gcc/*/gcc/*apple-darwin*/*" "{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*/gcc/*apple-darwin*/*"
].sort_by { |p| [p.size, p] } ].sort_by { |p| [p.size, p] }
end end
@@ -260,7 +272,8 @@ class Build
ENV['LDFLAGS'] = [ ENV['LDFLAGS'] = [
gcc_library_paths.map { |path| "-L#{path}" }, gcc_library_paths.map { |path| "-L#{path}" },
"-I#{gcc_dir}/include" "-I#{gcc_dir}/include",
"-I#{libgccjit_dir}/include"
].flatten.compact.join(' ') ].flatten.compact.join(' ')
ENV['LIBRARY_PATH'] = [ ENV['LIBRARY_PATH'] = [
@@ -365,10 +378,10 @@ class Build
] ]
filename = "Emacs.app-[#{metadata.join('][')}].tbz" filename = "Emacs.app-[#{metadata.join('][')}].tbz"
target = "#{builds_dir}/#{filename}" target = "#{builds_dir}/#{filename}"
app_base = File.basename(app) app_base = File.basename(app)
app_dir = File.dirname(app) app_dir = File.dirname(app)
if !File.exist?(target) if !File.exist?(target)
info "Creating #{filename} archive in \"#{builds_dir}\"..." info "Creating #{filename} archive in \"#{builds_dir}\"..."
@@ -587,7 +600,7 @@ class AbstractEmbedder
end end
def lib_dir_name def lib_dir_name
"lib-#{OS.arch}-#{OS.version.to_s.tr('.', '_')}" 'lib'
end end
end end
@@ -700,7 +713,7 @@ class LibEmbedder < AbstractEmbedder
end end
end end
class LibGccJitEmbedder < AbstractEmbedder class GccLibEmbedder < AbstractEmbedder
attr_reader :gcc_dir attr_reader :gcc_dir
def initialize(app, gcc_dir) def initialize(app, gcc_dir)
@@ -721,6 +734,7 @@ class LibGccJitEmbedder < AbstractEmbedder
FileUtils.mkdir_p(File.dirname(target_dir)) FileUtils.mkdir_p(File.dirname(target_dir))
FileUtils.cp_r(source_dir, target_dir) FileUtils.cp_r(source_dir, target_dir)
FileUtils.rm(Dir[File.join(target_dir, '**', '.DS_Store')], force: true)
end end
private private
@@ -734,13 +748,10 @@ class LibGccJitEmbedder < AbstractEmbedder
end end
def gcc_version def gcc_version
@gcc_version ||= Dir[File.join(gcc_dir, 'lib', 'gcc', '*', 'libgccjit.so*')] @gcc_version ||= Dir[File.join(gcc_dir, 'lib', 'gcc', '*', 'libgcc*')]
.map { |path| File.dirname(path) } .map { |path| File.basename(File.dirname(path)) }
.select { |path| path.match(%r{/\d+$}) } .select { |path| path.match(/^\d+$/) }
.uniq .uniq.map(&:to_i).max.to_s
.map { |dir| File.basename(dir).to_i }
.max
.to_s
end end
def source_dir def source_dir

View File

@@ -1,27 +0,0 @@
#! /usr/bin/env bash
set -e
brewdir="$(brew --prefix)"
formula="${brewdir}/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/gcc.rb"
if [ ! -f "$formula" ]; then
echo "ERROR: ${formula} does not exist." 1>&2
exit 1
fi
gnubins=(
"${brewdir}/opt/coreutils/libexec/gnubin"
"${brewdir}/opt/make/libexec/gnubin"
"${brewdir}/opt/gnu-sed/libexec/gnubin"
)
for gnubin in "${gnubins[@]}"; do
if [ -d "$gnubin" ]; then
export PATH="${gnubin}:$PATH"
fi
done
cp "$formula" ./Formula/
patch -f -p1 -i ./Formula/gcc.rb.patch
brew install ./Formula/gcc.rb --build-from-source --force

View File

@@ -1,8 +1,8 @@
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 25e2de9..14ee6dc 100644 index 25e2de9..bcedd31 100644
--- a/lisp/emacs-lisp/comp.el --- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el
@@ -2801,6 +2801,36 @@ queued with LOAD %" @@ -2801,6 +2801,45 @@ queued with LOAD %"
(comp-run-async-workers) (comp-run-async-workers)
(message "Compilation started.")))) (message "Compilation started."))))
@@ -13,15 +13,24 @@ index 25e2de9..14ee6dc 100644
+ (string-match-p "\.app\/Contents\/MacOS\/?$" + (string-match-p "\.app\/Contents\/MacOS\/?$"
+ invocation-directory)) + invocation-directory))
+ (let* ((library-path-env (getenv "LIBRARY_PATH")) + (let* ((library-path-env (getenv "LIBRARY_PATH"))
+ (gcc-dir (car (file-expand-wildcards + (gcc-base-dir (concat invocation-directory "lib/gcc"))
+ (concat invocation-directory "lib-*/gcc/*")))) + (gcc-version (car (seq-filter
+ (gcc-darwin-dir (car (file-expand-wildcards + (lambda (dir) (string-match-p "^[0-9]+$" dir))
+ (concat gcc-dir "/gcc/*apple-darwin*/*")))) + (directory-files gcc-base-dir))))
+ (gcc-dir (concat gcc-base-dir "/" gcc-version))
+ (darwin-base-dir (car (file-expand-wildcards
+ (concat gcc-dir "/gcc/*apple-darwin*"))))
+ (darwin-version (car (seq-filter
+ (lambda (dir)
+ (string-match-p
+ "^[0-9]+\\(\.[0-9]+\\(\.[0-9]+\\)?\\)?$" dir))
+ (directory-files darwin-base-dir))))
+ (darwin-dir (concat darwin-base-dir "/" darwin-version))
+ (lib-paths (append + (lib-paths (append
+ (list gcc-dir gcc-darwin-dir) + (list gcc-dir darwin-dir)
+ (if library-path-env (list library-path-env) (list))))) + (if library-path-env (list library-path-env) (list)))))
+ +
+ (when (and gcc-dir gcc-darwin-dir) + (when (and gcc-dir darwin-dir)
+ (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":"))))) + (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":")))))
+ +
+ ;; Remove advice, as it only needs to run once. + ;; Remove advice, as it only needs to run once.