Compare commits

..

10 Commits
0.4.3 ... 0.4.6

Author SHA1 Message Date
03ae8750b8 chore(release): 0.4.6 2021-02-15 11:43:58 +00:00
269dbdb1dd chore(build): use File.join wherever relevant
Ensures paths are correctly joined and no double and/or missing slash
errors can occur.
2021-02-15 11:42:49 +00:00
713c970da4 Merge pull request #30 from jimeh/improve-native-comp-env-setup-patch
fix(native_comp): improve env setup patch fixing potential issues
2021-02-15 11:41:52 +00:00
dca023daec fix(native_comp): improve env setup patch fixing potential issues
The old patch would dynamically glob within
Emacs.app/Contents/MacOS/lib/gcc using the full absolute path to
Emacs.app. If there are obsure characters like "[]" and others in the
absolute path, it can cause glob search within the
native-compile-setup-environment-variables function to fail, in turn
preventing native-comp from working.

The fix is to hard-code the relative paths from Emacs'
invocation-directory (**/Emacs.app/Contents/MacOS) into the environment
setup function itself, making it very simple and effectively just
joining a few strings and setting an environment variable.

It did require a little bit of cleanup and better organization of the
GCC/libgccjit releated code in the build script, creating a new GccInfo
class which is the central place for determining various paths and
information about GCC and libgccjit which the build will be using.
2021-02-15 09:49:47 +00:00
e56c26d06f docs(readme): update status section 2021-01-15 02:01:13 +00:00
b2860f22c3 chore(deps): add rubocop-daemon and solargraph to Gemfile 2021-01-15 02:00:46 +00:00
d1c5e7afb1 chore(release): 0.4.5 2021-01-06 20:32:30 +00:00
ab55f5421c fix(cli): remove defunct --[no-]native-comp-macos-fixes option
The underlying patching code was removed in v0.4.1 (commit
70bf6b05d5), as it was no longer needed,
but the related CLI flag and README info was mistakenly left in place.
2021-01-06 20:31:31 +00:00
eb09d5fa49 chore(release): 0.4.4 2021-01-02 14:01:37 +00:00
a47d3e0c6a fix(deps): add autoconf to Brewfile
On a fresh install of Big Sur with only the Xcode CLI tools installed,
autoconf is not available. Hence it needs to be installed from homebrew
instead.
2021-01-02 14:00:49 +00:00
6 changed files with 196 additions and 125 deletions

View File

@@ -1,5 +1,6 @@
# frozen_string_literal: true
brew 'autoconf'
brew 'coreutils'
brew 'curl'
brew 'expat'

View File

@@ -2,6 +2,27 @@
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.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)

View File

@@ -5,4 +5,6 @@ source 'http://rubygems.org/'
group :development do
gem 'byebug'
gem 'rubocop'
gem 'rubocop-daemon'
gem 'solargraph', '~> 0.39.17'
end

View File

@@ -18,7 +18,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-01-15) it works for me on my machine. Your luck may vary.
I have successfully built:
@@ -29,8 +29,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.1 (20C69)
- Xcode 12.3 (12C33)
## Limitations
@@ -74,8 +74,6 @@ Options:
--[no-]xwidgets Enable/disable XWidgets (default: enabled if supported)
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
--[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-titlebar Apply no-titlebar patch (default: disabled)
--no-frame-refocus Apply no-frame-refocus patch (default: disabled)
@@ -143,10 +141,6 @@ Building a Emacs.app with native-comp support
branch is now supported without much hassle thanks to the newly released
`libgccjit` Homebrew formula.
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:
```

View File

@@ -77,11 +77,13 @@ class Build
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
@options = options
@gcc_info = GccInfo.new
end
def build
@@ -99,7 +101,7 @@ class Build
symlink_internals(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
@@ -122,19 +124,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
@@ -206,28 +200,12 @@ 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] }
@gcc_library_paths ||= [
gcc_info.lib_dir,
gcc_info.darwin_lib_dir,
gcc_info.libgccjit_lib_dir
]
end
def autogen
@@ -256,20 +234,20 @@ 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')}",
'-O2',
'-march=native'
].compact.join(' ')
ENV['LDFLAGS'] = [
gcc_library_paths.map { |path| "-L#{path}" },
"-I#{gcc_dir}/include",
"-I#{libgccjit_dir}/include"
"-I#{File.join(gcc_info.root_dir, 'include')}",
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}"
].flatten.compact.join(' ')
ENV['LIBRARY_PATH'] = [
@@ -280,29 +258,30 @@ class Build
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',
@@ -443,10 +422,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 +503,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 +546,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
@@ -615,18 +598,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,7 +628,7 @@ 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)
@@ -669,7 +652,7 @@ class LibEmbedder < AbstractEmbedder
while_writable(bin_path) do
system(
'install_name_tool', '-change', match[1],
"@executable_path/#{rel_path}/#{match[2]}",
File.join('@executable_path', rel_path, match[2].to_s),
bin_path
)
end
@@ -686,11 +669,11 @@ class LibEmbedder < AbstractEmbedder
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,40 +683,121 @@ 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.rm(Dir[File.join(target_dir, '**/.DS_Store')], force: true)
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)
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
File.join(invocation_dir, gcc_info.relative_lib_dir)
end
def source_dir
@source_dir ||= File.join(gcc_dir, 'lib', 'gcc', gcc_version)
gcc_info.lib_dir
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
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)
root += '/' unless root[-1] == '/'
return if path[0..root.size - 1] != root
path[root.size..-1]
end
end
if __FILE__ == $PROGRAM_NAME
cli_options = {
macos_fixes: true,
native_full_aot: false,
parallel: Etc.nprocessors,
rsvg: false,
@@ -780,12 +844,6 @@ if __FILE__ == $PROGRAM_NAME
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

View File

@@ -1,10 +1,10 @@
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 25e2de9..bcedd31 100644
index 4036080976..2ff8dbd74c 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."))))
@@ -4079,6 +4079,52 @@ of (commands) to run simultaneously."
(let ((load (not (not load))))
(native--compile-async paths 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
+ "<%= 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