From 111cb6499368d14853a5927d38a43fc5e2f759f4 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 20 Sep 2020 20:49:10 +0100 Subject: [PATCH] feat(native_comp)!: use elisp patch instead of launcher script to set LIBRARY_PATH Replace the launcher script with a emacs-lisp patch to `comp.el` which sets the `LIBRARY_PATH` environment variable to point at the embedded GCC/libgccjit. This fixes issues related to the launcher script on macOS 10.15 and later. Fixes #14 BREAKING CHANGE: `--[no-]launcher` option is deprecated, as launcher script is no longer used. --- build-emacs-for-macos | 100 +++++++--------------------- launcher.bash.erb | 65 ------------------ patches/native-comp-env-setup.patch | 41 ++++++++++++ 3 files changed, 65 insertions(+), 141 deletions(-) delete mode 100755 launcher.bash.erb create mode 100644 patches/native-comp-env-setup.patch diff --git a/build-emacs-for-macos b/build-emacs-for-macos index 951ed1f..7f34a2d 100755 --- a/build-emacs-for-macos +++ b/build-emacs-for-macos @@ -72,7 +72,6 @@ class Build 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 :source_dir @@ -96,16 +95,11 @@ class Build 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) symlink_internals(app) 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 @@ -256,6 +250,8 @@ class Build apply_native_comp_macos_fixes end + apply_native_comp_env_setup_patch(source) + ENV['CFLAGS'] = [ "-I#{gcc_dir}/include", '-O2', @@ -426,6 +422,17 @@ class Build system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}") end + def apply_native_comp_env_setup_patch(source) + term = 'native-compile-setup-environment-variables' + 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 + ) + end + def apply_native_comp_macos_fixes filename = 'Makefile.in' pattern = /^src: Makefile\n(.*BIN_DESTDIR.*)\nblessmail: Makefile src\n/m @@ -521,7 +528,10 @@ class Build def apply_patch(patch, target) err "\"#{target}\" does not exist." unless File.exist?(target) - if patch[:url] + if patch[:file] + info 'Applying patch...' + FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch[:file]) } + elsif patch[:url] patch_dir = "#{target}/macos_patches" run_cmd('mkdir', '-p', patch_dir) @@ -535,8 +545,7 @@ class Build info "Downloading patch: #{patch[:url]}" run_cmd('curl', '-L#', patch[:url], '-o', patch_file) - info 'Applying patch...' - FileUtils.cd(target) { run_cmd('patch', '-f', '-p1', '-i', patch_file) } + apply_patch({ file: patch_file }, target) elsif patch[:replace] err 'Patch replace input error' unless patch[:replace].size == 3 @@ -739,67 +748,6 @@ class LibGccJitEmbedder < AbstractEmbedder 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 = { macos_fixes: true, @@ -855,12 +803,6 @@ if __FILE__ == $PROGRAM_NAME cli_options[:macos_fixes] = v end - opts.on('--[no-]launcher', - 'Enable/disable embedded launcher script ' \ - '(default: enabled if native-comp is enabled)') do |v| - cli_options[:launcher] = v - end - opts.on('--rsvg', 'Enable SVG image support via librsvg, ' \ 'can yield a unstable build (default: disabled)') do cli_options[:rsvg] = true @@ -885,6 +827,12 @@ if __FILE__ == $PROGRAM_NAME 'use --native-full-aot instead' end end + + opts.on('--[no-]launcher', + 'DEPRECATED: Launcher script is no longer used.') do |_| + raise Error, '--[no-]launcher option is deprecated, launcher ' \ + 'script is no longer used.' + end end.parse! Build.new(File.expand_path(__dir__), ARGV.shift, cli_options).build diff --git a/launcher.bash.erb b/launcher.bash.erb deleted file mode 100755 index 28b12cf..0000000 --- a/launcher.bash.erb +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# This launcher script is not part of Emacs proper. It is from the -# build-emacs-for-macos project (https://github.com/jimeh/build-emacs-for-macos) -# and helps facilitate proper startup of Emacs with environment varibales set as -# needed. -# -# Licensed under CC0 1.0 Universal: -# https://creativecommons.org/publicdomain/zero/1.0/ -# -set -e - -resolve_link() { - local file="$1" - - while [ -L "$file" ]; do - file="$(readlink "$file")" - done - - echo "$file" -} - -realname() { - local path="$1" - local resolved - local cwd - - cwd="$(pwd)" - resolved="$(resolve_link "$path")" - cd "$(dirname "$resolved")" - echo "$(pwd)/$(basename "$resolved")" - cd "$cwd" -} - -join() { - local IFS="$1" - local parts=() - shift - - for arg in "$@"; do - if [ "$arg" != "" ]; then - parts+=("$arg") - fi - done - - echo "${parts[*]}" -} - -DIR="$(dirname "$(realname "$0")")" -BIN="${DIR}/Emacs<%= bin_suffix %>" - -export PATH="${DIR}/bin:${DIR}/libexec:${PATH}" -<% if library_paths.any? %> -LIB_PATHS=( - '<%= library_paths.map { |p| p.gsub('\'', "\"'\"") }.join("'\n '") %>' -) -for lib in "${LIB_PATHS[@]}"; do - if [ -d "${DIR}/<%= lib_dir_name %>/${lib}" ]; then - libs="$(join : "$libs" "${DIR}/<%= lib_dir_name %>/${lib}")" - fi -done - -LIBRARY_PATH="$(join : "$libs" "$LIBRARY_PATH")" -export LIBRARY_PATH -<% end %> -exec "$BIN" "$@" diff --git a/patches/native-comp-env-setup.patch b/patches/native-comp-env-setup.patch new file mode 100644 index 0000000..7b3ecb5 --- /dev/null +++ b/patches/native-comp-env-setup.patch @@ -0,0 +1,41 @@ +diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el +index 25e2de9..14ee6dc 100644 +--- a/lisp/emacs-lisp/comp.el ++++ b/lisp/emacs-lisp/comp.el +@@ -2801,6 +2801,36 @@ queued with LOAD %" + (comp-run-async-workers) + (message "Compilation started.")))) + ++;;;###autoload ++(defun native-compile-setup-environment-variables (&rest _args) ++ "Ensure LIBRARY_PATH is set correctly when libgccjit is bundled." ++ (when (and (eq system-type 'darwin) ++ (string-match-p "\.app\/Contents\/MacOS\/?$" ++ invocation-directory)) ++ (let* ((library-path-env (getenv "LIBRARY_PATH")) ++ (gcc-dir (car (file-expand-wildcards ++ (concat invocation-directory "lib-*/gcc/*")))) ++ (gcc-darwin-dir (car (file-expand-wildcards ++ (concat gcc-dir "/gcc/*apple-darwin*/*")))) ++ (lib-paths (append ++ (list gcc-dir gcc-darwin-dir) ++ (if library-path-env (list library-path-env) (list))))) ++ ++ (when (and gcc-dir gcc-darwin-dir) ++ (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":"))))) ++ ++ ;; Remove advice, as it only needs to run once. ++ (advice-remove 'native-compile ++ 'native-compile-setup-environment-variables) ++ (advice-remove 'native-compile-async ++ 'native-compile-setup-environment-variables)) ++ ++;; Ensure environment setup runs before any native compilation. ++(advice-add 'native-compile :before ++ 'native-compile-setup-environment-variables) ++(advice-add 'native-compile-async :before ++ 'native-compile-setup-environment-variables) ++ + (provide 'comp) + + ;;; comp.el ends here