Compare commits

..

2 Commits

16 changed files with 498 additions and 307 deletions

View File

@@ -2,64 +2,6 @@
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.17](https://github.com/jimeh/build-emacs-for-macos/compare/0.4.16...0.4.17) (2021-06-20)
### Bug Fixes
* **download:** don't use GitHub API to get tarball URL ([707bc9e](https://github.com/jimeh/build-emacs-for-macos/commit/707bc9e0d13246b7cfb8d27da859a101d4a3c166))
### [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)

View File

@@ -72,16 +72,14 @@ 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 if supported (default: enabled)
--[no-]xwidgets Enable/disable XWidgets (default: enabled if supported)
--[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-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
--rsvg Enable SVG image support via librsvg, can yield a unstable build (default: disabled)
--no-titlebar Apply no-titlebar patch (default: disabled)
--no-frame-refocus Apply no-frame-refocus patch (default: disabled)
--[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
--[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
@@ -113,25 +111,29 @@ All sources as downloaded as tarballs from the
to get a list of tags/branches available to install, simply check said
repository.
## Use Emacs.app as `emacs` CLI Tool
## Use Self-Contained Emacs.app as `emacs` CLI Tool
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.
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.
To use it, simply add `Emacs.app/Contents/MacOS/bin` to your `PATH`. For
example, if you place Emacs.app in `/Applications`:
Personally I use something similar to this:
```bash
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.
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
```
If you want `emacs` in your terminal to launch a GUI instance of Emacs, don't
use the alias from the above example.
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
@@ -140,9 +142,9 @@ _Note: On 2021-04-25 the `feature/native-comp` branch was
into `master`._
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.
supports native-compilation, and enable it if available. You can override this
to force it on/off 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 elisp source files as possible to build Emacs itself. Any
@@ -150,39 +152,32 @@ 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`
option, which will native-compile all of Emacs' elisp at built-time. On my
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.
### Configuration
#### Native-Lisp Cache Directory
Add the following near the top of your `early-init.el` or `init.el`:
```elisp
(setq comp-speed 2)
```
By default natively compiled `*.eln` files will be cached in
`~/.emacs.d/eln-cache/`. If you want to customize that, simply set a new path as
the first element of the `native-comp-eln-load-path` variable. The path string
must end with a `/`.
the first element of the `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 'native-comp-eln-load-path)
(setcar native-comp-eln-load-path
(when (boundp 'comp-eln-load-path)
(setcar 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 +188,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 for native-comp](https://github.com/jimeh/build-emacs-for-macos/issues/6)
[#6 Known good commits of feature/native-comp branch](https://github.com/jimeh/build-emacs-for-macos/issues/6)
## Credits

52
bin/commit-info Executable file
View 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
View 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

View File

@@ -10,9 +10,7 @@ require 'json'
require 'net/http'
require 'optparse'
require 'pathname'
require 'time'
require 'uri'
require 'yaml'
class Error < StandardError; end
@@ -23,9 +21,9 @@ module Output
def out(msg, newline: true)
if newline
warn "==> #{msg}"
puts "==> #{msg}"
else
STDERR.print "==> #{msg}"
print "==> #{msg}"
end
end
@@ -71,8 +69,9 @@ end
class Build
include Output
EMACS_MIRROR_REPO = 'emacs-mirror/emacs'
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
attr_reader :root_dir
attr_reader :source_dir
@@ -88,10 +87,8 @@ class Build
end
def build
load_plan(options[:plan]) if options[:plan]
unless meta[:sha] && meta[:date]
err 'Failed to get commit info from GitHub.'
err 'Failed to get commit info from GitHub API.'
end
tarball = download_tarball(meta[:sha])
@@ -102,7 +99,6 @@ 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_info).embed if options[:native_comp]
@@ -112,17 +108,6 @@ class Build
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
@@ -161,20 +146,8 @@ class Build
info 'Downloading tarball from GitHub. This could take a while, ' \
'please be patient.'
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}")
result = run_cmd('curl', '-L', url, '-o', target)
err 'Download failed.' unless result
target
end
@@ -267,7 +240,7 @@ class Build
"-I#{File.join(gcc_info.root_dir, 'include')}",
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
'-O2',
(options[:native_march] ? '-march=native' : nil),
'-march=native',
ENV['CFLAGS']
].compact.join(' ')
@@ -326,7 +299,7 @@ class Build
configure_flags << '--with-xwidgets'
end
configure_flags << native_comp_configure_flag if options[:native_comp]
configure_flags << '--without-rsvg' if options[:rsvg] == false
configure_flags << '--without-rsvg' unless options[:rsvg]
run_cmd './configure', *configure_flags
@@ -385,51 +358,29 @@ class Build
end
end
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
def archive_app(app)
FileUtils.mkdir_p(builds_dir)
metadata = [
meta[:ref]&.gsub(/\W/, '-'),
meta[:date]&.strftime('%Y-%m-%d'),
meta[:date],
meta[:sha][0..6],
"macOS-#{OS.version}",
OS.arch
].compact
filename = "Emacs.app-[#{metadata.join('][')}].tbz"
@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)
target = "#{builds_dir}/#{filename}"
app_base = File.basename(app)
app_dir = File.dirname(app)
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
if !File.exist?(target)
info "Creating #{filename} archive in \"#{builds_dir}\"..."
FileUtils.cd(app_dir) { system('tar', '-cjf', target, app_base) }
else
info "#{filename} archive exists in " \
"#{relative_target_dir}, skipping archving."
"#{builds_dir.gsub(root_dir + '/', '')}, skipping archving."
end
end
@@ -453,33 +404,22 @@ class Build
ref_sha = options[:git_sha] || ref
info "Fetching info for git ref: #{ref_sha}"
commit_json = github_api_get(
"/repos/#{EMACS_MIRROR_REPO}/commits/#{ref_sha}"
)
url = format(LATEST_URL, ref_sha)
commit_json = http_get(url)
err "Failed to get commit info about: #{ref_sha}" if commit_json.nil?
commit = JSON.parse(commit_json)
meta = {
sha: commit['sha'],
date: Time.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
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)
def http_get(url)
response = Net::HTTP.get_response(URI.parse(url))
return unless response.code == '200'
response.body
@@ -620,7 +560,7 @@ class AbstractEmbedder
private
def invocation_dir
File.join(app, 'Contents', 'MacOS')
File.join(app, 'Contents/MacOS')
end
def bin
@@ -652,51 +592,18 @@ class LibEmbedder < AbstractEmbedder
FileUtils.cd(File.dirname(app)) do
copy_libs(binary)
copy_extra_libs(extra_libs, binary) if extra_libs.any?
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
self_ref_libs(binary)
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)
@@ -741,6 +648,31 @@ class LibEmbedder < AbstractEmbedder
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],
File.join('@executable_path', rel_path, match[2].to_s),
bin_path
)
end
end
end
end
def while_writable(file)
mode = File.stat(file).mode
File.chmod(0o775, file)
@@ -772,9 +704,7 @@ class GccLibEmbedder < AbstractEmbedder
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)
FileUtils.rm(Dir[File.join(target_dir, '**/.DS_Store')], force: true)
end
private
@@ -787,21 +717,9 @@ class GccLibEmbedder < AbstractEmbedder
File.join(invocation_dir, gcc_info.relative_lib_dir)
end
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
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
@@ -841,17 +759,6 @@ class GccInfo
@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
@@ -896,19 +803,19 @@ class GccInfo
private
def relative_dir(path, root)
Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
root += '/' unless root[-1] == '/'
return if path[0..root.size - 1] != root
path[root.size..-1]
end
end
if __FILE__ == $PROGRAM_NAME
cli_options = {
work_dir: File.expand_path(__dir__),
native_full_aot: false,
native_march: false,
parallel: Etc.nprocessors,
rsvg: true,
xwidgets: true,
github_auth: true
rsvg: false,
xwidgets: true
}
begin
@@ -928,15 +835,14 @@ 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 if supported ' \
'(default: enabled)') do |v|
'Enable/disable XWidgets ' \
'(default: enabled if supported)') do |v|
cli_options[:xwidgets] = v
end
@@ -946,22 +852,15 @@ 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-]rsvg',
'Enable/disable SVG image support via librsvg ' \
'(default: enabled)') do |v|
cli_options[:rsvg] = v
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
@@ -973,29 +872,25 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:no_frame_refocus] = true
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
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('--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
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!
work_dir = cli_options.delete(:work_dir)
Build.new(work_dir, ARGV.shift, cli_options).build
Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build
rescue Error => e
warn "ERROR: #{e.message}"
exit 1

View File

@@ -1,23 +0,0 @@
#!/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" "$@"

9
lib/base_action.rb Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@@ -1,10 +1,10 @@
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 8c638312b0..87af889ef4 100644
index 4036080976..2ff8dbd74c 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4215,6 +4215,52 @@ native-compile-async
@@ -4079,6 +4079,52 @@ of (commands) to run simultaneously."
(let ((load (not (not load))))
(native--compile-async files recursively load selector)))
(native--compile-async paths recursively load selector)))
+;;;###autoload
+(defun native-compile-setup-environment-variables (&rest _args)
@@ -19,7 +19,7 @@ index 8c638312b0..87af889ef4 100644
+ "<%= relative_lib_dir %>"
+ invocation-directory))
+ (darwin-dir (expand-file-name
+ "<%= sanitized_relative_darwin_lib_dir %>"
+ "<%= relative_darwin_lib_dir %>"
+ invocation-directory))
+ (lib-paths (list)))
+
@@ -54,4 +54,4 @@ index 8c638312b0..87af889ef4 100644
+
(provide 'comp)
;; LocalWords: limplified limplified limplification limplify Limple LIMPLE libgccjit elc eln
;;; comp.el ends here