mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 08:26:39 +00:00
refactor(internals): extract and DRY up a number of things
This commit is contained in:
@@ -13,14 +13,65 @@ require 'uri'
|
||||
|
||||
class Error < StandardError; end
|
||||
|
||||
def err(msg = nil)
|
||||
raise Error, msg
|
||||
module Output
|
||||
def info(msg, newline: true)
|
||||
out "INFO: #{msg}", newline: newline
|
||||
end
|
||||
|
||||
def out(msg, newline: true)
|
||||
if newline
|
||||
puts "==> #{msg}"
|
||||
else
|
||||
print "==> #{msg}"
|
||||
end
|
||||
end
|
||||
|
||||
def err(msg = nil)
|
||||
raise Error, msg
|
||||
end
|
||||
end
|
||||
|
||||
class OS
|
||||
def self.version
|
||||
@version ||= OSVersion.new
|
||||
end
|
||||
|
||||
def self.arch
|
||||
@arch ||= `uname -m`.strip
|
||||
end
|
||||
end
|
||||
|
||||
class OSVersion
|
||||
def initialize
|
||||
@version = `sw_vers -productVersion`.match(
|
||||
/(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)/
|
||||
)
|
||||
end
|
||||
|
||||
def to_s
|
||||
@to_s ||= "#{major}.#{minor}"
|
||||
end
|
||||
|
||||
def major
|
||||
@major ||= @version[:major].to_i
|
||||
end
|
||||
|
||||
def minor
|
||||
@minor ||= @version[:minor].to_i
|
||||
end
|
||||
|
||||
def patch
|
||||
@patch ||= @version[:patch].to_i
|
||||
end
|
||||
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
|
||||
LAUNCHER_TEMPLATE = './launcher.bash.erb'
|
||||
|
||||
attr_reader :root_dir
|
||||
attr_reader :ref
|
||||
@@ -41,7 +92,7 @@ class Build
|
||||
source = extract_tarball(tarball, patches(options))
|
||||
app = compile_source(source)
|
||||
|
||||
LibEmbedder.new(app, brew_dir, os.version, extra_libs).embed
|
||||
LibEmbedder.new(app, brew_dir, extra_libs).embed
|
||||
|
||||
archive_app(app)
|
||||
end
|
||||
@@ -84,11 +135,11 @@ class Build
|
||||
target = File.join(tarball_dir, filename)
|
||||
|
||||
if File.exist?(target)
|
||||
puts "INFO: #{filename} already exists locally, attempting to use."
|
||||
info "#{filename} already exists locally, attempting to use."
|
||||
return target
|
||||
end
|
||||
|
||||
puts 'Downloading tarball from GitHub. This could take a while, ' \
|
||||
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
|
||||
@@ -103,11 +154,11 @@ class Build
|
||||
target = File.join(source_dir, dirname)
|
||||
|
||||
if File.exist?(target)
|
||||
puts "\nINFO: #{dirname} source tree exists, attempting to use."
|
||||
info "#{dirname} source tree exists, attempting to use."
|
||||
return target
|
||||
end
|
||||
|
||||
puts 'Extracting tarball...'
|
||||
info 'Extracting tarball...'
|
||||
result = run_cmd('tar', '-xzf', filename, '-C', source_dir)
|
||||
err 'Tarball extraction failed.' unless result
|
||||
|
||||
@@ -129,7 +180,7 @@ class Build
|
||||
end
|
||||
|
||||
def detect_native_comp
|
||||
print 'Detecting native-comp support: '
|
||||
info 'Detecting native-comp support: ', newline: false
|
||||
options[:native_comp] = supports_native_comp?
|
||||
puts options[:native_comp] ? 'Supported' : 'Not supported'
|
||||
end
|
||||
@@ -154,12 +205,12 @@ class Build
|
||||
emacs_app = "#{target}/Emacs.app"
|
||||
|
||||
if File.exist?("#{target}/Emacs.app")
|
||||
puts 'INFO: Emacs.app already exists in ' \
|
||||
info 'Emacs.app already exists in ' \
|
||||
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use."
|
||||
return emacs_app
|
||||
end
|
||||
|
||||
puts 'Compiling from source. This will take a while...'
|
||||
info 'Compiling from source. This will take a while...'
|
||||
|
||||
FileUtils.cd(source) do
|
||||
if File.exist?('autogen/copy_autogen')
|
||||
@@ -170,7 +221,7 @@ class Build
|
||||
|
||||
detect_native_comp if options[:native_comp].nil?
|
||||
if options[:native_comp]
|
||||
puts 'Compiling with native-comp enabled'
|
||||
info 'Compiling with native-comp enabled'
|
||||
verify_native_comp
|
||||
verify_libgccjit
|
||||
|
||||
@@ -204,7 +255,7 @@ class Build
|
||||
"#{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}",
|
||||
"#{brew_dir}/Homebrew/Library/Homebrew/os/mac/pkgconfig/#{OS.version}",
|
||||
ENV['PKG_CONFIG_PATH']
|
||||
].compact.join(':')
|
||||
|
||||
@@ -231,8 +282,9 @@ class Build
|
||||
|
||||
# Disable aligned_alloc on Mojave and below. See issue:
|
||||
# https://github.com/daviderestivo/homebrew-emacs-head/issues/15
|
||||
if os.major <= 10 && os.minor <= 14
|
||||
puts 'Force disabling of aligned_alloc on macOS <= Mojave (10.14.x)'
|
||||
if OS.version.major <= 10 && OS.version.minor <= 14
|
||||
info 'Force disabling of aligned_alloc on macOS Mojave (10.14.x) ' \
|
||||
'and earlier'
|
||||
disable_alligned_alloc
|
||||
end
|
||||
|
||||
@@ -267,8 +319,8 @@ class Build
|
||||
ref.gsub(/\W/, '-'),
|
||||
meta[:date],
|
||||
meta[:sha][0..6],
|
||||
"macOS-#{os.version}",
|
||||
arch
|
||||
"macOS-#{OS.version}",
|
||||
OS.arch
|
||||
]
|
||||
|
||||
filename = "Emacs.app-[#{metadata.join('][')}].tbz"
|
||||
@@ -278,34 +330,14 @@ class Build
|
||||
app_dir = File.dirname(app)
|
||||
|
||||
if !File.exist?(target)
|
||||
puts "\nCreating #{filename} archive in \"#{build_dir}\"..."
|
||||
info "Creating #{filename} archive in \"#{build_dir}\"..."
|
||||
FileUtils.cd(app_dir) { system('tar', '-cjf', target, app_base) }
|
||||
else
|
||||
puts "\nINFO: #{filename} archive exists in " \
|
||||
info "#{filename} archive exists in " \
|
||||
"#{build_dir.gsub(root_dir + '/', '')}, skipping archving."
|
||||
end
|
||||
end
|
||||
|
||||
def os
|
||||
@os ||= begin
|
||||
ver = `sw_vers -productVersion`.chomp
|
||||
.sub(/^(\d+\.\d+\.\d)+/, '\1')
|
||||
.split('.')
|
||||
.map(&:to_i)
|
||||
|
||||
OpenStruct.new(
|
||||
'version' => "#{ver[0]}.#{ver[1]}",
|
||||
'major' => ver[0],
|
||||
'minor' => ver[1],
|
||||
'patch' => ver[2]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def arch
|
||||
@arch = `uname -m`.strip
|
||||
end
|
||||
|
||||
def disable_alligned_alloc
|
||||
filename = 'src/config.h'
|
||||
content = File.read(filename)
|
||||
@@ -345,15 +377,14 @@ class Build
|
||||
end
|
||||
|
||||
def run_cmd(*args)
|
||||
puts '==> ' + args.join(' ')
|
||||
out "CMD: #{args.join(' ')}"
|
||||
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||
end
|
||||
|
||||
def apply_native_comp_macos_fixes
|
||||
filename = 'Makefile.in'
|
||||
content = File.read(filename).gsub(
|
||||
/^src: Makefile\n(.*BIN_DESTDIR.*)\nblessmail: Makefile src\n/m
|
||||
) do |match|
|
||||
pattern = /^src: Makefile\n(.*BIN_DESTDIR.*)\nblessmail: Makefile src\n/m
|
||||
content = File.read(filename).gsub(pattern) do
|
||||
old_src_body = Regexp.last_match(1).strip
|
||||
|
||||
# check if already patched
|
||||
@@ -416,7 +447,7 @@ class Build
|
||||
p
|
||||
end
|
||||
|
||||
def apply_patch(patch, target, abort_on_failure = true)
|
||||
def apply_patch(patch, target)
|
||||
err "\"#{target}\" does not exist." unless File.exist?(target)
|
||||
|
||||
if patch[:url]
|
||||
@@ -430,17 +461,11 @@ class Build
|
||||
end
|
||||
patch_file = patch_file.gsub('{num}', num.to_s.rjust(3, '0'))
|
||||
|
||||
begin
|
||||
puts "Downloading patch: #{patch[:url]}"
|
||||
run_cmd('curl', '-L#', patch[:url], '-o', patch_file)
|
||||
info "Downloading patch: #{patch[:url]}"
|
||||
run_cmd('curl', '-L#', patch[:url], '-o', patch_file)
|
||||
|
||||
puts 'Applying patch...'
|
||||
FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch_file) }
|
||||
rescue Error => e
|
||||
raise e if abort_on_failure
|
||||
|
||||
puts "WARN: Failed to apply patch: #{e.message}"
|
||||
end
|
||||
info 'Applying patch...'
|
||||
FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch_file) }
|
||||
elsif patch[:replace]
|
||||
err 'Patch replace input error' unless patch[:replace].size == 3
|
||||
|
||||
@@ -460,23 +485,45 @@ class Build
|
||||
end
|
||||
end
|
||||
|
||||
class LibEmbedder
|
||||
attr_reader :app
|
||||
attr_reader :lib_source
|
||||
attr_reader :macos_version
|
||||
attr_reader :extra_libs
|
||||
class AbstractEmbedder
|
||||
include Output
|
||||
|
||||
def initialize(app, lib_source, macos_version, extra_libs = [])
|
||||
attr_reader :app
|
||||
|
||||
def initialize(app)
|
||||
err "#{app} does not exist" unless File.exist?(app)
|
||||
|
||||
@app = app
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def bin
|
||||
"#{app}/Contents/MacOS/Emacs"
|
||||
end
|
||||
|
||||
def lib_dir
|
||||
"#{app}/Contents/MacOS/#{lib_dir_name}"
|
||||
end
|
||||
|
||||
def lib_dir_name
|
||||
"lib-#{OS.arch}-#{OS.version}"
|
||||
end
|
||||
end
|
||||
|
||||
class LibEmbedder < AbstractEmbedder
|
||||
attr_reader :lib_source
|
||||
attr_reader :extra_libs
|
||||
|
||||
def initialize(app, lib_source, extra_libs = [])
|
||||
super(app)
|
||||
|
||||
@lib_source = lib_source
|
||||
@macos_version = macos_version
|
||||
@extra_libs = extra_libs
|
||||
end
|
||||
|
||||
def embed
|
||||
puts 'Embedding libraries into Emacs.app'
|
||||
info 'Embedding libraries into Emacs.app'
|
||||
|
||||
FileUtils.cd(File.dirname(app)) do
|
||||
copy_libs(bin)
|
||||
@@ -487,18 +534,6 @@ class LibEmbedder
|
||||
|
||||
private
|
||||
|
||||
def arch
|
||||
@arch = `uname -m`.strip
|
||||
end
|
||||
|
||||
def bin
|
||||
"#{app}/Contents/MacOS/Emacs"
|
||||
end
|
||||
|
||||
def lib_dir
|
||||
"#{app}/Contents/MacOS/lib-#{arch}-#{macos_version}"
|
||||
end
|
||||
|
||||
def copy_libs(exe, rel_path = nil)
|
||||
exe_file = File.basename(exe)
|
||||
rel_path ||= Pathname.new(lib_dir).relative_path_from(
|
||||
@@ -550,8 +585,10 @@ class LibEmbedder
|
||||
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}/*")
|
||||
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|
|
||||
|
||||
Reference in New Issue
Block a user