From 5ffffb7c778c9a1bdca5ced1c13fabde953a1c9c Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Thu, 3 Sep 2020 01:52:51 +0100 Subject: [PATCH 1/6] refactor(internals): extract and DRY up a number of things --- build-emacs-for-macos | 187 +++++++++++++++++++++++++----------------- 1 file changed, 112 insertions(+), 75 deletions(-) diff --git a/build-emacs-for-macos b/build-emacs-for-macos index b6ce6d9..805e274 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -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( + /(?\d+)\.(?\d+)\.(?\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| From 8e459ce00d8e5e3032ced260d8fbbc9b1dbc2c7a Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Fri, 4 Sep 2020 01:34:48 +0100 Subject: [PATCH 2/6] fix(requirements): make script compatible with Ruby 2.3.0 and later --- README.md | 6 ++++++ build-emacs-for-macos | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8c19e1..6c079f1 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,12 @@ The build produced does have some limitations: ``` brew bundle ``` +- Ruby 2.3.0 or later is needed to execute the build script itself. macOS comes + with Ruby, check your version with `ruby --version`. If it's too old, you can + install a newer version with: + ``` + brew install ruby + ``` ## Usage diff --git a/build-emacs-for-macos b/build-emacs-for-macos index 805e274..01f29f1 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -172,11 +172,11 @@ class Build end def supports_native_comp? - @supports_native_comp ||= configure_help.match?(/\s+--with-nativecomp\s+/) + @supports_native_comp ||= !!configure_help.match(/\s+--with-nativecomp\s+/) end def supports_xwidgets? - @supports_xwidgets ||= configure_help.match?(/\s+--with-xwidgets\s+/) + @supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/) end def detect_native_comp From 83289acd33b54a0d332fe92e2ad4ef7c1c633b72 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Thu, 3 Sep 2020 01:56:05 +0100 Subject: [PATCH 3/6] feat(native_comp): embedd gcc/libgccjit into Emacs.app The solution to get libgccjit properly working, and embedded in Emacs.app included: - The contents of GCC's lib folder (`/usr/local/opt/gcc/lib`) is copied into the `Contents/MacOS/lib--` folder. - Setting `LIBRARY_PATH` environment variable to correct GCC lib folders within Emacs.app. This is done through a bash launcher script which replaces the regular `Contents/MacOS/Emacs` executable. The main Emacs executable itself is named `Emacs-bin` now instead, so anything that depends on the exact process name will need updating. - The launcher script also adds `Content/MacOS/bin` and `Content/MacOS/libexec` folders to the PATH environment variable, to so ensure binary tools packaged into Emacs itself are available. This is done even when not doing a native-comp build. The launcher script skips setting LIBRARY_PATH if it's not a native-comp build. This should hopefully resolve both #5 and #7. --- .rubocop.yml | 3 + README.md | 1 + build-emacs-for-macos | 208 +++++++++++++++++++++++++++++++++++------- launcher.bash.erb | 65 +++++++++++++ 4 files changed, 245 insertions(+), 32 deletions(-) create mode 100755 launcher.bash.erb diff --git a/.rubocop.yml b/.rubocop.yml index e6f922d..e228843 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,2 +1,5 @@ +Style/Documentation: + Enabled: false + Style/LineLength: Max: 80 diff --git a/README.md b/README.md index 6c079f1..1d4215e 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Options: --[no-]native-fast-boot Enable/disable NATIVE_FAST_BOOT (default: enabled if native-comp supported) --[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) ``` Resulting applications are saved to the `builds` directory in a bzip2 compressed diff --git a/build-emacs-for-macos b/build-emacs-for-macos index 01f29f1..3e93ad8 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -3,6 +3,7 @@ require 'English' require 'date' +require 'erb' require 'etc' require 'fileutils' require 'json' @@ -74,6 +75,7 @@ class Build LAUNCHER_TEMPLATE = './launcher.bash.erb' attr_reader :root_dir + attr_reader :source_dir attr_reader :ref attr_reader :options @@ -89,26 +91,36 @@ class Build end tarball = download_tarball(meta[:sha]) - source = extract_tarball(tarball, patches(options)) - app = compile_source(source) + @source_dir = extract_tarball(tarball, patches(options)) + + autogen + detect_native_comp if options[:native_comp].nil? + + if options[:native_comp] && options[:launcher].nil? + options[:launcher] = true + end + + app = compile_source(@source_dir) LibEmbedder.new(app, brew_dir, extra_libs).embed + LibGccJitEmbedder.new(app, gcc_dir).embed if options[:native_comp] + LauncherEmbedder.new(app, LAUNCHER_TEMPLATE).embed if options[:launcher] archive_app(app) end private - def tarball_dir - @tarball_dir ||= File.join(root_dir, 'tarballs') + def tarballs_dir + @tarballs_dir ||= File.join(root_dir, 'tarballs') end - def source_dir - @source_dir ||= File.join(root_dir, 'sources') + def sources_dir + @sources_dir ||= File.join(root_dir, 'sources') end - def build_dir - @build_dir ||= File.join(root_dir, 'builds') + def builds_dir + @builds_dir ||= File.join(root_dir, 'builds') end def brew_dir @@ -128,11 +140,11 @@ class Build end def download_tarball(sha) - FileUtils.mkdir_p(tarball_dir) + FileUtils.mkdir_p(tarballs_dir) url = (DOWNLOAD_URL % sha) filename = "emacs-mirror-emacs-#{sha[0..6]}.tgz" - target = File.join(tarball_dir, filename) + target = File.join(tarballs_dir, filename) if File.exist?(target) info "#{filename} already exists locally, attempting to use." @@ -148,10 +160,10 @@ class Build end def extract_tarball(filename, patches = []) - FileUtils.mkdir_p(source_dir) + FileUtils.mkdir_p(sources_dir) dirname = File.basename(filename).gsub(/\.\w+$/, '') - target = File.join(source_dir, dirname) + target = File.join(sources_dir, dirname) if File.exist?(target) info "#{dirname} source tree exists, attempting to use." @@ -159,7 +171,7 @@ class Build end info 'Extracting tarball...' - result = run_cmd('tar', '-xzf', filename, '-C', source_dir) + result = run_cmd('tar', '-xzf', filename, '-C', sources_dir) err 'Tarball extraction failed.' unless result patches.each { |patch| apply_patch(patch, target) } @@ -168,7 +180,11 @@ class Build end def configure_help - @configure_help ||= `./configure --help` + return @configure_help if @configure_help + + FileUtils.cd(source_dir) { @configure_help = `./configure --help` } + + @configure_help end def supports_native_comp? @@ -200,6 +216,23 @@ class Build '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 + FileUtils.cd(source_dir) do + if File.exist?('autogen/copy_autogen') + run_cmd 'autogen/copy_autogen' + elsif File.exist?('autogen.sh') + run_cmd './autogen.sh' + end + end + end + def compile_source(source) target = "#{source}/nextstep" emacs_app = "#{target}/Emacs.app" @@ -213,13 +246,6 @@ class Build info 'Compiling from source. This will take a while...' FileUtils.cd(source) do - if File.exist?('autogen/copy_autogen') - run_cmd 'autogen/copy_autogen' - elsif File.exist?('autogen.sh') - run_cmd './autogen.sh' - end - - detect_native_comp if options[:native_comp].nil? if options[:native_comp] info 'Compiling with native-comp enabled' verify_native_comp @@ -237,14 +263,14 @@ class Build ].compact.join(' ') ENV['LDFLAGS'] = [ - "-L#{gcc_dir}/lib/gcc/10", + gcc_library_paths.map { |path| "-L#{path}" }, "-I#{gcc_dir}/include" - ].compact.join(' ') + ].flatten.compact.join(' ') ENV['LIBRARY_PATH'] = [ - "#{gcc_dir}/lib/gcc/10", + gcc_library_paths, ENV['LIBRARY_PATH'] - ].compact.join(':') + ].flatten.compact.join(':') end ENV['CC'] = 'clang' @@ -313,7 +339,7 @@ class Build end def archive_app(app) - FileUtils.mkdir_p(build_dir) + FileUtils.mkdir_p(builds_dir) metadata = [ ref.gsub(/\W/, '-'), @@ -324,17 +350,17 @@ class Build ] filename = "Emacs.app-[#{metadata.join('][')}].tbz" - target = "#{build_dir}/#{filename}" + target = "#{builds_dir}/#{filename}" app_base = File.basename(app) app_dir = File.dirname(app) if !File.exist?(target) - info "Creating #{filename} archive in \"#{build_dir}\"..." + info "Creating #{filename} archive in \"#{builds_dir}\"..." FileUtils.cd(app_dir) { system('tar', '-cjf', target, app_base) } else info "#{filename} archive exists in " \ - "#{build_dir.gsub(root_dir + '/', '')}, skipping archving." + "#{builds_dir.gsub(root_dir + '/', '')}, skipping archving." end end @@ -525,10 +551,13 @@ class LibEmbedder < AbstractEmbedder def embed info 'Embedding libraries into Emacs.app' + binary = "#{bin}-bin" if File.exist?("#{bin}-bin") + binary ||= bin + FileUtils.cd(File.dirname(app)) do - copy_libs(bin) - copy_extra_libs(extra_libs, bin) if extra_libs.any? - self_ref_libs(bin) + copy_libs(binary) + copy_extra_libs(extra_libs, binary) if extra_libs.any? + self_ref_libs(binary) end end @@ -617,6 +646,115 @@ class LibEmbedder < AbstractEmbedder end end +class LibGccJitEmbedder < AbstractEmbedder + attr_reader :gcc_dir + + def initialize(app, gcc_dir) + super(app) + @gcc_dir = gcc_dir + end + + def embed + if embedded? + info 'libgccjit already embedded in Emacs.app' + return + end + + info 'Embedding libgccjit into Emacs.app' + if gcc_version.empty? + err "No suitable GCC lib with libgccjit found in #{gcc_dir}" + end + + FileUtils.mkdir_p(File.dirname(target_dir)) + FileUtils.cp_r(source_dir, target_dir) + end + + private + + def embedded? + Dir[File.join(target_dir, 'libgccjit.so*')].any? + end + + def target_dir + File.join(lib_dir, 'gcc', gcc_version) + 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 + + def source_dir + @source_dir ||= File.join(gcc_dir, 'lib', 'gcc', gcc_version) + end +end + +class LauncherEmbedder < AbstractEmbedder + attr_reader :template + + def initialize(app, template) + super(app) + + @template = template + end + + def embed + if embedded? + info 'Launcher script already embedded in Emacs.app' + return + end + + info 'Embedding launcher script into Emacs.app' + + unless File.exist?("#{bin}#{bin_suffix}") + FileUtils.mv(bin, "#{bin}#{bin_suffix}") + end + + unless File.exist?("#{bin}#{bin_suffix}#{dump_ext}") + FileUtils.mv("#{bin}#{dump_ext}", "#{bin}#{bin_suffix}#{dump_ext}") + end + + unless File.exist?(bin) + File.write(bin, launcher) + File.chmod(0o775, bin) + end + end + + private + + def bin_suffix + '-bin' + end + + def dump_ext + '.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 + if __FILE__ == $PROGRAM_NAME cli_options = { native_fast_boot: true, @@ -669,6 +807,12 @@ if __FILE__ == $PROGRAM_NAME '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 end.parse! begin diff --git a/launcher.bash.erb b/launcher.bash.erb new file mode 100755 index 0000000..28b12cf --- /dev/null +++ b/launcher.bash.erb @@ -0,0 +1,65 @@ +#!/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" "$@" From 583f22a360a08bf236ea0e0562e6fd1ddda3b933 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Fri, 4 Sep 2020 01:48:50 +0100 Subject: [PATCH 4/6] feat(patches): add support for optional no-titlebar and no-refocus-frame patches --- README.md | 2 ++ build-emacs-for-macos | 63 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1d4215e..d797219 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ Options: --[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) + --no-titlebar Apply no-titlebar patch (default: disabled) + --no-frame-refocus Apply no-frame-refocus patch (default: disabled) ``` Resulting applications are saved to the `builds` directory in a bzip2 compressed diff --git a/build-emacs-for-macos b/build-emacs-for-macos index 3e93ad8..da549ba 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -301,7 +301,9 @@ class Build '/Library/Application Support/Emacs/${version}/site-lisp:' \ '/Library/Application Support/Emacs/site-lisp' ] - configure_flags << '--with-xwidgets' if supports_xwidgets? + if options[:xwidgets] && supports_xwidgets? + configure_flags << '--with-xwidgets' + end configure_flags << '--with-nativecomp' if options[:native_comp] run_cmd './configure', *configure_flags @@ -441,9 +443,11 @@ class Build def effective_version @effective_version ||= begin case ref + when /^emacs-26.*/ + 'emacs-26' when /^emacs-27.*/ 'emacs-27' - when /^emacs-28.*/, NATIVE_COMP_REF_REGEXP, 'master' + else 'emacs-28' end end @@ -452,22 +456,46 @@ class Build def patches(opts = {}) p = [] - if effective_version - if opts[:xwidgets] && effective_version == 'emacs-27' + if %w[emacs-26 emacs-27 emacs-28].include?(effective_version) + p << { + url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ + "patches/#{effective_version}/fix-window-role.patch" + } + end + + if %w[emacs-27 emacs-28].include?(effective_version) + p << { + url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ + "patches/#{effective_version}/system-appearance.patch" + } + + if options[:no_titlebar] + p << { + url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ + "patches/#{effective_version}/no-titlebar.patch" + } + end + + if options[:no_frame_refocus] + p << { + url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ + "patches/#{effective_version}/no-frame-refocus-cocoa.patch" + } + end + end + + if effective_version == 'emacs-27' + p << { + url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ + "patches/#{effective_version}/ligatures-freeze-fix.patch" + } + + if opts[:xwidgets] p << { url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ "patches/#{effective_version}/xwidgets_webkit_in_cocoa.patch" } end - - p << { - url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ - "patches/#{effective_version}/fix-window-role.patch" - } - p << { - url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ - "patches/#{effective_version}/system-appearance.patch" - } end p @@ -813,6 +841,15 @@ if __FILE__ == $PROGRAM_NAME '(default: enabled if native-comp is enabled)') do |v| cli_options[:launcher] = v 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 From 9d264357df61cf57a153947d2c22e28c27cba2d5 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Fri, 4 Sep 2020 22:52:51 +0100 Subject: [PATCH 5/6] feat(native_comp): support renaming of eln-cache director to native-lisp --- build-emacs-for-macos | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/build-emacs-for-macos b/build-emacs-for-macos index da549ba..074faec 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -101,6 +101,7 @@ class Build end app = compile_source(@source_dir) + symlink_internals(app) LibEmbedder.new(app, brew_dir, extra_libs).embed LibGccJitEmbedder.new(app, gcc_dir).embed if options[:native_comp] @@ -329,17 +330,24 @@ class Build err 'Build failed.' unless File.exist?(emacs_app) - if options[:native_comp] - FileUtils.cd(File.join(emacs_app, 'Contents')) do - FileUtils.ln_s('Resources/lisp', 'lisp') - dir = Dir['MacOS/libexec/emacs/**/eln-cache'].first - FileUtils.ln_s(dir, 'eln-cache') - end - end - emacs_app end + 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 + FileUtils.ln_s('Resources/lisp', 'lisp') unless File.exist?('lisp') + + source = Dir['MacOS/libexec/emacs/**/eln-cache', + 'MacOS/lib/emacs/**/native-lisp'].first + target = File.basename(source) + FileUtils.ln_s(source, target) unless File.exist?(target) + end + end + def archive_app(app) FileUtils.mkdir_p(builds_dir) From d30b45fb2e507af98c3a958d159be3402a7a7bd1 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sat, 5 Sep 2020 04:32:41 +0100 Subject: [PATCH 6/6] fix(svg): disable rsvg by default When SVG support is enabled via librsvg, launching builds of Emacs 27.1 or later from the Finder into GUI mode will crash Emacs if the fancy startup screen is used. This crash has been observed with librsvg 2.46.4, 2.48.7 and 2.48.8. Hence SVG image support is now disabled by default. Should you need it, you will need to disable the startup screen to avoid Emacs crashing, by putting this in your init.el: (setq inhibit-startup-screen t) The cause of the issue seems to be the `image-size` function as called from `use-fancy-splash-screens-p`. --- README.md | 1 + build-emacs-for-macos | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d797219..92d68cd 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Options: --[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) --no-titlebar Apply no-titlebar patch (default: disabled) --no-frame-refocus Apply no-frame-refocus patch (default: disabled) ``` diff --git a/build-emacs-for-macos b/build-emacs-for-macos index 074faec..a7e69f1 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -306,6 +306,7 @@ class Build configure_flags << '--with-xwidgets' end configure_flags << '--with-nativecomp' if options[:native_comp] + configure_flags << '--without-rsvg' unless options[:rsvg] run_cmd './configure', *configure_flags @@ -793,10 +794,11 @@ end if __FILE__ == $PROGRAM_NAME cli_options = { + macos_fixes: true, native_fast_boot: true, parallel: Etc.nprocessors, - xwidgets: true, - macos_fixes: true + rsvg: false, + xwidgets: true } OptionParser.new do |opts| @@ -850,6 +852,11 @@ if __FILE__ == $PROGRAM_NAME 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