Compare commits

...

28 Commits
0.2.0 ... 0.4.6

Author SHA1 Message Date
03ae8750b8 chore(release): 0.4.6 2021-02-15 11:43:58 +00:00
269dbdb1dd chore(build): use File.join wherever relevant
Ensures paths are correctly joined and no double and/or missing slash
errors can occur.
2021-02-15 11:42:49 +00:00
713c970da4 Merge pull request #30 from jimeh/improve-native-comp-env-setup-patch
fix(native_comp): improve env setup patch fixing potential issues
2021-02-15 11:41:52 +00:00
dca023daec fix(native_comp): improve env setup patch fixing potential issues
The old patch would dynamically glob within
Emacs.app/Contents/MacOS/lib/gcc using the full absolute path to
Emacs.app. If there are obsure characters like "[]" and others in the
absolute path, it can cause glob search within the
native-compile-setup-environment-variables function to fail, in turn
preventing native-comp from working.

The fix is to hard-code the relative paths from Emacs'
invocation-directory (**/Emacs.app/Contents/MacOS) into the environment
setup function itself, making it very simple and effectively just
joining a few strings and setting an environment variable.

It did require a little bit of cleanup and better organization of the
GCC/libgccjit releated code in the build script, creating a new GccInfo
class which is the central place for determining various paths and
information about GCC and libgccjit which the build will be using.
2021-02-15 09:49:47 +00:00
e56c26d06f docs(readme): update status section 2021-01-15 02:01:13 +00:00
b2860f22c3 chore(deps): add rubocop-daemon and solargraph to Gemfile 2021-01-15 02:00:46 +00:00
d1c5e7afb1 chore(release): 0.4.5 2021-01-06 20:32:30 +00:00
ab55f5421c fix(cli): remove defunct --[no-]native-comp-macos-fixes option
The underlying patching code was removed in v0.4.1 (commit
70bf6b05d5), as it was no longer needed,
but the related CLI flag and README info was mistakenly left in place.
2021-01-06 20:31:31 +00:00
eb09d5fa49 chore(release): 0.4.4 2021-01-02 14:01:37 +00:00
a47d3e0c6a fix(deps): add autoconf to Brewfile
On a fresh install of Big Sur with only the Xcode CLI tools installed,
autoconf is not available. Hence it needs to be installed from homebrew
instead.
2021-01-02 14:00:49 +00:00
5a61a72a73 chore(release): 0.4.3 2020-12-28 11:47:11 +00:00
9cdf67e71b Merge pull request #26 from jimeh/fix-big-sur
fix(big-sur): resolve issues with building and native-comp on Big Sur
2020-12-28 11:42:45 +00:00
946856e9c2 fix(big-sur): add Xcode CLI tools lib directory to runtime LIBRARY_PATH 2020-12-25 15:59:53 +00:00
claford-v-lawrence
2247158051 fix(big-sur): added support for building on Big Sur
Curtsy of https://apple.stackexchange.com/questions/408999/gfortran-compiler-error-on-mac-os-big-sur
2020-12-25 15:59:47 +00:00
4a7c507858 chore(release): 0.4.2 2020-12-09 23:58:00 +00:00
884f1607f6 fix(cli): avoid error if --git-sha is used without a branch/tag/sha argument
Fixes #21
2020-12-09 23:57:51 +00:00
c7daa1350b fix(native_comp): update env setup patch for recent changes to comp.el 2020-12-09 23:35:23 +00:00
9223ff8e28 chore(release): 0.4.1 2020-10-29 10:38:07 +00:00
70bf6b05d5 feat(native_comp): remove patch based on feature/native-comp-macos-fixes branch
Based on comparing two Emacs.app builds, one with and one without the
patch, it seems to have no effect at all on the contents of Emacs.app.
2020-10-29 10:35:18 +00:00
8936f4762a docs(readme): add CLI usage instructions
Resolves #16
2020-10-04 16:33:25 +01:00
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
09e67381cb chore(release): 0.3.0 2020-09-22 20:29:06 +01:00
d21ccad3e4 docs(readme): update custom eln cache location instructions
Recent builds seem to pre-allocate empty `*.eln.tmp` files rather than
empty `*.eln` files. So the issue of empty `*.eln` files preventing
Emacs from starting should no longer be an issue.

I'm leaving #3 open for now, in case anyone is using older git SHAs from
the list of known good commits in #6.
2020-09-22 20:28:49 +01:00
036d2a82d9 Merge pull request #15 from jimeh/setup-library-path-with-elisp
feat(native_comp)!: use elisp patch instead of launcher script to set LIBRARY_PATH
2020-09-22 20:06:23 +01:00
111cb64993 feat(native_comp)!: use elisp patch instead of launcher script to set LIBRARY_PATH
Replace the launcher script with a emacs-lisp patch to `comp.el` which
sets the `LIBRARY_PATH` environment variable to point at the embedded
GCC/libgccjit.

