mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
8d165b627b
|
|||
|
9c977a75b5
|
|||
|
2054c8c0aa
|
|||
|
ca09d1a95f
|
|||
|
f1e60e31d9
|
|||
|
8d197aea73
|
|||
|
844df73c8f
|
|||
|
f1fc68c8f5
|
|||
|
e19a6a7bc2
|
|||
|
1000999eb2
|
|||
|
a75047fb3a
|
|||
|
a1641946e4
|
|||
|
581594da3c
|
|||
|
bdad382e7f
|
|||
|
e25ceaa7e2
|
|||
|
03ae8750b8
|
|||
|
269dbdb1dd
|
|||
| 713c970da4 | |||
|
dca023daec
|
|||
|
e56c26d06f
|
|||
|
b2860f22c3
|
|||
|
d1c5e7afb1
|
|||
|
ab55f5421c
|
|||
|
eb09d5fa49
|
|||
|
a47d3e0c6a
|
|||
|
5a61a72a73
|
|||
| 9cdf67e71b | |||
|
946856e9c2
|
|||
|
|
2247158051
|
||
|
4a7c507858
|
|||
|
884f1607f6
|
|||
|
c7daa1350b
|
|||
|
9223ff8e28
|
|||
|
70bf6b05d5
|
|||
|
8936f4762a
|
|||
|
be8e04e7a5
|
|||
| aadf32cbbe | |||
|
d8bbcb72b3
|
|||
|
d6f11b5459
|
|||
|
09e67381cb
|
|||
|
d21ccad3e4
|
|||
| 036d2a82d9 | |||
|
111cb64993
|
|||
|
fe3af6c4c9
|
|||
|
7ca3f52819
|
|||
|
0ab94da153
|
|||
|
01d27c0891
|
10
.rubocop.yml
10
.rubocop.yml
@@ -1,5 +1,9 @@
|
|||||||
|
AllCops:
|
||||||
|
TargetRubyVersion: 2.3
|
||||||
|
NewCops: enable
|
||||||
|
|
||||||
|
Layout/LineLength:
|
||||||
|
Max: 80
|
||||||
|
|
||||||
Style/Documentation:
|
Style/Documentation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/LineLength:
|
|
||||||
Max: 80
|
|
||||||
|
|||||||
3
Brewfile
3
Brewfile
@@ -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'
|
||||||
|
|||||||
106
CHANGELOG.md
106
CHANGELOG.md
@@ -2,6 +2,112 @@
|
|||||||
|
|
||||||
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.10](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.9...0.4.10) (2021-04-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **cli:** correctly default to master branch if no git ref is given ([844df73](https://github.com/jimeh/build-emacs-for-macos/commit/844df73c8fa8440e657f7900ec89cdedb7c4c312))
|
||||||
|
|
||||||
|
### [0.4.9](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.8...0.4.9) (2021-04-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **cli:** default to "master" if no git ref is given ([e19a6a7](https://github.com/jimeh/build-emacs-for-macos/commit/e19a6a7bc24379292ee06ae4c805b8c5365f2d97)), closes [#35](https://github.com/jimeh/build-emacs-for-macos/issues/35)
|
||||||
|
* **native_comp:** skip symlink creation for recent builds which do not need symlinks ([1000999](https://github.com/jimeh/build-emacs-for-macos/commit/1000999eb2673dc207a390ff3f902b9987b99173))
|
||||||
|
|
||||||
|
### [0.4.8](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.7...0.4.8) (2021-02-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native_comp:** add support for new --with-native-compilation flag ([581594d](https://github.com/jimeh/build-emacs-for-macos/commit/581594da3cfbf1dd2fa28e91710b767e21ff75d2))
|
||||||
|
|
||||||
|
### [0.4.7](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.6...0.4.7) (2021-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native_comp:** add libgccjit include dir during build stage ([e25ceaa](https://github.com/jimeh/build-emacs-for-macos/commit/e25ceaa7e25b0e1b9947401597845b5ba43e6cd1)), closes [#20](https://github.com/jimeh/build-emacs-for-macos/issues/20)
|
||||||
|
|
||||||
|
### [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)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* **native_comp:** Deprecate `--[no-]native-fast-boot` option in favor of `--[no-]native-full-aot`
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **native_comp:** add support for NATIVE_FULL_AOT, replacing NATIVE_FAST_BOOT ([0ab94da](https://github.com/jimeh/build-emacs-for-macos/commit/0ab94da15309b04978982369bdfa17e03e9b6329))
|
||||||
|
|
||||||
### [0.1.1](https://github.com/jimeh/build-emacs-for-macos/compare/0.1.0...0.1.1) (2020-09-19)
|
### [0.1.1](https://github.com/jimeh/build-emacs-for-macos/compare/0.1.0...0.1.1) (2020-09-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
2
Gemfile
2
Gemfile
@@ -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
|
||||||
|
|||||||
12
Makefile
Normal file
12
Makefile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.PHONY: new-version
|
||||||
|
new-version: check-npx
|
||||||
|
npx standard-version
|
||||||
|
|
||||||
|
.PHONY: next-version
|
||||||
|
next-version: check-npx
|
||||||
|
npx standard-version --dry-run
|
||||||
|
|
||||||
|
.PHONY: check-npx
|
||||||
|
check-npx:
|
||||||
|
$(if $(shell which npx),,\
|
||||||
|
$(error No npx execuable found in PATH, please install NodeJS))
|
||||||
113
README.md
113
README.md
@@ -1,7 +1,8 @@
|
|||||||
# build-emacs-for-macos
|
# build-emacs-for-macos
|
||||||
|
|
||||||
My personal hacked together script for building a completely self-contained
|
My personal hacked together script for building a completely self-contained
|
||||||
Emacs.app application on macOS, from any git branch, tag, or ref.
|
Emacs.app application on macOS, from any git branch, tag, or ref. With support
|
||||||
|
for native-compilation.
|
||||||
|
|
||||||
Use this script at your own risk.
|
Use this script at your own risk.
|
||||||
|
|
||||||
@@ -18,7 +19,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-04-25) it works for me on my machine. Your luck may vary.
|
||||||
|
|
||||||
I have successfully built:
|
I have successfully built:
|
||||||
|
|
||||||
@@ -29,8 +30,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.2.3 (20D91)
|
||||||
- Xcode 11.6
|
- Xcode 12.4 (12D4e)
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
@@ -71,15 +72,14 @@ available here: https://github.com/emacs-mirror/emacs
|
|||||||
Options:
|
Options:
|
||||||
-j, --parallel COUNT Compile using COUNT parallel processes (detected: 8)
|
-j, --parallel COUNT Compile using COUNT parallel processes (detected: 8)
|
||||||
--git-sha SHA Override detected git SHA of specified branch allowing builds of old commits
|
--git-sha SHA Override detected git SHA of specified branch allowing builds of old commits
|
||||||
--[no-]xwidgets Enable/disable XWidgets (default: enabled)
|
--[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-fast-boot Enable/disable NATIVE_FAST_BOOT (default: enabled if native-comp supported)
|
--[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-]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
|
||||||
@@ -88,10 +88,13 @@ 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 with native-compilation
|
||||||
build Emacs.app from it:
|
as of writing) and build Emacs.app from it:
|
||||||
|
|
||||||
```
|
```
|
||||||
./build-emacs-for-macos
|
./build-emacs-for-macos
|
||||||
@@ -108,43 +111,50 @@ 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
|
_Note: On 2021-04-25 the `feature/native-comp` branch was
|
||||||
([gccemacs](https://akrl.sdf.org/gccemacs.html)) from the `feature/native-comp`
|
[merged](http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=289000eee729689b0cf362a21baa40ac7f9506f6)
|
||||||
branch, you will need to install a patched version of Homebrew's `gcc` formula
|
into `master`._
|
||||||
that includes libgccjit.
|
|
||||||
|
|
||||||
The patch itself is in `./Formula/gcc.rb.patch`, and comes from
|
The build script will automatically detect if the source tree being built
|
||||||
[this](https://gist.github.com/mikroskeem/0a5c909c1880408adf732ceba6d3f9ab#1-gcc-with-libgccjit-enabled)
|
supports native-compilation, and enable it if available. You can override this
|
||||||
gist.
|
to force it on/off by passing `--native-comp` or `--no-native-comp`
|
||||||
|
respectfully.
|
||||||
|
|
||||||
You can install the patched formula by running the helper script:
|
By default `NATIVE_FULL_AOT` is disabled which ensures a fast build by native
|
||||||
|
compiling as few elisp source files as possible to build Emacs itself. Any
|
||||||
|
remaining elisp files will be dynamically compiled in the background the first
|
||||||
|
time they are used.
|
||||||
|
|
||||||
```
|
To enable native full Ahead-of-Time compilation, pass in the `--native-full-aot`
|
||||||
./install-patched-gcc
|
option, which will native-compile all of Emacs' elisp as built-time. On my
|
||||||
```
|
machine it takes around 10 minutes to build Emacs.app with `NATIVE_FULL_AOT`
|
||||||
|
disabled, and around 20-25 minutes with it enabled.
|
||||||
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
|
### Configuration
|
||||||
|
|
||||||
@@ -159,24 +169,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/" user-emacs-directory))
|
(setcar comp-eln-load-path
|
||||||
(find-exec (executable-find "find")))
|
(expand-file-name "cache/eln-cache/" user-emacs-directory)))
|
||||||
(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"))))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Issues
|
### Issues
|
||||||
|
|||||||
52
bin/commit-info
Executable file
52
bin/commit-info
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative '../lib/commit_info'
|
||||||
|
require_relative '../lib/errors'
|
||||||
|
require_relative '../lib/log'
|
||||||
|
|
||||||
|
options = {
|
||||||
|
repo: 'emacs-mirror/emacs',
|
||||||
|
output: File.expand_path('../tarballs', __dir__),
|
||||||
|
log_level: :info
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = <<~TXT
|
||||||
|
Usage: ./commit-info [options] <branch/tag/sha>
|
||||||
|
|
||||||
|
Fetch commit info of given GitHub repository branch, tag, or SHA.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
TXT
|
||||||
|
|
||||||
|
opts.on('-r', '--repo STRING',
|
||||||
|
"GitHub repository (default: #{options[:repo]})") do |v|
|
||||||
|
options[:repo] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-o', '--output DIR', 'Directory to save tarball in ' \
|
||||||
|
"(default: #{options[:output]})") do |v|
|
||||||
|
options[:output] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-l', '--log-level LEVEL', 'Log level ' \
|
||||||
|
"(default: #{options[:log_level]})") do |v|
|
||||||
|
options[:log_level] = v.to_sym
|
||||||
|
end
|
||||||
|
end.parse!
|
||||||
|
|
||||||
|
begin
|
||||||
|
logger = Log.new('commit-info', options[:log_level])
|
||||||
|
commit = CommitInfo.new(
|
||||||
|
ref: ARGV[0],
|
||||||
|
repo: options[:repo],
|
||||||
|
logger: logger
|
||||||
|
).perform
|
||||||
|
|
||||||
|
puts commit.to_yaml
|
||||||
|
rescue Error => e
|
||||||
|
handle_error(e)
|
||||||
|
end
|
||||||
53
bin/download-tarball
Executable file
53
bin/download-tarball
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative '../lib/download_tarball'
|
||||||
|
require_relative '../lib/errors'
|
||||||
|
require_relative '../lib/log'
|
||||||
|
|
||||||
|
options = {
|
||||||
|
repo: 'emacs-mirror/emacs',
|
||||||
|
output: File.expand_path('../tarballs', __dir__),
|
||||||
|
log_level: :info
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = <<~TXT
|
||||||
|
Usage: ./download-tarball [options] <branch/tag/sha>
|
||||||
|
|
||||||
|
Download a tarball of given GitHub repository branch, tag, or SHA.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
TXT
|
||||||
|
|
||||||
|
opts.on('-r', '--repo STRING',
|
||||||
|
"GitHub repository (default: #{options[:repo]})") do |v|
|
||||||
|
options[:repo] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-o', '--output DIR', 'Directory to save tarball in ' \
|
||||||
|
"(default: #{options[:output]})") do |v|
|
||||||
|
options[:output] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-l', '--log-level LEVEL', 'Log level ' \
|
||||||
|
"(default: #{options[:log_level]})") do |v|
|
||||||
|
options[:log_level] = v.to_sym
|
||||||
|
end
|
||||||
|
end.parse!
|
||||||
|
|
||||||
|
begin
|
||||||
|
logger = Log.new('download-tarball', options[:log_level])
|
||||||
|
tarball = DownloadTarball.new(
|
||||||
|
ref: ARGV[0],
|
||||||
|
repo: options[:repo],
|
||||||
|
output: options[:output],
|
||||||
|
logger: logger
|
||||||
|
).perform
|
||||||
|
|
||||||
|
puts tarball.to_yaml
|
||||||
|
rescue Error => e
|
||||||
|
handle_error(e)
|
||||||
|
end
|
||||||
@@ -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 || 'master'
|
||||||
@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."
|
||||||
@@ -188,14 +180,20 @@ class Build
|
|||||||
@configure_help
|
@configure_help
|
||||||
end
|
end
|
||||||
|
|
||||||
def supports_native_comp?
|
|
||||||
@supports_native_comp ||= !!configure_help.match(/\s+--with-nativecomp\s+/)
|
|
||||||
end
|
|
||||||
|
|
||||||
def supports_xwidgets?
|
def supports_xwidgets?
|
||||||
@supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/)
|
@supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def supports_native_comp?
|
||||||
|
@supports_native_comp ||= !native_comp_configure_flag.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def native_comp_configure_flag
|
||||||
|
@native_comp_configure_flag ||= configure_help.match(
|
||||||
|
/\s+(--with-native(?:comp|-compilation))\s+/
|
||||||
|
)&.[](1)
|
||||||
|
end
|
||||||
|
|
||||||
def detect_native_comp
|
def detect_native_comp
|
||||||
info 'Detecting native-comp support: ', newline: false
|
info 'Detecting native-comp support: ', newline: false
|
||||||
options[:native_comp] = supports_native_comp?
|
options[:native_comp] = supports_native_comp?
|
||||||
@@ -208,22 +206,6 @@ 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
|
|
||||||
@gcc_library_paths ||= Dir[
|
|
||||||
"#{gcc_dir}/lib/gcc/*",
|
|
||||||
"#{gcc_dir}/lib/gcc/*/gcc/*apple-darwin*/*"
|
|
||||||
].sort_by { |p| [p.size, p] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def autogen
|
def autogen
|
||||||
FileUtils.cd(source_dir) do
|
FileUtils.cd(source_dir) do
|
||||||
if File.exist?('autogen/copy_autogen')
|
if File.exist?('autogen/copy_autogen')
|
||||||
@@ -235,10 +217,10 @@ class Build
|
|||||||
end
|
end
|
||||||
|
|
||||||
def compile_source(source)
|
def compile_source(source)
|
||||||
target = "#{source}/nextstep"
|
target = File.join(source, 'nextstep')
|
||||||
emacs_app = "#{target}/Emacs.app"
|
emacs_app = File.join(target, 'Emacs.app')
|
||||||
|
|
||||||
if File.exist?("#{target}/Emacs.app")
|
if File.exist?(emacs_app)
|
||||||
info 'Emacs.app already exists in ' \
|
info 'Emacs.app already exists in ' \
|
||||||
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use."
|
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use."
|
||||||
return emacs_app
|
return emacs_app
|
||||||
@@ -250,51 +232,62 @@ 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['NATIVE_FAST_BOOT'] = '1' if options[:native_fast_boot]
|
|
||||||
ENV['CFLAGS'] = [
|
ENV['CFLAGS'] = [
|
||||||
"-I#{gcc_dir}/include",
|
"-I#{File.join(gcc_info.root_dir, 'include')}",
|
||||||
|
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
|
||||||
'-O2',
|
'-O2',
|
||||||
'-march=native'
|
'-march=native',
|
||||||
|
ENV['CFLAGS']
|
||||||
].compact.join(' ')
|
].compact.join(' ')
|
||||||
|
|
||||||
ENV['LDFLAGS'] = [
|
ENV['LDFLAGS'] = [
|
||||||
gcc_library_paths.map { |path| "-L#{path}" },
|
"-L#{gcc_info.lib_dir}",
|
||||||
"-I#{gcc_dir}/include"
|
"-L#{gcc_info.darwin_lib_dir}",
|
||||||
].flatten.compact.join(' ')
|
"-L#{gcc_info.libgccjit_lib_dir}",
|
||||||
|
"-I#{File.join(gcc_info.root_dir, 'include')}",
|
||||||
|
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
|
||||||
|
ENV['LDFLAGS']
|
||||||
|
].compact.join(' ')
|
||||||
|
|
||||||
ENV['LIBRARY_PATH'] = [
|
ENV['LIBRARY_PATH'] = [
|
||||||
gcc_library_paths,
|
gcc_info.lib_dir,
|
||||||
|
gcc_info.darwin_lib_dir,
|
||||||
|
gcc_info.libgccjit_lib_dir,
|
||||||
ENV['LIBRARY_PATH']
|
ENV['LIBRARY_PATH']
|
||||||
].flatten.compact.join(':')
|
].compact.join(':')
|
||||||
end
|
end
|
||||||
|
|
||||||
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',
|
||||||
@@ -305,7 +298,7 @@ class Build
|
|||||||
if options[:xwidgets] && supports_xwidgets?
|
if options[:xwidgets] && supports_xwidgets?
|
||||||
configure_flags << '--with-xwidgets'
|
configure_flags << '--with-xwidgets'
|
||||||
end
|
end
|
||||||
configure_flags << '--with-nativecomp' if options[:native_comp]
|
configure_flags << native_comp_configure_flag if options[:native_comp]
|
||||||
configure_flags << '--without-rsvg' unless options[:rsvg]
|
configure_flags << '--without-rsvg' unless options[:rsvg]
|
||||||
|
|
||||||
run_cmd './configure', *configure_flags
|
run_cmd './configure', *configure_flags
|
||||||
@@ -323,6 +316,15 @@ class Build
|
|||||||
|
|
||||||
if options[:native_comp]
|
if options[:native_comp]
|
||||||
make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'"
|
make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'"
|
||||||
|
|
||||||
|
if options[:native_full_aot]
|
||||||
|
info 'Using NATIVE_FULL_AOT=1'
|
||||||
|
make_flags << 'NATIVE_FULL_AOT=1'
|
||||||
|
ENV.delete('NATIVE_FAST_BOOT')
|
||||||
|
else
|
||||||
|
ENV.delete('NATIVE_FULL_AOT')
|
||||||
|
ENV['NATIVE_FAST_BOOT'] = '1'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
run_cmd 'make', *make_flags
|
run_cmd 'make', *make_flags
|
||||||
@@ -337,13 +339,20 @@ class Build
|
|||||||
def symlink_internals(app)
|
def symlink_internals(app)
|
||||||
return unless options[:native_comp]
|
return unless options[:native_comp]
|
||||||
|
|
||||||
info 'Creating symlinks within Emacs.app needed for native-comp'
|
|
||||||
|
|
||||||
FileUtils.cd(File.join(app, 'Contents')) do
|
FileUtils.cd(File.join(app, 'Contents')) do
|
||||||
|
# Skip creation of symlinks if *.eln files are located under
|
||||||
|
# Resources/native-lisp. Emacs is capable of finding lisp sources and
|
||||||
|
# *.eln cache files without symlinks.
|
||||||
|
return if Dir['Resources/native-lisp/**/*.eln'].any?
|
||||||
|
|
||||||
|
info 'Creating symlinks within Emacs.app needed for native-comp'
|
||||||
|
|
||||||
FileUtils.ln_s('Resources/lisp', 'lisp') unless File.exist?('lisp')
|
FileUtils.ln_s('Resources/lisp', 'lisp') unless File.exist?('lisp')
|
||||||
|
|
||||||
source = Dir['MacOS/libexec/emacs/**/eln-cache',
|
source = Dir['MacOS/libexec/emacs/**/eln-cache',
|
||||||
'MacOS/lib/emacs/**/native-lisp'].first
|
'MacOS/lib/emacs/**/native-lisp'].first
|
||||||
|
err 'Failed to find native-lisp cache directory for symlink creation.'
|
||||||
|
|
||||||
target = File.basename(source)
|
target = File.basename(source)
|
||||||
FileUtils.ln_s(source, target) unless File.exist?(target)
|
FileUtils.ln_s(source, target) unless File.exist?(target)
|
||||||
end
|
end
|
||||||
@@ -353,18 +362,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}\"..."
|
||||||
@@ -394,16 +403,19 @@ class Build
|
|||||||
return @meta if @meta
|
return @meta if @meta
|
||||||
|
|
||||||
ref_sha = options[:git_sha] || ref
|
ref_sha = options[:git_sha] || ref
|
||||||
|
info "Fetching info for git ref: #{ref_sha}"
|
||||||
url = format(LATEST_URL, ref_sha)
|
url = format(LATEST_URL, ref_sha)
|
||||||
commit_json = http_get(url)
|
commit_json = http_get(url)
|
||||||
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)
|
||||||
@@ -418,35 +430,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
|
||||||
@@ -513,11 +509,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
|
||||||
@@ -527,8 +526,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
|
||||||
|
|
||||||
@@ -561,16 +559,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
|
||||||
|
|
||||||
@@ -613,18 +611,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
|
||||||
|
|
||||||
@@ -643,7 +641,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)
|
||||||
@@ -667,7 +665,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
|
||||||
@@ -679,16 +677,17 @@ class LibEmbedder < AbstractEmbedder
|
|||||||
mode = File.stat(file).mode
|
mode = File.stat(file).mode
|
||||||
File.chmod(0o775, file)
|
File.chmod(0o775, file)
|
||||||
yield
|
yield
|
||||||
|
ensure
|
||||||
File.chmod(mode, file)
|
File.chmod(mode, file)
|
||||||
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
|
||||||
@@ -698,176 +697,199 @@ 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_fast_boot: true,
|
|
||||||
parallel: Etc.nprocessors,
|
parallel: Etc.nprocessors,
|
||||||
rsvg: false,
|
rsvg: false,
|
||||||
xwidgets: true
|
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 emacs-mirror/emacs/emacs Github repo,
|
|
||||||
available here: https://github.com/emacs-mirror/emacs
|
|
||||||
|
|
||||||
Options:
|
|
||||||
DOC
|
|
||||||
|
|
||||||
opts.on('-j', '--parallel COUNT',
|
|
||||||
'Compile using COUNT parallel processes ' \
|
|
||||||
"(detected: #{cli_options[:parallel]})") do |v|
|
|
||||||
cli_options[:parallel] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--git-sha SHA', 'Override detected git SHA of specified branch ' \
|
|
||||||
'allowing builds of old commits') do |v|
|
|
||||||
cli_options[:git_sha] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--[no-]xwidgets',
|
|
||||||
'Enable/disable XWidgets ' \
|
|
||||||
'(default: enabled)') do |v|
|
|
||||||
cli_options[:xwidgets] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--[no-]native-comp',
|
|
||||||
'Enable/disable native-comp ' \
|
|
||||||
'(default: enabled if supported)') do |v|
|
|
||||||
cli_options[:native_comp] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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, ' \
|
|
||||||
'can yield a unstable build (default: disabled)') do
|
|
||||||
cli_options[:rsvg] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--no-titlebar', 'Apply no-titlebar patch (default: disabled)') do
|
|
||||||
cli_options[:no_titlebar] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--no-frame-refocus',
|
|
||||||
'Apply no-frame-refocus patch (default: disabled)') do
|
|
||||||
cli_options[:no_frame_refocus] = true
|
|
||||||
end
|
|
||||||
end.parse!
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = <<~DOC
|
||||||
|
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
|
||||||
|
|
||||||
|
Options:
|
||||||
|
DOC
|
||||||
|
|
||||||
|
opts.on('-j', '--parallel COUNT',
|
||||||
|
'Compile using COUNT parallel processes ' \
|
||||||
|
"(detected: #{cli_options[:parallel]})") do |v|
|
||||||
|
cli_options[:parallel] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--git-sha SHA', 'Override detected git SHA of specified ' \
|
||||||
|
'branch allowing builds of old commits') do |v|
|
||||||
|
cli_options[:git_sha] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--[no-]xwidgets',
|
||||||
|
'Enable/disable XWidgets ' \
|
||||||
|
'(default: enabled if supported)') do |v|
|
||||||
|
cli_options[:xwidgets] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--[no-]native-comp',
|
||||||
|
'Enable/disable native-comp ' \
|
||||||
|
'(default: enabled if supported)') do |v|
|
||||||
|
cli_options[:native_comp] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--[no-]native-full-aot',
|
||||||
|
'Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation ' \
|
||||||
|
'(default: disabled)') do |v|
|
||||||
|
cli_options[:native_full_aot] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--rsvg', 'Enable SVG image support via librsvg, ' \
|
||||||
|
'can yield a unstable build (default: disabled)') do
|
||||||
|
cli_options[:rsvg] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--no-titlebar', 'Apply no-titlebar patch (default: disabled)') do
|
||||||
|
cli_options[:no_titlebar] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--no-frame-refocus',
|
||||||
|
'Apply no-frame-refocus patch (default: disabled)') do
|
||||||
|
cli_options[:no_frame_refocus] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('--[no-]native-fast-boot',
|
||||||
|
'DEPRECATED: use --[no-]native-full-aot instead') do |v|
|
||||||
|
if v
|
||||||
|
raise Error, '--native-fast-boot option is deprecated, ' \
|
||||||
|
'use --no-native-full-aot instead'
|
||||||
|
else
|
||||||
|
raise Error, '--no-native-fast-boot option is deprecated, ' \
|
||||||
|
'use --native-full-aot instead'
|
||||||
|
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!
|
||||||
|
|
||||||
Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build
|
Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build
|
||||||
rescue Error => e
|
rescue Error => e
|
||||||
warn "ERROR: #{e.message}"
|
warn "ERROR: #{e.message}"
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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" "$@"
|
|
||||||
9
lib/base_action.rb
Normal file
9
lib/base_action.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative './common'
|
||||||
|
require_relative './output'
|
||||||
|
|
||||||
|
class BaseAction
|
||||||
|
include Common
|
||||||
|
include Output
|
||||||
|
end
|
||||||
46
lib/commit.rb
Normal file
46
lib/commit.rb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'json'
|
||||||
|
require 'time'
|
||||||
|
require 'yaml'
|
||||||
|
|
||||||
|
require_relative './errors'
|
||||||
|
require_relative './common'
|
||||||
|
|
||||||
|
class Commit
|
||||||
|
include Common
|
||||||
|
|
||||||
|
attr_reader :repo
|
||||||
|
attr_reader :ref
|
||||||
|
attr_reader :message
|
||||||
|
attr_reader :sha
|
||||||
|
attr_reader :time
|
||||||
|
|
||||||
|
def initialize(sha:, time:, repo: nil, ref: nil, message: nil)
|
||||||
|
@sha = sha
|
||||||
|
@time = time
|
||||||
|
@repo = repo
|
||||||
|
@ref = ref
|
||||||
|
@message = message
|
||||||
|
end
|
||||||
|
|
||||||
|
def sha_short
|
||||||
|
sha[0..6]
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_hash
|
||||||
|
{
|
||||||
|
'repo' => repo,
|
||||||
|
'ref' => ref,
|
||||||
|
'sha' => sha,
|
||||||
|
'sha_short' => sha_short,
|
||||||
|
'time' => time.utc,
|
||||||
|
'timestamp' => time.utc.to_i,
|
||||||
|
'message' => message
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_yaml
|
||||||
|
to_hash.to_yaml
|
||||||
|
end
|
||||||
|
end
|
||||||
43
lib/commit_info.rb
Normal file
43
lib/commit_info.rb
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative './base_action'
|
||||||
|
require_relative './commit'
|
||||||
|
|
||||||
|
class CommitInfo < BaseAction
|
||||||
|
COMMIT_URL = 'https://api.github.com/repos/%s/commits/%s'
|
||||||
|
|
||||||
|
attr_reader :ref
|
||||||
|
attr_reader :repo
|
||||||
|
attr_reader :logger
|
||||||
|
|
||||||
|
def initialize(ref:, repo:, logger:)
|
||||||
|
@ref = ref
|
||||||
|
@repo = repo
|
||||||
|
@logger = logger
|
||||||
|
|
||||||
|
err 'branch/tag/sha argument cannot be empty' if ref.nil? || ref.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
info "Fetching info for git ref: #{ref}"
|
||||||
|
|
||||||
|
url = format(COMMIT_URL, repo, ref)
|
||||||
|
commit_json = http_get(url)
|
||||||
|
|
||||||
|
err "Failed to get commit info about: #{ref}" if commit_json.nil?
|
||||||
|
|
||||||
|
parsed = JSON.parse(commit_json)
|
||||||
|
commit = Commit.new(
|
||||||
|
repo: repo,
|
||||||
|
ref: ref,
|
||||||
|
sha: parsed&.dig('sha'),
|
||||||
|
message: parsed&.dig('commit', 'message'),
|
||||||
|
time: Time.parse(parsed&.dig('commit', 'committer', 'date')).utc
|
||||||
|
)
|
||||||
|
|
||||||
|
err 'Failed to get commit SHA' if commit.sha.nil? || commit.sha.empty?
|
||||||
|
err 'Failed to get commit time' if commit.time.nil?
|
||||||
|
|
||||||
|
commit
|
||||||
|
end
|
||||||
|
end
|
||||||
23
lib/common.rb
Normal file
23
lib/common.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'net/http'
|
||||||
|
|
||||||
|
module Common
|
||||||
|
private
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_cmd(*args)
|
||||||
|
info "executing: #{args.join(' ')}"
|
||||||
|
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def http_get(url)
|
||||||
|
response = Net::HTTP.get_response(URI.parse(url))
|
||||||
|
return unless response.code == '200'
|
||||||
|
|
||||||
|
response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
61
lib/download_tarball.rb
Normal file
61
lib/download_tarball.rb
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'fileutils'
|
||||||
|
require 'json'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
|
require_relative './base_action'
|
||||||
|
|
||||||
|
require_relative './commit_info'
|
||||||
|
require_relative './tarball'
|
||||||
|
|
||||||
|
class DownloadTarball < BaseAction
|
||||||
|
TARBALL_URL = 'https://github.com/%s/tarball/%s'
|
||||||
|
|
||||||
|
attr_reader :ref
|
||||||
|
attr_reader :repo
|
||||||
|
attr_reader :output
|
||||||
|
attr_reader :logger
|
||||||
|
|
||||||
|
def initialize(ref:, repo:, output:, logger:)
|
||||||
|
@ref = ref
|
||||||
|
@repo = repo
|
||||||
|
@output = output
|
||||||
|
@logger = logger
|
||||||
|
|
||||||
|
err 'branch/tag/sha argument cannot be empty' if ref.nil? || ref.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
FileUtils.mkdir_p(output)
|
||||||
|
tarball = Tarball.new(file: target, commit: commit)
|
||||||
|
|
||||||
|
if File.exist?(target)
|
||||||
|
info "#{filename} already exists locally, attempting to use."
|
||||||
|
return tarball
|
||||||
|
end
|
||||||
|
|
||||||
|
info 'Downloading tarball from GitHub. This could take a while, ' \
|
||||||
|
'please be patient.'
|
||||||
|
result = run_cmd('curl', '-L', url, '-o', target)
|
||||||
|
err 'Download failed.' if !result || !File.exist?(target)
|
||||||
|
|
||||||
|
tarball
|
||||||
|
end
|
||||||
|
|
||||||
|
def url
|
||||||
|
@url ||= format(TARBALL_URL, repo, commit.sha)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename
|
||||||
|
@filename ||= "#{repo.gsub(/[^\w]/, '-')}-#{commit.sha_short}.tgz"
|
||||||
|
end
|
||||||
|
|
||||||
|
def target
|
||||||
|
@target ||= File.join(output, filename)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit
|
||||||
|
@commit ||= CommitInfo.new(ref: ref, repo: repo, logger: logger).perform
|
||||||
|
end
|
||||||
|
end
|
||||||
12
lib/errors.rb
Normal file
12
lib/errors.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
def handle_error(err)
|
||||||
|
warn "ERROR: #{err.message}"
|
||||||
|
Process.exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
class Error < StandardError; end
|
||||||
|
|
||||||
|
class CommitNotFound < Error; end
|
||||||
|
class NoCommitSHA < Error; end
|
||||||
|
class NoCommitTime < Error; end
|
||||||
31
lib/log.rb
Normal file
31
lib/log.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Log
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
attr_reader :name
|
||||||
|
attr_reader :level
|
||||||
|
|
||||||
|
def initialize(name, level = :info)
|
||||||
|
@name = name
|
||||||
|
@level = level
|
||||||
|
end
|
||||||
|
|
||||||
|
def_delegators :logger, :debug, :info, :warn, :error, :fatal, :unkonwn
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def logger
|
||||||
|
@logger ||= Logger.new($stderr).tap do |l|
|
||||||
|
l.progname = name
|
||||||
|
l.level = level
|
||||||
|
l.formatter = formatter
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatter
|
||||||
|
proc do |severity, _datetime, progname, msg|
|
||||||
|
"==> [#{progname}] #{severity}: #{msg}\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
28
lib/output.rb
Normal file
28
lib/output.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'forwardable'
|
||||||
|
require 'logger'
|
||||||
|
|
||||||
|
require_relative './errors'
|
||||||
|
|
||||||
|
module Output
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def logger_name(name = nil)
|
||||||
|
return @logger_name if name.nil?
|
||||||
|
|
||||||
|
@logger_name = name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def_delegators :logger, :debug, :info, :warn, :error, :fatal, :unkonwn
|
||||||
|
|
||||||
|
def err(msg = nil)
|
||||||
|
raise Error, msg
|
||||||
|
end
|
||||||
|
end
|
||||||
24
lib/tarball.rb
Normal file
24
lib/tarball.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'yaml'
|
||||||
|
|
||||||
|
class Tarball
|
||||||
|
attr_reader :file
|
||||||
|
attr_reader :commit
|
||||||
|
|
||||||
|
def initialize(file:, commit:)
|
||||||
|
@file = file
|
||||||
|
@commit = commit
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_hash
|
||||||
|
{
|
||||||
|
'file' => file,
|
||||||
|
'commit' => commit.to_hash
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_yaml
|
||||||
|
to_hash.to_yaml
|
||||||
|
end
|
||||||
|
end
|
||||||
57
patches/native-comp-env-setup.diff.erb
Normal file
57
patches/native-comp-env-setup.diff.erb
Normal 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
|
||||||
Reference in New Issue
Block a user