mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c55bf68e61
|
|||
| 26ce446226 | |||
|
ca2d4c38f6
|
|||
|
bd81870659
|
|||
|
5cd9d1c5fa
|
|||
| 6ae14b597c | |||
|
deda28e5ad
|
|||
|
3d6caac962
|
|||
| 11de27358d | |||
|
8237aa9272
|
|||
|
3ffe83c94e
|
|||
|
9f6ec5954f
|
|||
| 9ea79670d8 | |||
|
72e40248e1
|
|||
|
7259111478
|
|||
|
bb45cda023
|
|||
|
ab872202df
|
|||
|
2d1c5d47d9
|
|||
| 30a71c423e | |||
|
5c48445397
|
|||
|
bf7c4d5deb
|
|||
|
3ffeb4854c
|
|||
|
0a22d8393c
|
|||
|
ac8348323d
|
|||
| 59f52b65ee | |||
|
81a96f4d60
|
|||
|
1df39fafe6
|
|||
|
14a8d1aaaf
|
|||
|
272a3000a1
|
|||
|
d684cf560f
|
|||
| ea189a6713 | |||
|
63289216d7
|
|||
|
2054c8c0aa
|
|||
|
ca09d1a95f
|
|||
|
f1e60e31d9
|
|||
|
8d197aea73
|
|||
|
844df73c8f
|
|||
|
f1fc68c8f5
|
|||
|
e19a6a7bc2
|
|||
|
1000999eb2
|
|||
|
a75047fb3a
|
|||
|
a1641946e4
|
|||
|
581594da3c
|
|||
|
bdad382e7f
|
|||
|
e25ceaa7e2
|
|||
|
03ae8750b8
|
|||
|
269dbdb1dd
|
|||
| 713c970da4 | |||
|
dca023daec
|
|||
|
e56c26d06f
|
|||
|
b2860f22c3
|
|||
|
d1c5e7afb1
|
|||
|
ab55f5421c
|
|||
|
eb09d5fa49
|
|||
|
a47d3e0c6a
|
1
Brewfile
1
Brewfile
@@ -1,5 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
brew 'autoconf'
|
||||
brew 'coreutils'
|
||||
brew 'curl'
|
||||
brew 'expat'
|
||||
|
||||
101
CHANGELOG.md
101
CHANGELOG.md
@@ -2,6 +2,107 @@
|
||||
|
||||
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.16](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.15...0.4.16) (2021-06-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiling:** improve portability of builds ([ca2d4c3](https://github.com/jimeh/build-emacs-for-macos/commit/ca2d4c38f69c434c77c266594104bfbf34ad5221))
|
||||
* **native_comp:** crash on launch when gcc homebrew package was not installed ([bd81870](https://github.com/jimeh/build-emacs-for-macos/commit/bd8187065928b9f79de8b14222c98f8dc34bfe5f))
|
||||
|
||||
### [0.4.15](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.14...0.4.15) (2021-05-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **github:** perform authenticated GitHub API requests when GITHUB_TOKEN env var is set ([deda28e](https://github.com/jimeh/build-emacs-for-macos/commit/deda28e5aded2817bcc7956f377378576372816f))
|
||||
|
||||
### [0.4.14](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.13...0.4.14) (2021-05-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **cli:** add "emacs" CLI launcher script to Emacs.app/Conents/MacOS/bin ([8237aa9](https://github.com/jimeh/build-emacs-for-macos/commit/8237aa9272ce1d13a412b2495cbaa90df38d928b)), closes [#41](https://github.com/jimeh/build-emacs-for-macos/issues/41)
|
||||
|
||||
### [0.4.13](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.12...0.4.13) (2021-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **codesign:** prevent "bundle format unrecognized" error from codesign ([7259111](https://github.com/jimeh/build-emacs-for-macos/commit/7259111478ecb838dea9c8f50ea39eafdf47ed5a))
|
||||
* **embed:** avoid potential error caused by trying to set duplicate rpath ([bb45cda](https://github.com/jimeh/build-emacs-for-macos/commit/bb45cda0231e99618571dc835348cf5c3345e277))
|
||||
|
||||
### [0.4.12](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.11...0.4.12) (2021-05-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **shared-libraries:** stop aggressive dylib re-linking ([0a22d83](https://github.com/jimeh/build-emacs-for-macos/commit/0a22d8393c53305354c4c6d8e784e7d59caa039a)), closes [#12](https://github.com/jimeh/build-emacs-for-macos/issues/12)
|
||||
* **svg:** enable SVG by default via librsvg ([bf7c4d5](https://github.com/jimeh/build-emacs-for-macos/commit/bf7c4d5debf32980dbbabc1ea99b58b266390011))
|
||||
|
||||
### [0.4.11](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.10...0.4.11) (2021-05-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **builds:** update build script for new plan.yml format ([1df39fa](https://github.com/jimeh/build-emacs-for-macos/commit/1df39fafe62ada385aa1d92e6b7f591c16c0a80c))
|
||||
* **release:** initial attempt at providing automatic builds ([6328921](https://github.com/jimeh/build-emacs-for-macos/commit/63289216d70e496d664a7e3078dea5a82eb8f65d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **release:** attempt to fix issue with talking to GitHub API ([272a300](https://github.com/jimeh/build-emacs-for-macos/commit/272a3000a1f96d8f131e684736127b923513a205))
|
||||
|
||||
### [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)
|
||||
|
||||
|
||||
|
||||
2
Gemfile
2
Gemfile
@@ -5,4 +5,6 @@ source 'http://rubygems.org/'
|
||||
group :development do
|
||||
gem 'byebug'
|
||||
gem 'rubocop'
|
||||
gem 'rubocop-daemon'
|
||||
gem 'solargraph', '~> 0.39.17'
|
||||
end
|
||||
|
||||
17
Makefile
17
Makefile
@@ -1,9 +1,12 @@
|
||||
.PHONY: new-version
|
||||
new-version:
|
||||
$(if $(shell which npx),,\
|
||||
$(error No npx found in PATH, please install NodeJS))
|
||||
$(if $(shell which standard-version),,\
|
||||
$(error No standard-version found in PATH, install with: \
|
||||
npm install -g standard-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))
|
||||
|
||||
112
README.md
112
README.md
@@ -1,7 +1,8 @@
|
||||
# build-emacs-for-macos
|
||||
|
||||
My personal hacked together script for building a completely self-contained
|
||||
Emacs.app application on macOS, from any git branch, tag, or ref.
|
||||
Emacs.app application on macOS, from any git branch, tag, or ref. With support
|
||||
for native-compilation.
|
||||
|
||||
Use this script at your own risk.
|
||||
|
||||
@@ -18,7 +19,7 @@ Use this script at your own risk.
|
||||
|
||||
## Status
|
||||
|
||||
As of writing (2020-10-04) 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:
|
||||
|
||||
@@ -29,8 +30,8 @@ I have successfully built:
|
||||
For reference, my machine is:
|
||||
|
||||
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
|
||||
- macOS 10.15.6 (19G2021)
|
||||
- Xcode 12.0
|
||||
- macOS Big Sur 11.2.3 (20D91)
|
||||
- Xcode 12.4 (12D4e)
|
||||
|
||||
## Limitations
|
||||
|
||||
@@ -71,16 +72,16 @@ available here: https://github.com/emacs-mirror/emacs
|
||||
Options:
|
||||
-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
|
||||
--[no-]xwidgets Enable/disable XWidgets (default: enabled if supported)
|
||||
--[no-]xwidgets Enable/disable XWidgets if supported (default: enabled)
|
||||
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
|
||||
--[no-]native-march Enable/disable -march=native CFLAG(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)
|
||||
--rsvg Enable SVG image support via librsvg, can yield a unstable build (default: disabled)
|
||||
--[no-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
|
||||
--no-titlebar Apply no-titlebar 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.
|
||||
--[no-]github-auth Make authenticated GitHub API requests if GITHUB_TOKEN environment variable is set.(default: enabled)
|
||||
--work-dir DIR Specify a working directory where tarballs, sources, and builds will be stored and worked with
|
||||
--plan FILE Follow given plan file, instead of using given git ref/sha
|
||||
```
|
||||
|
||||
Resulting applications are saved to the `builds` directory in a bzip2 compressed
|
||||
@@ -94,8 +95,8 @@ trash the corresponding directory from the `sources` directory.
|
||||
|
||||
### Examples
|
||||
|
||||
To download a tarball of the `master` branch (Emacs 28.x as of writing) and
|
||||
build Emacs.app from it:
|
||||
To download a tarball of the `master` branch (Emacs 28.x with native-compilation
|
||||
as of writing) and build Emacs.app from it:
|
||||
|
||||
```
|
||||
./build-emacs-for-macos
|
||||
@@ -112,77 +113,76 @@ All sources as downloaded as tarballs from the
|
||||
to get a list of tags/branches available to install, simply check said
|
||||
repository.
|
||||
|
||||
## Use Self-Contained Emacs.app as `emacs` CLI Tool
|
||||
## Use 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.
|
||||
Builds come with a custom `emacs` shell script launcher for use from the command
|
||||
line. It makes sure to use the main `Emacs.app/Contents/MacOS/Emacs` executable
|
||||
from the correct path, ensuring it finds all the relevant dependencies within
|
||||
the Emacs.app bundle.
|
||||
|
||||
Personally I use something similar to this:
|
||||
To use it, simply add `Emacs.app/Contents/MacOS/bin` to your `PATH`. For
|
||||
example, if you place Emacs.app in `/Applications`:
|
||||
|
||||
```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"
|
||||
if [ -d "/Applications/Emacs.app/Contents/MacOS/bin" ]; then
|
||||
export PATH="/Applications/Emacs.app/Contents/MacOS/bin:$PATH"
|
||||
alias emacs="emacs -nw" # Always launch "emacs" in terminal mode.
|
||||
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.
|
||||
If you want `emacs` in your terminal to launch a GUI instance of Emacs, don't
|
||||
use the alias from the above example.
|
||||
|
||||
## Native-Comp
|
||||
|
||||
Building a Emacs.app with native-comp support
|
||||
([gccemacs](https://akrl.sdf.org/gccemacs.html)) from the `feature/native-comp`
|
||||
branch is now supported without much hassle thanks to the newly released
|
||||
`libgccjit` Homebrew formula.
|
||||
_Note: On 2021-04-25 the `feature/native-comp` branch was
|
||||
[merged](http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=289000eee729689b0cf362a21baa40ac7f9506f6)
|
||||
into `master`._
|
||||
|
||||
Changes from the `feature/native-comp-macos-fixes` branch are also applied
|
||||
through a custom patch process which should be more future-proof compared to a
|
||||
regular git diff patch.
|
||||
|
||||
To build a Emacs.app with native compilation enabled, simply run:
|
||||
|
||||
```
|
||||
./build-emacs-for-macos feature/native-comp
|
||||
```
|
||||
The build script will automatically detect if the source tree being built
|
||||
supports native-compilation, and enable it if available. You can override the
|
||||
auto-detection logic to force enable or force disable native-compilation by
|
||||
passing `--native-comp` or `--no-native-comp` respectfully.
|
||||
|
||||
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
|
||||
lisp files will be dynamically compiled in the background the first time you use
|
||||
them. To enable native full AoT, pass in the `--native-full-aot` option.
|
||||
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.
|
||||
|
||||
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.
|
||||
To enable native full Ahead-of-Time compilation, pass in the `--native-full-aot`
|
||||
option, which will native-compile all of Emacs' elisp at 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.
|
||||
|
||||
### Configuration
|
||||
|
||||
Add the following near the top of your `early-init.el` or `init.el`:
|
||||
|
||||
```elisp
|
||||
(setq comp-speed 2)
|
||||
```
|
||||
#### Native-Lisp Cache Directory
|
||||
|
||||
By default natively compiled `*.eln` files will be cached in
|
||||
`~/.emacs.d/eln-cache/`. If you want to customize that, simply set a new path as
|
||||
the first element of the `comp-eln-load-path` variable. The path string must end
|
||||
with a `/`.
|
||||
the first element of the `native-comp-eln-load-path` variable. The path string
|
||||
must end with a `/`.
|
||||
|
||||
Below is an example which stores all compiled `*.eln` files in `cache/eln-cache`
|
||||
within your Emacs configuration directory:
|
||||
|
||||
```elisp
|
||||
(when (boundp 'comp-eln-load-path)
|
||||
(setcar comp-eln-load-path
|
||||
(when (boundp 'native-comp-eln-load-path)
|
||||
(setcar native-comp-eln-load-path
|
||||
(expand-file-name "cache/eln-cache/" user-emacs-directory)))
|
||||
```
|
||||
|
||||
#### Compilation Warnings
|
||||
|
||||
By default any warnings encountered during async native compilation will pop up
|
||||
a warnings buffer. As this tends to happen rather frequently with a lot of
|
||||
packages, it can get annoying. You can disable showing these warnings by setting
|
||||
`native-comp-async-report-warnings-errors` to `nil`:
|
||||
|
||||
```elisp
|
||||
(setq native-comp-async-report-warnings-errors nil)
|
||||
```
|
||||
|
||||
### Issues
|
||||
|
||||
Please see all issues with the
|
||||
@@ -193,7 +193,7 @@ types of issues and or behavior you can expect.
|
||||
### Known Good Commits/Builds
|
||||
|
||||
A list of known "good" commits which produce working builds is tracked in:
|
||||
[#6 Known good commits of feature/native-comp branch](https://github.com/jimeh/build-emacs-for-macos/issues/6)
|
||||
[#6 Known good commits for native-comp](https://github.com/jimeh/build-emacs-for-macos/issues/6)
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@ require 'json'
|
||||
require 'net/http'
|
||||
require 'optparse'
|
||||
require 'pathname'
|
||||
require 'time'
|
||||
require 'uri'
|
||||
require 'yaml'
|
||||
|
||||
class Error < StandardError; end
|
||||
|
||||
@@ -21,9 +23,9 @@ module Output
|
||||
|
||||
def out(msg, newline: true)
|
||||
if newline
|
||||
puts "==> #{msg}"
|
||||
warn "==> #{msg}"
|
||||
else
|
||||
print "==> #{msg}"
|
||||
STDERR.print "==> #{msg}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,24 +71,27 @@ end
|
||||
class Build
|
||||
include Output
|
||||
|
||||
DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s'
|
||||
LATEST_URL = 'https://api.github.com/repos/emacs-mirror/emacs/commits/%s'
|
||||
NATIVE_COMP_REF_REGEXP = %r{^feature/native-comp}.freeze
|
||||
EMACS_MIRROR_REPO = 'emacs-mirror/emacs'
|
||||
DOWNLOAD_URL = 'https://api.github.com/repos/emacs-mirror/emacs/tarball/%s'
|
||||
|
||||
attr_reader :root_dir
|
||||
attr_reader :source_dir
|
||||
attr_reader :ref
|
||||
attr_reader :options
|
||||
attr_reader :gcc_info
|
||||
|
||||
def initialize(root_dir, ref = nil, options = {})
|
||||
@root_dir = root_dir
|
||||
@ref = ref
|
||||
@ref = ref || 'master'
|
||||
@options = options
|
||||
@gcc_info = GccInfo.new
|
||||
end
|
||||
|
||||
def build
|
||||
load_plan(options[:plan]) if options[:plan]
|
||||
|
||||
unless meta[:sha] && meta[:date]
|
||||
err 'Failed to get commit info from GitHub API.'
|
||||
err 'Failed to get commit info from GitHub.'
|
||||
end
|
||||
|
||||
tarball = download_tarball(meta[:sha])
|
||||
@@ -97,15 +102,27 @@ class Build
|
||||
|
||||
app = compile_source(@source_dir)
|
||||
symlink_internals(app)
|
||||
add_cli_helper(app)
|
||||
|
||||
LibEmbedder.new(app, brew_dir, extra_libs).embed
|
||||
GccLibEmbedder.new(app, gcc_dir).embed if options[:native_comp]
|
||||
GccLibEmbedder.new(app, gcc_info).embed if options[:native_comp]
|
||||
|
||||
archive_app(app)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_plan(filename)
|
||||
plan = YAML.safe_load(File.read(filename), [:Time])
|
||||
|
||||
@meta = {
|
||||
sha: plan.dig('commit', 'sha'),
|
||||
ref: plan.dig('commit', 'ref'),
|
||||
date: plan.dig('commit', 'date')
|
||||
}
|
||||
@archive_filename = plan['archive']
|
||||
end
|
||||
|
||||
def tarballs_dir
|
||||
@tarballs_dir ||= File.join(root_dir, 'tarballs')
|
||||
end
|
||||
@@ -122,19 +139,11 @@ class Build
|
||||
@brew_dir ||= `brew --prefix`.chomp
|
||||
end
|
||||
|
||||
def gcc_dir
|
||||
@gcc_dir ||= `brew --prefix gcc`.chomp
|
||||
end
|
||||
|
||||
def libgccjit_dir
|
||||
@libgccjit_dir ||= `brew --prefix libgccjit`.chomp
|
||||
end
|
||||
|
||||
def extra_libs
|
||||
@extra_libs ||= [
|
||||
"#{brew_dir}/opt/expat/lib/libexpat.1.dylib",
|
||||
"#{brew_dir}/opt/libiconv/lib/libiconv.2.dylib",
|
||||
"#{brew_dir}/opt/zlib/lib/libz.1.dylib"
|
||||
File.join(brew_dir, 'opt/expat/lib/libexpat.1.dylib'),
|
||||
File.join(brew_dir, 'opt/libiconv/lib/libiconv.2.dylib'),
|
||||
File.join(brew_dir, 'opt/zlib/lib/libz.1.dylib')
|
||||
]
|
||||
end
|
||||
|
||||
@@ -152,8 +161,20 @@ class Build
|
||||
|
||||
info 'Downloading tarball from GitHub. This could take a while, ' \
|
||||
'please be patient.'
|
||||
result = run_cmd('curl', '-L', url, '-o', target)
|
||||
err 'Download failed.' unless result
|
||||
|
||||
args = ['curl', '-L', url, '-o', target]
|
||||
log_args = args.clone
|
||||
|
||||
if options[:github_auth] && ENV['GITHUB_TOKEN']
|
||||
args = [args[0]] +
|
||||
['-H', "Authorization: Token #{ENV['GITHUB_TOKEN']}"] + args[1..-1]
|
||||
log_args = [log_args[0]] +
|
||||
['-H', '"Authorization: Token $GITHUB_TOKEN"'] +
|
||||
log_args[1..-1]
|
||||
end
|
||||
|
||||
out "CMD: #{log_args.join(' ')}"
|
||||
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||
|
||||
target
|
||||
end
|
||||
@@ -186,14 +207,20 @@ class Build
|
||||
@configure_help
|
||||
end
|
||||
|
||||
def supports_native_comp?
|
||||
@supports_native_comp ||= !!configure_help.match(/\s+--with-nativecomp\s+/)
|
||||
end
|
||||
|
||||
def supports_xwidgets?
|
||||
@supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/)
|
||||
end
|
||||
|
||||
def 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
|
||||
info 'Detecting native-comp support: ', newline: false
|
||||
options[:native_comp] = supports_native_comp?
|
||||
@@ -206,30 +233,6 @@ class Build
|
||||
err 'This emacs source tree does not support native-comp'
|
||||
end
|
||||
|
||||
def verify_libgccjit
|
||||
err 'gcc not installed' unless Dir.exist?(gcc_dir)
|
||||
err 'libgccjit not installed' unless Dir.exist?(libgccjit_dir)
|
||||
|
||||
if Dir["#{libgccjit_dir}/lib/**/libgccjit.so*"].empty?
|
||||
err "Detected libgccjit (#{libgccjit_dir}) does not have any " \
|
||||
'libgccjit.so* files. Please try reinstalling libgccjit: ' \
|
||||
'brew reinstall libgccjit'
|
||||
end
|
||||
|
||||
dirs = Dir["{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*"]
|
||||
return if dirs.map { |dir| File.basename(dir) }.uniq == %w[10]
|
||||
|
||||
err 'Detected gcc and libgccjit library paths do not belong to the ' \
|
||||
"same major version. Detected paths:\n - #{dirs.join(' - ')}"
|
||||
end
|
||||
|
||||
def gcc_library_paths
|
||||
@gcc_library_paths ||= Dir[
|
||||
"{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*",
|
||||
"{#{gcc_dir},#{libgccjit_dir}}/lib/gcc/*/gcc/*apple-darwin*/*"
|
||||
].sort_by { |p| [p.size, p] }
|
||||
end
|
||||
|
||||
def autogen
|
||||
FileUtils.cd(source_dir) do
|
||||
if File.exist?('autogen/copy_autogen')
|
||||
@@ -241,10 +244,10 @@ class Build
|
||||
end
|
||||
|
||||
def compile_source(source)
|
||||
target = "#{source}/nextstep"
|
||||
emacs_app = "#{target}/Emacs.app"
|
||||
target = File.join(source, 'nextstep')
|
||||
emacs_app = File.join(target, 'Emacs.app')
|
||||
|
||||
if File.exist?("#{target}/Emacs.app")
|
||||
if File.exist?(emacs_app)
|
||||
info 'Emacs.app already exists in ' \
|
||||
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use."
|
||||
return emacs_app
|
||||
@@ -256,53 +259,61 @@ class Build
|
||||
if options[:native_comp]
|
||||
info 'Compiling with native-comp enabled'
|
||||
verify_native_comp
|
||||
verify_libgccjit
|
||||
gcc_info.verify_libgccjit
|
||||
|
||||
apply_native_comp_env_setup_patch(source)
|
||||
|
||||
ENV['CFLAGS'] = [
|
||||
"-I#{gcc_dir}/include",
|
||||
"-I#{File.join(gcc_info.root_dir, 'include')}",
|
||||
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
|
||||
'-O2',
|
||||
'-march=native'
|
||||
(options[:native_march] ? '-march=native' : nil),
|
||||
ENV['CFLAGS']
|
||||
].compact.join(' ')
|
||||
|
||||
ENV['LDFLAGS'] = [
|
||||
gcc_library_paths.map { |path| "-L#{path}" },
|
||||
"-I#{gcc_dir}/include",
|
||||
"-I#{libgccjit_dir}/include"
|
||||
].flatten.compact.join(' ')
|
||||
"-L#{gcc_info.lib_dir}",
|
||||
"-L#{gcc_info.darwin_lib_dir}",
|
||||
"-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'] = [
|
||||
gcc_library_paths,
|
||||
gcc_info.lib_dir,
|
||||
gcc_info.darwin_lib_dir,
|
||||
gcc_info.libgccjit_lib_dir,
|
||||
ENV['LIBRARY_PATH']
|
||||
].flatten.compact.join(':')
|
||||
].compact.join(':')
|
||||
end
|
||||
|
||||
ENV['CC'] = 'clang'
|
||||
ENV['PKG_CONFIG_PATH'] = [
|
||||
"#{brew_dir}/lib/pkgconfig",
|
||||
"#{brew_dir}/share/pkgconfig",
|
||||
"#{brew_dir}/opt/expat/lib/pkgconfig",
|
||||
"#{brew_dir}/opt/libxml2/lib/pkgconfig",
|
||||
"#{brew_dir}/opt/ncurses/lib/pkgconfig",
|
||||
"#{brew_dir}/opt/zlib/lib/pkgconfig",
|
||||
"#{brew_dir}/Homebrew/Library/Homebrew/os/mac/pkgconfig/#{OS.version}",
|
||||
File.join(brew_dir, 'lib/pkgconfig'),
|
||||
File.join(brew_dir, 'share/pkgconfig'),
|
||||
File.join(brew_dir, 'opt/expat/lib/pkgconfig'),
|
||||
File.join(brew_dir, 'opt/libxml2/lib/pkgconfig'),
|
||||
File.join(brew_dir, 'opt/ncurses/lib/pkgconfig'),
|
||||
File.join(brew_dir, 'opt/zlib/lib/pkgconfig'),
|
||||
File.join(brew_dir, 'Homebrew/Library/Homebrew/os/mac/pkgconfig',
|
||||
OS.version.to_s),
|
||||
ENV['PKG_CONFIG_PATH']
|
||||
].compact.join(':')
|
||||
|
||||
ENV['PATH'] = [
|
||||
"#{brew_dir}/opt/make/libexec/gnubin",
|
||||
"#{brew_dir}/opt/coreutils/libexec/gnubin",
|
||||
"#{brew_dir}/opt/gnu-sed/libexec/gnubin",
|
||||
"#{brew_dir}/bin",
|
||||
"#{brew_dir}/opt/texinfo/bin",
|
||||
File.join(brew_dir, 'opt/make/libexec/gnubin'),
|
||||
File.join(brew_dir, 'opt/coreutils/libexec/gnubin'),
|
||||
File.join(brew_dir, 'opt/gnu-sed/libexec/gnubin'),
|
||||
File.join(brew_dir, 'bin'),
|
||||
File.join(brew_dir, 'opt/texinfo/bin'),
|
||||
ENV['PATH']
|
||||
].compact.join(':')
|
||||
|
||||
|
||||
ENV['LIBRARY_PATH'] = [
|
||||
ENV['LIBRARY_PATH'],
|
||||
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
|
||||
].compact.join(':')
|
||||
ENV['LIBRARY_PATH'],
|
||||
'/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib'
|
||||
].compact.join(':')
|
||||
|
||||
configure_flags = [
|
||||
'--with-ns',
|
||||
@@ -314,8 +325,8 @@ class Build
|
||||
if options[:xwidgets] && supports_xwidgets?
|
||||
configure_flags << '--with-xwidgets'
|
||||
end
|
||||
configure_flags << '--with-nativecomp' if options[:native_comp]
|
||||
configure_flags << '--without-rsvg' unless options[:rsvg]
|
||||
configure_flags << native_comp_configure_flag if options[:native_comp]
|
||||
configure_flags << '--without-rsvg' if options[:rsvg] == false
|
||||
|
||||
run_cmd './configure', *configure_flags
|
||||
|
||||
@@ -330,17 +341,17 @@ class Build
|
||||
make_flags = []
|
||||
make_flags += ['-j', options[:parallel].to_s] if options[:parallel]
|
||||
|
||||
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
|
||||
|
||||
if options[:native_comp]
|
||||
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
|
||||
|
||||
run_cmd 'make', *make_flags
|
||||
@@ -355,41 +366,70 @@ class Build
|
||||
def symlink_internals(app)
|
||||
return unless options[:native_comp]
|
||||
|
||||
info 'Creating symlinks within Emacs.app needed for native-comp'
|
||||
|
||||
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')
|
||||
|
||||
source = Dir['MacOS/libexec/emacs/**/eln-cache',
|
||||
'MacOS/lib/emacs/**/native-lisp'].first
|
||||
err 'Failed to find native-lisp cache directory for symlink creation.'
|
||||
|
||||
target = File.basename(source)
|
||||
FileUtils.ln_s(source, target) unless File.exist?(target)
|
||||
end
|
||||
end
|
||||
|
||||
def archive_app(app)
|
||||
FileUtils.mkdir_p(builds_dir)
|
||||
def add_cli_helper(app)
|
||||
source = File.join(__dir__, 'helper', 'emacs-cli.bash')
|
||||
target = File.join(app, 'Contents', 'MacOS', 'bin', 'emacs')
|
||||
dir = File.dirname(target)
|
||||
|
||||
info "Adding \"emacs\" CLI helper to #{dir}"
|
||||
|
||||
FileUtils.mkdir_p(dir)
|
||||
FileUtils.cp(source, target)
|
||||
FileUtils.chmod('+w', target)
|
||||
end
|
||||
|
||||
def archive_filename
|
||||
return @archive_filename if @archive_filename
|
||||
|
||||
metadata = [
|
||||
meta[:ref]&.gsub(/\W/, '-'),
|
||||
meta[:date],
|
||||
meta[:date]&.strftime('%Y-%m-%d'),
|
||||
meta[:sha][0..6],
|
||||
"macOS-#{OS.version}",
|
||||
OS.arch
|
||||
].compact
|
||||
|
||||
filename = "Emacs.app-[#{metadata.join('][')}].tbz"
|
||||
target = "#{builds_dir}/#{filename}"
|
||||
@archive_filename = File.join(builds_dir, filename)
|
||||
end
|
||||
|
||||
def archive_app(app)
|
||||
filename = File.basename(archive_filename)
|
||||
target_dir = File.dirname(archive_filename)
|
||||
relative_target_dir = target_dir.gsub(root_dir + '/', '')
|
||||
|
||||
FileUtils.mkdir_p(target_dir)
|
||||
|
||||
app_base = File.basename(app)
|
||||
app_dir = File.dirname(app)
|
||||
|
||||
if !File.exist?(target)
|
||||
info "Creating #{filename} archive in \"#{builds_dir}\"..."
|
||||
FileUtils.cd(app_dir) { system('tar', '-cjf', target, app_base) }
|
||||
if !File.exist?(archive_filename)
|
||||
info "Creating #{filename} archive in \"#{relative_target_dir}\"..."
|
||||
FileUtils.cd(app_dir) do
|
||||
system('tar', '-cjf', archive_filename, app_base)
|
||||
end
|
||||
else
|
||||
info "#{filename} archive exists in " \
|
||||
"#{builds_dir.gsub(root_dir + '/', '')}, skipping archving."
|
||||
"#{relative_target_dir}, skipping archving."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -412,22 +452,34 @@ class Build
|
||||
return @meta if @meta
|
||||
|
||||
ref_sha = options[:git_sha] || ref
|
||||
url = format(LATEST_URL, ref_sha)
|
||||
commit_json = http_get(url)
|
||||
info "Fetching info for git ref: #{ref_sha}"
|
||||
commit_json = github_api_get(
|
||||
"/repos/#{EMACS_MIRROR_REPO}/commits/#{ref_sha}"
|
||||
)
|
||||
err "Failed to get commit info about: #{ref_sha}" if commit_json.nil?
|
||||
|
||||
commit = JSON.parse(commit_json)
|
||||
meta = {
|
||||
sha: commit['sha'],
|
||||
date: Date.parse(commit['commit']['committer']['date'])
|
||||
date: Time.parse(commit['commit']['committer']['date'])
|
||||
}
|
||||
meta[:ref] = ref if ref && ref[0..6] != meta[:sha][0..6]
|
||||
|
||||
@meta = meta
|
||||
end
|
||||
|
||||
def http_get(url)
|
||||
response = Net::HTTP.get_response(URI.parse(url))
|
||||
def github_api_get(uri)
|
||||
uri = URI.join('https://api.github.com/', uri)
|
||||
|
||||
http = Net::HTTP.new(uri.hostname, uri.port)
|
||||
http.use_ssl = true if uri.scheme == 'https'
|
||||
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
if options[:github_auth] && ENV['GITHUB_TOKEN']
|
||||
request['Authorization'] = "Token #{ENV['GITHUB_TOKEN']}"
|
||||
end
|
||||
|
||||
response = http.request(request)
|
||||
return unless response.code == '200'
|
||||
|
||||
response.body
|
||||
@@ -443,10 +495,14 @@ class Build
|
||||
file = 'lisp/emacs-lisp/comp.el'
|
||||
return if `grep '#{term}' '#{file}'`.strip.size.positive?
|
||||
|
||||
apply_patch(
|
||||
{ file: "#{__dir__}/patches/native-comp-env-setup.patch" },
|
||||
source
|
||||
template = File.read(
|
||||
File.join(__dir__, 'patches/native-comp-env-setup.diff.erb')
|
||||
)
|
||||
patch = ERB.new(template).result(gcc_info.get_binding)
|
||||
patch_file = File.join(source, 'macos_patches/native-comp-env-setup.diff')
|
||||
|
||||
File.write(patch_file, patch)
|
||||
apply_patch({ file: patch_file }, source)
|
||||
end
|
||||
|
||||
def effective_version
|
||||
@@ -520,7 +576,7 @@ class Build
|
||||
patch_dir = "#{target}/macos_patches"
|
||||
run_cmd('mkdir', '-p', patch_dir)
|
||||
|
||||
patch_file = "#{patch_dir}/patch-{num}.diff"
|
||||
patch_file = File.join(patch_dir, 'patch-{num}.diff')
|
||||
num = 1
|
||||
while File.exist?(patch_file.gsub('{num}', num.to_s.rjust(3, '0')))
|
||||
num += 1
|
||||
@@ -563,16 +619,16 @@ class AbstractEmbedder
|
||||
|
||||
private
|
||||
|
||||
def invocation_dir
|
||||
File.join(app, 'Contents', 'MacOS')
|
||||
end
|
||||
|
||||
def bin
|
||||
"#{app}/Contents/MacOS/Emacs"
|
||||
File.join(invocation_dir, 'Emacs')
|
||||
end
|
||||
|
||||
def lib_dir
|
||||
"#{app}/Contents/MacOS/#{lib_dir_name}"
|
||||
end
|
||||
|
||||
def lib_dir_name
|
||||
'lib'
|
||||
File.join(invocation_dir, 'lib')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -596,18 +652,51 @@ class LibEmbedder < AbstractEmbedder
|
||||
FileUtils.cd(File.dirname(app)) do
|
||||
copy_libs(binary)
|
||||
copy_extra_libs(extra_libs, binary) if extra_libs.any?
|
||||
self_ref_libs(binary)
|
||||
if eln_files.any?
|
||||
info "Embedding libraries for #{eln_files.size} *.eln files " \
|
||||
'within Emacs.app'
|
||||
rel_path = Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(binary))
|
||||
).to_s
|
||||
eln_files.each { |f| copy_libs(f, rel_path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def eln_files
|
||||
@eln_files ||= Dir[
|
||||
File.join(
|
||||
app, 'Contents', 'Resources', 'native-lisp', '**', '*.eln'
|
||||
),
|
||||
File.join(
|
||||
app, 'Contents', 'MacOS', 'lib', 'emacs', '**',
|
||||
'native-lisp', '**', '*.eln'
|
||||
),
|
||||
File.join(
|
||||
app, 'Contents', 'MacOS', 'libexec', 'emacs', '**',
|
||||
'eln-cache', '**', '*.eln'
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
def copy_libs(exe, rel_path = nil)
|
||||
exe_file = File.basename(exe)
|
||||
rel_path ||= Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(exe))
|
||||
).to_s
|
||||
|
||||
rpath = File.join('@executable_path', rel_path)
|
||||
rpaths = `otool -l "#{exe}" | grep -A 2 'cmd LC_RPATH' | grep 'path'`
|
||||
|
||||
unless rpaths.include?(rpath)
|
||||
while_writable(exe) do
|
||||
system('install_name_tool', '-add_rpath',
|
||||
File.join('@executable_path', rel_path), exe)
|
||||
end
|
||||
end
|
||||
|
||||
`otool -L "#{exe}"`.split("\n")[1..-1].each do |line|
|
||||
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
|
||||
next unless match && match[1].start_with?(lib_source)
|
||||
@@ -615,18 +704,18 @@ class LibEmbedder < AbstractEmbedder
|
||||
while_writable(exe) do
|
||||
if match[2] == exe_file
|
||||
system('install_name_tool', '-id',
|
||||
"@executable_path/#{rel_path}/#{match[2]}", exe)
|
||||
File.join('@executable_path', rel_path, match[2].to_s), exe)
|
||||
else
|
||||
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
|
||||
|
||||
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.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
|
||||
|
||||
@@ -645,52 +734,28 @@ class LibEmbedder < AbstractEmbedder
|
||||
|
||||
while_writable(target) do
|
||||
system('install_name_tool', '-id',
|
||||
"@executable_path/#{rel_path}/#{lib_file}", target)
|
||||
File.join('@executable_path', rel_path, lib_file), target)
|
||||
end
|
||||
|
||||
copy_libs(target, rel_path)
|
||||
end
|
||||
end
|
||||
|
||||
def self_ref_libs(exe)
|
||||
rel_path = Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(exe))
|
||||
).to_s
|
||||
lib_paths ||= Dir.glob("#{lib_dir}/*").select { |f| File.file?(f) }
|
||||
libs = lib_paths.map { |f| File.basename(f) }
|
||||
|
||||
([exe] + lib_paths).each do |bin_path|
|
||||
`otool -L "#{bin_path}"`.split("\n")[1..-1].each do |line|
|
||||
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
|
||||
next unless match
|
||||
next if match[1].start_with?('@executable_path/')
|
||||
next unless libs.include?(match[2])
|
||||
|
||||
while_writable(bin_path) do
|
||||
system(
|
||||
'install_name_tool', '-change', match[1],
|
||||
"@executable_path/#{rel_path}/#{match[2]}",
|
||||
bin_path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def while_writable(file)
|
||||
mode = File.stat(file).mode
|
||||
File.chmod(0o775, file)
|
||||
yield
|
||||
ensure
|
||||
File.chmod(mode, file)
|
||||
end
|
||||
end
|
||||
|
||||
class GccLibEmbedder < AbstractEmbedder
|
||||
attr_reader :gcc_dir
|
||||
attr_reader :gcc_info
|
||||
|
||||
def initialize(app, gcc_dir)
|
||||
def initialize(app, gcc_info)
|
||||
super(app)
|
||||
@gcc_dir = gcc_dir
|
||||
@gcc_info = gcc_info
|
||||
end
|
||||
|
||||
def embed
|
||||
@@ -700,44 +765,150 @@ class GccLibEmbedder < AbstractEmbedder
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
FileUtils.mkdir_p(File.dirname(target_dir))
|
||||
FileUtils.cp_r(source_dir, target_dir)
|
||||
FileUtils.rm(Dir[File.join(target_dir, '**', '.DS_Store')], force: true)
|
||||
FileUtils.chmod_R('u+w', target_dir)
|
||||
FileUtils.mv(source_darwin_dir, target_darwin_dir)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def embedded?
|
||||
Dir[File.join(target_dir, 'libgccjit.so*')].any?
|
||||
Dir[File.join(target_dir, 'libgcc*')].any?
|
||||
end
|
||||
|
||||
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', '*', 'libgcc*')]
|
||||
.map { |path| File.basename(File.dirname(path)) }
|
||||
.select { |path| path.match(/^\d+$/) }
|
||||
.uniq.map(&:to_i).max.to_s
|
||||
def source_darwin_dir
|
||||
File.join(invocation_dir, gcc_info.relative_darwin_lib_dir)
|
||||
end
|
||||
|
||||
def target_darwin_dir
|
||||
File.join(invocation_dir, gcc_info.sanitized_relative_darwin_lib_dir)
|
||||
end
|
||||
|
||||
def source_dir
|
||||
@source_dir ||= File.join(gcc_dir, 'lib', 'gcc', gcc_version)
|
||||
gcc_info.lib_dir
|
||||
end
|
||||
|
||||
def relative_dir(path, root)
|
||||
Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
|
||||
end
|
||||
end
|
||||
|
||||
class GccInfo
|
||||
include Output
|
||||
|
||||
def root_dir
|
||||
@root_dir ||= `brew --prefix gcc`.chomp
|
||||
end
|
||||
|
||||
def major_version
|
||||
@major_version ||= File.basename(lib_dir)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
# Sanitize folder name with full "MAJOR.MINOR.PATCH" version number to just
|
||||
# the MAJOR version. Apple's codesign CLI tool throws a "bundle format
|
||||
# unrecognized" error if there are any folders with two dots in their name
|
||||
# within the Emacs.app application bundle.
|
||||
def sanitized_relative_darwin_lib_dir
|
||||
@sanitized_relative_darwin_lib_dir ||= File.join(
|
||||
File.dirname(relative_darwin_lib_dir),
|
||||
File.basename(relative_darwin_lib_dir).split('.').first
|
||||
)
|
||||
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
|
||||
|
||||
return if major_version == libgccjit_major_version
|
||||
|
||||
err <<~TEXT
|
||||
Detected GCC and libgccjit library paths do not belong to the same major
|
||||
version of GCC. Detected paths:
|
||||
- #{lib_dir}
|
||||
- #{libgccjit_lib_dir}
|
||||
TEXT
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def relative_dir(path, root)
|
||||
Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
|
||||
end
|
||||
end
|
||||
|
||||
if __FILE__ == $PROGRAM_NAME
|
||||
cli_options = {
|
||||
macos_fixes: true,
|
||||
work_dir: File.expand_path(__dir__),
|
||||
native_full_aot: false,
|
||||
native_march: false,
|
||||
parallel: Etc.nprocessors,
|
||||
rsvg: false,
|
||||
xwidgets: true
|
||||
rsvg: true,
|
||||
xwidgets: true,
|
||||
github_auth: true
|
||||
}
|
||||
|
||||
begin
|
||||
@@ -757,14 +928,15 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:parallel] = v
|
||||
end
|
||||
|
||||
opts.on('--git-sha SHA', 'Override detected git SHA of specified ' \
|
||||
'branch allowing builds of old commits') do |v|
|
||||
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|
|
||||
'Enable/disable XWidgets if supported ' \
|
||||
'(default: enabled)') do |v|
|
||||
cli_options[:xwidgets] = v
|
||||
end
|
||||
|
||||
@@ -774,21 +946,22 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:native_comp] = v
|
||||
end
|
||||
|
||||
opts.on('--[no-]native-march',
|
||||
'Enable/disable -march=native CFLAG' \
|
||||
'(default: disabled)') do |v|
|
||||
cli_options[:native_march] = 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('--[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('--rsvg', 'Enable SVG image support via librsvg, ' \
|
||||
'can yield a unstable build (default: disabled)') do
|
||||
cli_options[:rsvg] = true
|
||||
opts.on('--[no-]rsvg',
|
||||
'Enable/disable SVG image support via librsvg ' \
|
||||
'(default: enabled)') do |v|
|
||||
cli_options[:rsvg] = v
|
||||
end
|
||||
|
||||
opts.on('--no-titlebar', 'Apply no-titlebar patch (default: disabled)') do
|
||||
@@ -800,25 +973,29 @@ if __FILE__ == $PROGRAM_NAME
|
||||
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
|
||||
opts.on('--[no-]github-auth',
|
||||
'Make authenticated GitHub API requests if GITHUB_TOKEN ' \
|
||||
'environment variable is set.' \
|
||||
'(default: enabled)') do |v|
|
||||
cli_options[:github_auth] = v
|
||||
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.'
|
||||
opts.on('--work-dir DIR',
|
||||
'Specify a working directory where tarballs, sources, and ' \
|
||||
'builds will be stored and worked with') do |v|
|
||||
cli_options[:work_dir] = v
|
||||
end
|
||||
|
||||
opts.on(
|
||||
'--plan FILE',
|
||||
'Follow given plan file, instead of using given git ref/sha'
|
||||
) do |v|
|
||||
cli_options[:plan] = v
|
||||
end
|
||||
end.parse!
|
||||
|
||||
Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build
|
||||
work_dir = cli_options.delete(:work_dir)
|
||||
Build.new(work_dir, ARGV.shift, cli_options).build
|
||||
rescue Error => e
|
||||
warn "ERROR: #{e.message}"
|
||||
exit 1
|
||||
|
||||
23
helper/emacs-cli.bash
Executable file
23
helper/emacs-cli.bash
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
resolve_link() {
|
||||
"$(type -p greadlink readlink | head -1)" "$1"
|
||||
}
|
||||
|
||||
abs_dirname() {
|
||||
local path="$1"
|
||||
local name
|
||||
local cwd
|
||||
cwd="$(pwd)"
|
||||
|
||||
while [ -n "$path" ]; do
|
||||
cd "${path%/*}" || exit 1
|
||||
name="${path##*/}"
|
||||
path="$(resolve_link "$name" || true)"
|
||||
done
|
||||
|
||||
pwd
|
||||
cd "$cwd" || exit 1
|
||||
}
|
||||
|
||||
exec "$(dirname "$(abs_dirname "$0")")/Emacs" "$@"
|
||||
@@ -1,10 +1,10 @@
|
||||
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
|
||||
index 25e2de9..bcedd31 100644
|
||||
index 8c638312b0..87af889ef4 100644
|
||||
--- a/lisp/emacs-lisp/comp.el
|
||||
+++ b/lisp/emacs-lisp/comp.el
|
||||
@@ -2801,6 +2801,57 @@ queued with LOAD %"
|
||||
(comp-run-async-workers)
|
||||
(message "Compilation started."))))
|
||||
@@ -4215,6 +4215,52 @@ native-compile-async
|
||||
(let ((load (not (not load))))
|
||||
(native--compile-async files recursively load selector)))
|
||||
|
||||
+;;;###autoload
|
||||
+(defun native-compile-setup-environment-variables (&rest _args)
|
||||
@@ -15,27 +15,22 @@ index 25e2de9..bcedd31 100644
|
||||
+ (let* ((library-path-env (getenv "LIBRARY_PATH"))
|
||||
+ (devtools-dir
|
||||
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
|
||||
+ (gcc-base-dir (concat invocation-directory "lib/gcc"))
|
||||
+ (gcc-version (car (seq-filter
|
||||
+ (lambda (dir) (string-match-p "^[0-9]+$" dir))
|
||||
+ (directory-files gcc-base-dir))))
|
||||
+ (gcc-dir (concat gcc-base-dir "/" gcc-version))
|
||||
+ (darwin-base-dir (car (file-expand-wildcards
|
||||
+ (concat gcc-dir "/gcc/*apple-darwin*"))))
|
||||
+ (darwin-version (car (seq-filter
|
||||
+ (lambda (dir)
|
||||
+ (string-match-p
|
||||
+ "^[0-9]+\\(\.[0-9]+\\(\.[0-9]+\\)?\\)?$" dir))
|
||||
+ (directory-files darwin-base-dir))))
|
||||
+ (darwin-dir (concat darwin-base-dir "/" darwin-version))
|
||||
+ (lib-paths (append
|
||||
+ (list gcc-dir darwin-dir)
|
||||
+ (if (file-directory-p devtools-dir)
|
||||
+ (list devtools-dir) (list))
|
||||
+ (if library-path-env (list library-path-env) (list)))))
|
||||
+ (gcc-dir (expand-file-name
|
||||
+ "<%= relative_lib_dir %>"
|
||||
+ invocation-directory))
|
||||
+ (darwin-dir (expand-file-name
|
||||
+ "<%= sanitized_relative_darwin_lib_dir %>"
|
||||
+ invocation-directory))
|
||||
+ (lib-paths (list)))
|
||||
+
|
||||
+ (when (and gcc-dir darwin-dir)
|
||||
+ (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":")))))
|
||||
+ (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
|
||||
@@ -59,4 +54,4 @@ index 25e2de9..bcedd31 100644
|
||||
+
|
||||
(provide 'comp)
|
||||
|
||||
;;; comp.el ends here
|
||||
;; LocalWords: limplified limplified limplification limplify Limple LIMPLE libgccjit elc eln
|
||||
Reference in New Issue
Block a user