This fixes issues related to the launcher script on macOS 10.15 and
later.

Fixes #14
BREAKING CHANGE: `--[no-]launcher` option is deprecated, as launcher script is no longer used.
2020-09-22 20:03:17 +01:00
9 changed files with 330 additions and 331 deletions

View File

@@ -1,13 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
brew 'autoconf'
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,72 @@
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.6](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.5...0.4.6) (2021-02-15)
### Bug Fixes
* **native_comp:** improve env setup patch fixing potential issues ([dca023d](https://github.com/jimeh/build-emacs-for-macos/commit/dca023daecd8704f197cbc391380aa194bc47d62))
### [0.4.5](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.4...0.4.5) (2021-01-06)
### Bug Fixes
* **cli:** remove defunct --[no-]native-comp-macos-fixes option ([ab55f54](https://github.com/jimeh/build-emacs-for-macos/commit/ab55f5421c81dc629e487bf4b8bb402657cb1bc4))
### [0.4.4](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.3...0.4.4) (2021-01-02)
### Bug Fixes
* **deps:** add autoconf to Brewfile ([a47d3e0](https://github.com/jimeh/build-emacs-for-macos/commit/a47d3e0c6a8ea8161a3bad0eafdac2401cf53129))
### [0.4.3](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.2...0.4.3) (2020-12-28)
### Bug Fixes
* **big-sur:** add Xcode CLI tools lib directory to runtime LIBRARY_PATH ([946856e](https://github.com/jimeh/build-emacs-for-macos/commit/946856e9c242d4a6fb5f839d8cae0acfafecdfc6))
* **big-sur:** added support for building on Big Sur ([2247158](https://github.com/jimeh/build-emacs-for-macos/commit/2247158051d0f59933569b6974b2b5269f13c79e))
### [0.4.2](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.1...0.4.2) (2020-12-09)
### Bug Fixes
* **cli:** avoid error if --git-sha is used without a branch/tag/sha argument ([884f160](https://github.com/jimeh/build-emacs-for-macos/commit/884f1607f6707ca187b1abfb0ce562757d872230)), closes [#21](https://github.com/jimeh/build-emacs-for-macos/issues/21)
* **native_comp:** update env setup patch for recent changes to comp.el ([c7daa13](https://github.com/jimeh/build-emacs-for-macos/commit/c7daa1350bd69df172ce6484c54189d2cee8d97e))
### [0.4.1](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.0...0.4.1) (2020-10-29)
### Features
* **native_comp:** remove patch based on feature/native-comp-macos-fixes branch ([70bf6b0](https://github.com/jimeh/build-emacs-for-macos/commit/70bf6b05d584976632b2fd2947c0bf692f5b6421))
## [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)
### ⚠ BREAKING CHANGES
* **native_comp:** `--[no-]launcher` option is deprecated, as launcher script is no longer used.
### Features
* **native_comp:** use elisp patch instead of launcher script to set LIBRARY_PATH ([111cb64](https://github.com/jimeh/build-emacs-for-macos/commit/111cb6499368d14853a5927d38a43fc5e2f759f4)), closes [#14](https://github.com/jimeh/build-emacs-for-macos/issues/14)
## [0.2.0](https://github.com/jimeh/build-emacs-for-macos/compare/0.1.1...0.2.0) (2020-09-20) ## [0.2.0](https://github.com/jimeh/build-emacs-for-macos/compare/0.1.1...0.2.0) (2020-09-20)

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

@@ -5,4 +5,6 @@ source 'http://rubygems.org/'
group :development do group :development do
gem 'byebug' gem 'byebug'
gem 'rubocop' gem 'rubocop'
gem 'rubocop-daemon'
gem 'solargraph', '~> 0.39.17'
end end

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 (2021-01-15) it works for me on my machine. Your luck may vary.
I have successfully built: I have successfully built:
@@ -29,8 +29,8 @@ I have successfully built:
For reference, my machine is: 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 Big Sur 11.1 (20C69)
- Xcode 11.7 - Xcode 12.3 (12C33)
## Limitations ## Limitations
@@ -74,13 +74,11 @@ Options:
--[no-]xwidgets Enable/disable XWidgets (default: enabled if supported) --[no-]xwidgets Enable/disable XWidgets (default: enabled if supported)
--[no-]native-comp Enable/disable native-comp (default: enabled if supported) --[no-]native-comp Enable/disable native-comp (default: enabled if supported)
--[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
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 +87,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
@@ -109,31 +110,38 @@ All sources as downloaded as tarballs from the
to get a list of tags/branches available to install, simply check said to get a list of tags/branches available to install, simply check said
repository. repository.
## Use Self-Contained Emacs.app as `emacs` CLI Tool
As the application bundle is self-contained, the main executable needs to be run
from within the application bundle. This means a simple symlink to
`Emacs.app/Contents/MacOS/Emacs` will not work. Instead the best approach is to
create a shell alias called `emacs` pointing to the right place.
Personally I use something similar to this:
```bash
if [ -f "/Applications/Emacs.app/Contents/MacOS/Emacs" ]; then
export EMACS="/Applications/Emacs.app/Contents/MacOS/Emacs"
alias emacs="$EMACS -nw"
fi
if [ -f "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient" ]; then
alias emacsclient="/Applications/Emacs.app/Contents/MacOS/bin/emacsclient"
fi
```
Setting the `EMACS` variable to the binary path seems to be a good idea, as some
tools seems to use it to figure out the path to Emacs' executable, including
[doom-emacs](https://github.com/hlissner/doom-emacs)' `doom` CLI tool.
## 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 To build a Emacs.app with native compilation enabled, simply run:
[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 ./build-emacs-for-macos feature/native-comp
@@ -142,7 +150,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.
@@ -160,26 +168,13 @@ By default natively compiled `*.eln` files will be cached in
the first element of the `comp-eln-load-path` variable. The path string must end the first element of the `comp-eln-load-path` variable. The path string must end
with a `/`. with a `/`.
Also it seems somewhat common that some `*.eln` files are left behind with a
zero-byte file size if Emacs is quit while async native compilation is in
progress. Such empty files causes errors on startup, and needs to be deleted.
Below is an example which stores all compiled `*.eln` files in `cache/eln-cache` Below is an example which stores all compiled `*.eln` files in `cache/eln-cache`
within your Emacs configuration directory, and also deletes any `*.eln` files in within your Emacs configuration directory:
said directory which have a file size of zero bytes:
```elisp ```elisp
(when (boundp 'comp-eln-load-path) (when (boundp 'comp-eln-load-path)
(let ((eln-cache-dir (expand-file-name "cache/eln-cache/" (setcar comp-eln-load-path
user-emacs-directory)) (expand-file-name "cache/eln-cache/" user-emacs-directory)))
(find-exec (executable-find "find")))
(setcar comp-eln-load-path eln-cache-dir)
;; Quitting emacs while native compilation in progress can leave zero byte
;; sized *.eln files behind. Hence delete such files during startup.
(when find-exec
(call-process find-exec nil nil nil eln-cache-dir
"-name" "*.eln" "-size" "0" "-delete" "-or"
"-name" "*.eln.tmp" "-size" "0" "-delete"))))
``` ```
### Issues ### Issues

View File

@@ -72,17 +72,18 @@ class Build
DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s' DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s'
LATEST_URL = 'https://api.github.com/repos/emacs-mirror/emacs/commits/%s' LATEST_URL = 'https://api.github.com/repos/emacs-mirror/emacs/commits/%s'
NATIVE_COMP_REF_REGEXP = %r{^feature/native-comp}.freeze NATIVE_COMP_REF_REGEXP = %r{^feature/native-comp}.freeze
LAUNCHER_TEMPLATE = './launcher.bash.erb'
attr_reader :root_dir attr_reader :root_dir
attr_reader :source_dir attr_reader :source_dir
attr_reader :ref attr_reader :ref
attr_reader :options attr_reader :options
attr_reader :gcc_info
def initialize(root_dir, ref = 'master', options = {}) def initialize(root_dir, ref = nil, options = {})
@root_dir = root_dir @root_dir = root_dir
@ref = ref @ref = ref
@options = options @options = options
@gcc_info = GccInfo.new
end end
def build def build
@@ -96,16 +97,11 @@ class Build
autogen autogen
detect_native_comp if options[:native_comp].nil? detect_native_comp if options[:native_comp].nil?
if options[:native_comp] && options[:launcher].nil?
options[:launcher] = true
end
app = compile_source(@source_dir) app = compile_source(@source_dir)
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_info).embed if options[:native_comp]
LauncherEmbedder.new(app, LAUNCHER_TEMPLATE).embed if options[:launcher]
archive_app(app) archive_app(app)
end end
@@ -128,15 +124,11 @@ class Build
@brew_dir ||= `brew --prefix`.chomp @brew_dir ||= `brew --prefix`.chomp
end end
def gcc_dir
@gcc_dir ||= `brew --prefix gcc`.chomp
end
def extra_libs def extra_libs
@extra_libs ||= [ @extra_libs ||= [
"#{brew_dir}/opt/expat/lib/libexpat.1.dylib", File.join(brew_dir, 'opt/expat/lib/libexpat.1.dylib'),
"#{brew_dir}/opt/libiconv/lib/libiconv.2.dylib", File.join(brew_dir, 'opt/libiconv/lib/libiconv.2.dylib'),
"#{brew_dir}/opt/zlib/lib/libz.1.dylib" File.join(brew_dir, 'opt/zlib/lib/libz.1.dylib')
] ]
end end
@@ -145,7 +137,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."
@@ -208,20 +200,12 @@ class Build
err 'This emacs source tree does not support native-comp' err 'This emacs source tree does not support native-comp'
end end
def verify_libgccjit
err 'gcc not installed' unless Dir.exist?(gcc_dir)
return if Dir["#{gcc_dir}/lib/**/libgccjit.so*"].any?
err "Detected GCC (#{gcc_dir}) does not have libgccjit. Ensure patched " \
'gcc brew formula has been installed via ./install-patched-gcc'
end
def gcc_library_paths def gcc_library_paths
@gcc_library_paths ||= Dir[ @gcc_library_paths ||= [
"#{gcc_dir}/lib/gcc/*", gcc_info.lib_dir,
"#{gcc_dir}/lib/gcc/*/gcc/*apple-darwin*/*" gcc_info.darwin_lib_dir,
].sort_by { |p| [p.size, p] } gcc_info.libgccjit_lib_dir
]
end end
def autogen def autogen
@@ -250,21 +234,20 @@ class Build
if options[:native_comp] if options[:native_comp]
info 'Compiling with native-comp enabled' info 'Compiling with native-comp enabled'
verify_native_comp verify_native_comp
verify_libgccjit gcc_info.verify_libgccjit
if options[:macos_fixes] && ref != 'feature/native-comp-macos-fixes' apply_native_comp_env_setup_patch(source)
apply_native_comp_macos_fixes
end
ENV['CFLAGS'] = [ ENV['CFLAGS'] = [
"-I#{gcc_dir}/include", "-I#{File.join(gcc_info.root_dir, 'include')}",
'-O2', '-O2',
'-march=native' '-march=native'
].compact.join(' ') ].compact.join(' ')
ENV['LDFLAGS'] = [ ENV['LDFLAGS'] = [
gcc_library_paths.map { |path| "-L#{path}" }, gcc_library_paths.map { |path| "-L#{path}" },
"-I#{gcc_dir}/include" "-I#{File.join(gcc_info.root_dir, 'include')}",
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}"
].flatten.compact.join(' ') ].flatten.compact.join(' ')
ENV['LIBRARY_PATH'] = [ ENV['LIBRARY_PATH'] = [
@@ -275,25 +258,31 @@ class Build
ENV['CC'] = 'clang' ENV['CC'] = 'clang'
ENV['PKG_CONFIG_PATH'] = [ ENV['PKG_CONFIG_PATH'] = [
"#{brew_dir}/lib/pkgconfig", File.join(brew_dir, 'lib/pkgconfig'),
"#{brew_dir}/share/pkgconfig", File.join(brew_dir, 'share/pkgconfig'),
"#{brew_dir}/opt/expat/lib/pkgconfig", File.join(brew_dir, 'opt/expat/lib/pkgconfig'),
"#{brew_dir}/opt/libxml2/lib/pkgconfig", File.join(brew_dir, 'opt/libxml2/lib/pkgconfig'),
"#{brew_dir}/opt/ncurses/lib/pkgconfig", File.join(brew_dir, 'opt/ncurses/lib/pkgconfig'),
"#{brew_dir}/opt/zlib/lib/pkgconfig", File.join(brew_dir, 'opt/zlib/lib/pkgconfig'),
"#{brew_dir}/Homebrew/Library/Homebrew/os/mac/pkgconfig/#{OS.version}", File.join(brew_dir, 'Homebrew/Library/Homebrew/os/mac/pkgconfig',
OS.version.to_s),
ENV['PKG_CONFIG_PATH'] ENV['PKG_CONFIG_PATH']
].compact.join(':') ].compact.join(':')
ENV['PATH'] = [ ENV['PATH'] = [
"#{brew_dir}/opt/make/libexec/gnubin", File.join(brew_dir, 'opt/make/libexec/gnubin'),
"#{brew_dir}/opt/coreutils/libexec/gnubin", File.join(brew_dir, 'opt/coreutils/libexec/gnubin'),
"#{brew_dir}/opt/gnu-sed/libexec/gnubin", File.join(brew_dir, 'opt/gnu-sed/libexec/gnubin'),
"#{brew_dir}/bin", File.join(brew_dir, 'bin'),
"#{brew_dir}/opt/texinfo/bin", File.join(brew_dir, 'opt/texinfo/bin'),
ENV['PATH'] ENV['PATH']
].compact.join(':') ].compact.join(':')
ENV['LIBRARY_PATH'] = [
ENV['LIBRARY_PATH'],
'/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib'
].compact.join(':')
configure_flags = [ configure_flags = [
'--with-ns', '--with-ns',
'--with-modules', '--with-modules',
@@ -361,18 +350,18 @@ class Build
FileUtils.mkdir_p(builds_dir) FileUtils.mkdir_p(builds_dir)
metadata = [ metadata = [
ref.gsub(/\W/, '-'), meta[:ref]&.gsub(/\W/, '-'),
meta[:date], meta[:date],
meta[:sha][0..6], meta[:sha][0..6],
"macOS-#{OS.version}", "macOS-#{OS.version}",
OS.arch OS.arch
] ].compact
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}\"..."
@@ -407,11 +396,13 @@ class Build
err "Failed to get commit info about: #{ref_sha}" if commit_json.nil? err "Failed to get commit info about: #{ref_sha}" if commit_json.nil?
commit = JSON.parse(commit_json) commit = JSON.parse(commit_json)
meta = {
@meta = {
sha: commit['sha'], sha: commit['sha'],
date: Date.parse(commit['commit']['committer']['date']) date: Date.parse(commit['commit']['committer']['date'])
} }
meta[:ref] = ref if ref && ref[0..6] != meta[:sha][0..6]
@meta = meta
end end
def http_get(url) def http_get(url)
@@ -426,35 +417,19 @@ class Build
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}") system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
end end
def apply_native_comp_macos_fixes def apply_native_comp_env_setup_patch(source)
filename = 'Makefile.in' term = 'native-compile-setup-environment-variables'
pattern = /^src: Makefile\n(.*BIN_DESTDIR.*)\nblessmail: Makefile src\n/m file = 'lisp/emacs-lisp/comp.el'
content = File.read(filename).gsub(pattern) do return if `grep '#{term}' '#{file}'`.strip.size.positive?
old_src_body = Regexp.last_match(1).strip
# check if already patched template = File.read(
if old_src_body.include?('BIN_DESTDIR=\'${ns_appbindir}/\'') File.join(__dir__, 'patches/native-comp-env-setup.diff.erb')
return old_src_body )
end patch = ERB.new(template).result(gcc_info.get_binding)
patch_file = File.join(source, 'macos_patches/native-comp-env-setup.diff')
self_contained = old_src_body.gsub( File.write(patch_file, patch)
'BIN_DESTDIR=\'$(DESTDIR)${bindir}/\'', apply_patch({ file: patch_file }, source)
'BIN_DESTDIR=\'${ns_appbindir}/\''
)
<<~REPLACEMENT
src: Makefile
ifeq (${ns_self_contained},no)
\t#{old_src_body}
else
\t#{self_contained}
endif
blessmail: Makefile src
REPLACEMENT
end
File.open(filename, 'w') { |f| f.write(content) }
end end
def effective_version def effective_version
@@ -521,11 +496,14 @@ class Build
def apply_patch(patch, target) def apply_patch(patch, target)
err "\"#{target}\" does not exist." unless File.exist?(target) err "\"#{target}\" does not exist." unless File.exist?(target)
if patch[:url] if patch[:file]
info 'Applying patch...'
FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch[:file]) }
elsif patch[:url]
patch_dir = "#{target}/macos_patches" patch_dir = "#{target}/macos_patches"
run_cmd('mkdir', '-p', patch_dir) run_cmd('mkdir', '-p', patch_dir)
patch_file = "#{patch_dir}/patch-{num}.diff" patch_file = File.join(patch_dir, 'patch-{num}.diff')
num = 1 num = 1
while File.exist?(patch_file.gsub('{num}', num.to_s.rjust(3, '0'))) while File.exist?(patch_file.gsub('{num}', num.to_s.rjust(3, '0')))
num += 1 num += 1
@@ -535,8 +513,7 @@ class Build
info "Downloading patch: #{patch[:url]}" info "Downloading patch: #{patch[:url]}"
run_cmd('curl', '-L#', patch[:url], '-o', patch_file) run_cmd('curl', '-L#', patch[:url], '-o', patch_file)
info 'Applying patch...' apply_patch({ file: patch_file }, target)
FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch_file) }
elsif patch[:replace] elsif patch[:replace]
err 'Patch replace input error' unless patch[:replace].size == 3 err 'Patch replace input error' unless patch[:replace].size == 3
@@ -569,16 +546,16 @@ class AbstractEmbedder
private private
def invocation_dir
File.join(app, 'Contents/MacOS')
end
def bin def bin
"#{app}/Contents/MacOS/Emacs" File.join(invocation_dir, 'Emacs')
end end
def lib_dir def lib_dir
"#{app}/Contents/MacOS/#{lib_dir_name}" File.join(invocation_dir, 'lib')
end
def lib_dir_name
"lib-#{OS.arch}-#{OS.version.to_s.tr('.', '_')}"
end end
end end
@@ -621,18 +598,18 @@ class LibEmbedder < AbstractEmbedder
while_writable(exe) do while_writable(exe) do
if match[2] == exe_file if match[2] == exe_file
system('install_name_tool', '-id', system('install_name_tool', '-id',
"@executable_path/#{rel_path}/#{match[2]}", exe) File.join('@executable_path', rel_path, match[2].to_s), exe)
else else
system('install_name_tool', '-change', match[1], system('install_name_tool', '-change', match[1],
"@executable_path/#{rel_path}/#{match[2]}", exe) File.join('@executable_path', rel_path, match[2].to_s), exe)
end end
end end
next if match[2] == exe_file || File.exist?("#{lib_dir}/#{match[2]}") next if match[2] == exe_file || File.exist?(File.join(lib_dir, match[2]))
FileUtils.mkdir_p(lib_dir) FileUtils.mkdir_p(lib_dir)
FileUtils.cp(match[1], lib_dir) FileUtils.cp(match[1], lib_dir)
copy_libs("#{lib_dir}/#{match[2]}", rel_path) copy_libs(File.join(lib_dir, match[2].to_s), rel_path)
end end
end end
@@ -651,7 +628,7 @@ class LibEmbedder < AbstractEmbedder
while_writable(target) do while_writable(target) do
system('install_name_tool', '-id', system('install_name_tool', '-id',
"@executable_path/#{rel_path}/#{lib_file}", target) File.join('@executable_path', rel_path, lib_file), target)
end end
copy_libs(target, rel_path) copy_libs(target, rel_path)
@@ -675,7 +652,7 @@ class LibEmbedder < AbstractEmbedder
while_writable(bin_path) do while_writable(bin_path) do
system( system(
'install_name_tool', '-change', match[1], 'install_name_tool', '-change', match[1],
"@executable_path/#{rel_path}/#{match[2]}", File.join('@executable_path', rel_path, match[2].to_s),
bin_path bin_path
) )
end end
@@ -691,12 +668,12 @@ class LibEmbedder < AbstractEmbedder
end end
end end
class LibGccJitEmbedder < AbstractEmbedder class GccLibEmbedder < AbstractEmbedder
attr_reader :gcc_dir attr_reader :gcc_info
def initialize(app, gcc_dir) def initialize(app, gcc_info)
super(app) super(app)
@gcc_dir = gcc_dir @gcc_info = gcc_info
end end
def embed def embed
@@ -706,103 +683,121 @@ class LibGccJitEmbedder < AbstractEmbedder
end end
info 'Embedding libgccjit into Emacs.app' info 'Embedding libgccjit into Emacs.app'
if gcc_version.empty?
err "No suitable GCC lib with libgccjit found in #{gcc_dir}" if gcc_info.lib_dir.empty?
err "No suitable GCC lib dir found in #{gcc_info.root_dir}"
end end
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
def embedded? def embedded?
Dir[File.join(target_dir, 'libgccjit.so*')].any? Dir[File.join(target_dir, 'libgcc*')].any?
end end
def target_dir def target_dir
File.join(lib_dir, 'gcc', gcc_version) File.join(invocation_dir, gcc_info.relative_lib_dir)
end
def gcc_version
@gcc_version ||= Dir[File.join(gcc_dir, 'lib', 'gcc', '*', 'libgccjit.so*')]
.map { |path| File.dirname(path) }
.select { |path| path.match(%r{/\d+$}) }
.uniq
.map { |dir| File.basename(dir).to_i }
.max
.to_s
end end
def source_dir def source_dir
@source_dir ||= File.join(gcc_dir, 'lib', 'gcc', gcc_version) gcc_info.lib_dir
end end
end end
class LauncherEmbedder < AbstractEmbedder class GccInfo
attr_reader :template include Output
def initialize(app, template) def root_dir
super(app) @root_dir ||= `brew --prefix gcc`.chomp
@template = template
end end
def embed def major_version
if embedded? @major_version ||= File.basename(lib_dir)
info 'Launcher script already embedded in Emacs.app' end
return
def lib_dir
@lib_dir ||= Dir[File.join(root_dir, 'lib/gcc/*/libgcc*')]
.map { |path| File.dirname(path) }
.select { |path| File.basename(path).match(/^\d+$/) }
.max_by { |path| File.basename(path).to_i }
end
def relative_lib_dir
@relative_lib_dir ||= relative_dir(lib_dir, root_dir)
end
def darwin_lib_dir
@darwin_lib_dir ||= Dir[
File.join(lib_dir, 'gcc/*apple-darwin*/*')
].max_by do |path|
[
File.basename(File.dirname(path)).match(/darwin(\d+)$/)[1].to_i,
File.basename(path).split('.').map(&:to_i)
]
end
end
def relative_darwin_lib_dir
@relative_darwin_lib_dir ||= relative_dir(darwin_lib_dir, root_dir)
end
def libgccjit_root_dir
@libgccjit_root_dir ||= `brew --prefix libgccjit`.chomp
end
def libgccjit_major_version
@libgccjit_major_version ||= File.basename(libgccjit_lib_dir.to_s)
end
def libgccjit_lib_dir
@libgccjit_lib_dir ||= Dir[
File.join(libgccjit_root_dir, 'lib/gcc/*/libgccjit.so*')
]
.map { |path| File.dirname(path) }
.select { |path| File.basename(path).match(/^\d+$/) }
.max_by { |path| File.basename(path).to_i }
end
def verify_libgccjit
err 'gcc not installed' unless Dir.exist?(root_dir)
err 'libgccjit not installed' unless Dir.exist?(libgccjit_root_dir)
if libgccjit_lib_dir&.empty?
err "Detected libgccjit (#{libgccjit_root_dir}) does not have any " \
'libgccjit.so* files. Please try reinstalling libgccjit: ' \
'brew reinstall libgccjit'
end end
info 'Embedding launcher script into Emacs.app' return if major_version == libgccjit_major_version
unless File.exist?("#{bin}#{bin_suffix}") err <<~TEXT
FileUtils.mv(bin, "#{bin}#{bin_suffix}") Detected GCC and libgccjit library paths do not belong to the same major
end version of GCC. Detected paths:
- #{lib_dir}
- #{libgccjit_lib_dir}
TEXT
end
unless File.exist?("#{bin}#{bin_suffix}#{dump_ext}") def get_binding
FileUtils.mv("#{bin}#{dump_ext}", "#{bin}#{bin_suffix}#{dump_ext}") binding
end
unless File.exist?(bin)
File.write(bin, launcher)
File.chmod(0o775, bin)
end
end end
private private
def bin_suffix def relative_dir(path, root)
'-bin' root += '/' unless root[-1] == '/'
end return if path[0..root.size - 1] != root
def dump_ext path[root.size..-1]
'.pdmp'
end
def embedded?
File.exist?(bin) &&
File.exist?("#{bin}#{bin_suffix}") &&
File.exist?("#{bin}#{bin_suffix}#{dump_ext}")
end
def launcher
@launcher ||= ERB.new(File.read(template)).result(binding)
end
def library_paths
@library_paths ||= Dir[
"#{lib_dir}/gcc/*",
"#{lib_dir}/gcc/*/gcc/*apple-darwin*/*"
].map do |p|
p.gsub(/^#{Regexp.escape(lib_dir + '/')}/, '')
end.sort_by { |p| [p.size, p] }
end end
end end
if __FILE__ == $PROGRAM_NAME if __FILE__ == $PROGRAM_NAME
cli_options = { cli_options = {
macos_fixes: true,
native_full_aot: false, native_full_aot: false,
parallel: Etc.nprocessors, parallel: Etc.nprocessors,
rsvg: false, rsvg: false,
@@ -849,18 +844,6 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:native_full_aot] = v cli_options[:native_full_aot] = v
end end
opts.on('--[no-]native-comp-macos-fixes',
'Enable/disable fix based on feature/native-comp-macos-fixes ' \
'branch (default: enabled if native-comp supported)') do |v|
cli_options[:macos_fixes] = v
end
opts.on('--[no-]launcher',
'Enable/disable embedded launcher script ' \
'(default: enabled if native-comp is enabled)') do |v|
cli_options[:launcher] = v
end
opts.on('--rsvg', 'Enable SVG image support via librsvg, ' \ opts.on('--rsvg', 'Enable SVG image support via librsvg, ' \
'can yield a unstable build (default: disabled)') do 'can yield a unstable build (default: disabled)') do
cli_options[:rsvg] = true cli_options[:rsvg] = true
@@ -885,6 +868,12 @@ if __FILE__ == $PROGRAM_NAME
'use --native-full-aot instead' 'use --native-full-aot instead'
end end
end end
opts.on('--[no-]launcher',
'DEPRECATED: Launcher script is no longer used.') do |_|
raise Error, '--[no-]launcher option is deprecated, launcher ' \
'script is no longer used.'
end
end.parse! end.parse!
Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build

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,65 +0,0 @@
#!/bin/bash
# This launcher script is not part of Emacs proper. It is from the
# build-emacs-for-macos project (https://github.com/jimeh/build-emacs-for-macos)
# and helps facilitate proper startup of Emacs with environment varibales set as
# needed.
#
# Licensed under CC0 1.0 Universal:
# https://creativecommons.org/publicdomain/zero/1.0/
#
set -e
resolve_link() {
local file="$1"
while [ -L "$file" ]; do
file="$(readlink "$file")"
done
echo "$file"
}
realname() {
local path="$1"
local resolved
local cwd
cwd="$(pwd)"
resolved="$(resolve_link "$path")"
cd "$(dirname "$resolved")"
echo "$(pwd)/$(basename "$resolved")"
cd "$cwd"
}
join() {
local IFS="$1"
local parts=()
shift
for arg in "$@"; do
if [ "$arg" != "" ]; then
parts+=("$arg")
fi
done
echo "${parts[*]}"
}
DIR="$(dirname "$(realname "$0")")"
BIN="${DIR}/Emacs<%= bin_suffix %>"
export PATH="${DIR}/bin:${DIR}/libexec:${PATH}"
<% if library_paths.any? %>
LIB_PATHS=(
'<%= library_paths.map { |p| p.gsub('\'', "\"'\"") }.join("'\n '") %>'
)
for lib in "${LIB_PATHS[@]}"; do
if [ -d "${DIR}/<%= lib_dir_name %>/${lib}" ]; then
libs="$(join : "$libs" "${DIR}/<%= lib_dir_name %>/${lib}")"
fi
done
LIBRARY_PATH="$(join : "$libs" "$LIBRARY_PATH")"
export LIBRARY_PATH
<% end %>
exec "$BIN" "$@"

View File

@@ -0,0 +1,57 @@
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 4036080976..2ff8dbd74c 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4079,6 +4079,52 @@ of (commands) to run simultaneously."
(let ((load (not (not load))))
(native--compile-async paths recursively load selector)))
+;;;###autoload
+(defun native-compile-setup-environment-variables (&rest _args)
+ "Ensure LIBRARY_PATH is set correctly when libgccjit is bundled."
+ (when (and (eq system-type 'darwin)
+ (string-match-p "\.app\/Contents\/MacOS\/?$"
+ invocation-directory))
+ (let* ((library-path-env (getenv "LIBRARY_PATH"))
+ (devtools-dir
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
+ (gcc-dir (expand-file-name
+ "<%= relative_lib_dir %>"
+ invocation-directory))
+ (darwin-dir (expand-file-name
+ "<%= relative_darwin_lib_dir %>"
+ invocation-directory))
+ (lib-paths (list)))
+
+ (if library-path-env
+ (push library-path-env lib-paths))
+ (if (file-directory-p devtools-dir)
+ (push devtools-dir lib-paths))
+ (push darwin-dir lib-paths)
+ (push gcc-dir lib-paths)
+
+ (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":"))))
+
+ ;; Remove advice, as it only needs to run once.
+ (advice-remove 'native-compile
+ 'native-compile-setup-environment-variables)
+ (advice-remove 'comp--native-compile
+ 'native-compile-setup-environment-variables)
+ (advice-remove 'native-compile-async
+ 'native-compile-setup-environment-variables)
+ (advice-remove 'native--compile-async
+ 'native-compile-setup-environment-variables))
+
+;; Ensure environment setup runs before any native compilation.
+(advice-add 'native-compile :before
+ 'native-compile-setup-environment-variables)
+(advice-add 'comp--native-compile :before
+ 'native-compile-setup-environment-variables)
+(advice-add 'native-compile-async :before
+ 'native-compile-setup-environment-variables)
+(advice-add 'native--compile-async :before
+ 'native-compile-setup-environment-variables)
+
(provide 'comp)
;;; comp.el ends here