Compare commits

..

16 Commits

Author SHA1 Message Date
59f1bcd3e8 chore(release): 0.6.26 2021-11-27 05:01:57 +00:00
e767e284b7 Merge pull request #62 from jimeh/improve-shared-library-embedding 2021-11-27 05:01:16 +00:00
8129a2e93b docs(readme): update Status section, and minor tweaks 2021-11-27 04:58:54 +00:00
4ae288cae3 feat(build): re-link eln files by default again
This reverts commit d338c136db.

Thanks to using relinking with @rpath, paths are shorting leaving enough
room in all *.eln files to be signed.
2021-11-27 04:25:03 +00:00
3bd78d130a feat(native-comp): no longer require gcc homebrew formula
This finally makes Emacs.app with native-comp fully self-contained, no
longer requiring the GCC Homebrew formula to be installed when
loading *.eln files that link against
/usr/local/lib/gcc/11/libgcc_s.1.dylib.

By adding the signing entitlement
com.apple.security.cs.allow-dyld-environment-variables, which allows
dynamic library loading to be controlled via DYLD_* environment
variables. It seems the lack of this was preventing Emacs from loading
the bundled libgcc_s.1.dylib file from Contents/Frameworks.

Fixes #53
2021-11-27 04:01:23 +00:00
fb5362ce18 fix(embed): relink shared libraries with @rpath instead of @executable_path
This allows much shorter shared library link paths within *.eln files
compared to when using @executable_path, which leaves enough space in
them to sign all *.eln files, while directly having them linked against
the embedded copy of GCC shared libraries.
2021-11-27 03:47:43 +00:00
1a34a9504a chore(release): 0.6.25 2021-11-25 23:38:52 +00:00
8513521d29 Merge pull request #61 from jimeh/refactor-file-operations 2021-11-25 23:36:55 +00:00
88bbefadc6 refactor(embed): use cp, mv, and chmod shell commands instead of FileUtils
It seems like Ruby's FileUtils.cp_r method especially was messing with
some file attributes, causing Emacs to print details about loading
various elisp files on startup. While when Emacs.app is copied into the
output build directory using "cp -a" instead of FileUtils.cp_r it does
not exhibit this behavior.
2021-11-25 20:14:16 +00:00
f1bf1d93b8 chore(release): 0.6.24 2021-11-24 21:42:52 +00:00
8a467b0d43 fix(embedding): embedding GCC fails when paths do not require sanitizing
It seems homebrew bottle of GCC for macOS Monterey (12.0) have changed their
directory structure slightly, which caused an issue were we were trying
to rename a specific directory to the same name it already had.

This behavior is still required as it looks like GCC on macOS
Catalina (10.15), the GCC homebrew bottle still uses the old directory
structure.
2021-11-24 21:39:03 +00:00
9c29f721b4 chore(release): 0.6.23 2021-11-10 22:19:28 +00:00
4ac71ddf39 docs(readme): update usage section with latest help text 2021-11-10 22:19:06 +00:00
d338c136db fix(build): do not re-link eln files by default
Relinking is currently failing for some of the *.eln files. See #60 for
details of the error.

Long-term plan is to investigate native-comp's compilation options to
hopefully resolve this issue.
2021-11-10 22:11:13 +00:00
d054a17fc7 chore(release): 0.6.22 2021-11-10 01:56:19 +00:00
4030ceb9ca feat(patch): add support for posix-spawn patch from emacs-plus 2021-11-10 01:55:38 +00:00
5 changed files with 163 additions and 85 deletions

View File

@@ -2,6 +2,42 @@
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.6.26](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.25...v0.6.26) (2021-11-27)
### Features
* **build:** re-link eln files by default again ([4ae288c](https://github.com/jimeh/build-emacs-for-macos/commit/4ae288cae34c5e1d291dad7b6b654fe37c4a221f))
* **native-comp:** no longer require gcc homebrew formula ([3bd78d1](https://github.com/jimeh/build-emacs-for-macos/commit/3bd78d130a5419a6530a7d30e271569e501870fb)), closes [#53](https://github.com/jimeh/build-emacs-for-macos/issues/53)
### Bug Fixes
* **embed:** relink shared libraries with [@rpath](https://github.com/rpath) instead of [@executable](https://github.com/executable)_path ([fb5362c](https://github.com/jimeh/build-emacs-for-macos/commit/fb5362ce183ce43e52afcc0fc721cf2145f9c85b))
### [0.6.25](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.24...v0.6.25) (2021-11-25)
### [0.6.24](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.23...v0.6.24) (2021-11-24)
### Bug Fixes
* **embedding:** embedding GCC fails when paths do not require sanitizing ([8a467b0](https://github.com/jimeh/build-emacs-for-macos/commit/8a467b0d43140f6956d53c27e2319ae1b572868c))
### [0.6.23](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.22...v0.6.23) (2021-11-10)
### Bug Fixes
* **build:** do not re-link eln files by default ([d338c13](https://github.com/jimeh/build-emacs-for-macos/commit/d338c136db8acc4378154cf66ed7db5462787602)), closes [#60](https://github.com/jimeh/build-emacs-for-macos/issues/60)
### [0.6.22](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.21...v0.6.22) (2021-11-10)
### Features
* **patch:** add support for posix-spawn patch from emacs-plus ([4030ceb](https://github.com/jimeh/build-emacs-for-macos/commit/4030ceb9cab6749af3c28161ac97caec90a8aed0))
### [0.6.21](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.20...v0.6.21) (2021-10-27)
### [0.6.20](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.19...v0.6.20) (2021-10-23)

View File

@@ -17,21 +17,10 @@ Use this script at your own risk.
built from the `master` branch. This script allows you to choose any branch,
tag, or git ref you want.
## Status
## Binary Builds
As of writing (2021-04-25) it works for me on my machine. Your luck may vary.
I have successfully built:
- `emacs-27.1` release git tag
- `master` branch (Emacs 28.x)
- `feature/native-comp` branch (Emacs 28.x)
For reference, my machine is:
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
- macOS Big Sur 11.2.3 (20D91)
- Xcode 12.4 (12D4e)
Nightly and stable binary builds produced with this build script are available
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
## Limitations
@@ -41,14 +30,9 @@ The build produced does have some limitations:
application will be that of the machine it was built on.
- The minimum required macOS version of the built application will be the same
as that of the machine it was built on.
- The application is not signed, so running it on machines other than the one
that built the application will yield warnings. If you want to make a signed
Emacs.app, google is you friend for finding signing instructions.
## Binary Builds
Nightly and stable binary builds produced with this build script are available
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
- The application is not signed automatically, but the CLI tool used to sign the
nightly builds is available. Run `go run ./cmd/emacs-builder package --help`
for details. More detailed instructions will come soon.
## Requirements
@@ -66,6 +50,26 @@ from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
brew install ruby
```
## Status
As of writing (2021-11-27) it works for me on my machine and for the nightly
builds in [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds). Your luck
may vary.
I have successfully built:
- `emacs-28` release branch
- `master` branch (Emacs 29.x)
For reference, my machine is:
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
- macOS Monterey 12.0.1 (21A559)
- Xcode 13.1 (13A1030d)
Nightly builds are built with GitHub Actions on GitHub-hosted runners, using
`macos-10.15`.
## Usage
```
@@ -81,8 +85,10 @@ Options:
--[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-]relink-eln-files Enable/disable re-linking shared libraries in bundled *.eln files (default: enabled)
--[no-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
--no-titlebar Apply no-titlebar patch (default: disabled)
--posix-spawn Apply posix-spawn 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
@@ -90,7 +96,8 @@ Options:
--build-name NAME Override generated build name
--dist-include x,y,z List of extra files to copy from Emacs source into build folder/archive (default: COPYING)
--[no-]archive Enable/disable creating *.tbz archive (default: enabled)
--[no-]archive-keep Enable/disable keeping source folder for archive (default: disabled)
--[no-]archive-keep-build-dir
Enable/disable keeping source folder for archive (default: disabled)
--plan FILE Follow given plan file, instead of using given git ref/sha
```

View File

@@ -26,7 +26,7 @@ module Output
if newline
warn "==> #{msg}"
else
STDERR.print "==> #{msg}"
$stderr.print "==> #{msg}"
end
end
@@ -35,6 +35,19 @@ module Output
end
end
module System
include Output
def run_cmd(*args)
out("CMD: #{args.join(' ')}")
cmd(*args)
end
def cmd(*args)
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
end
end
class OS
def self.version
@version ||= OSVersion.new
@@ -71,6 +84,7 @@ end
class Build
include Output
include System
EMACS_MIRROR_REPO = 'emacs-mirror/emacs'
DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s'
@@ -199,7 +213,7 @@ class Build
end
out "CMD: #{log_args.join(' ')}"
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
cmd(*args)
target
end
@@ -400,13 +414,13 @@ class Build
info "Copying \"#{app_name}\" to: #{target_dir}"
FileUtils.mkdir_p(target_dir)
FileUtils.cp_r(app, target_dir)
cmd('cp', '-a', app, target_dir)
options[:dist_include]&.each do |filename|
src = File.join(source_dir, filename)
if File.exist?(src)
info "Copying \"#{filename}\" to: #{target_dir}"
FileUtils.cp_r(src, target_dir)
cmd('cp', '-pRL', src, target_dir)
else
info "Warning: #{filename} does not exist in #{source_dir}"
end
@@ -431,7 +445,7 @@ class Build
info 'Creating symlinks within Emacs.app needed for native-comp'
if !File.exist?('lisp') && File.exist?('Resources/lisp')
FileUtils.ln_s('Resources/lisp', 'lisp')
run_cmd('ln', '-s', 'Resources/lisp', 'lisp')
end
# Check for folder name containing two dots (.), as this causes Apple's
@@ -453,7 +467,7 @@ class Build
new_name = File.join(parent, base.gsub(/\.(.+)\./, '-\\1-'))
info "Renaming: #{old_name} --> #{new_name}"
FileUtils.mv(old_name, new_name)
cmd('mv', old_name, new_name)
end
base = File.basename(parent)
@@ -477,7 +491,7 @@ class Build
end
target = File.basename(source)
FileUtils.ln_s(source, target) unless File.exist?(target)
run_cmd('ln', '-s', source, target) unless File.exist?(target)
end
end
@@ -535,7 +549,7 @@ class Build
if !File.exist?(archive_filename)
info "Creating #{filename} archive in \"#{target_dir}\"..."
FileUtils.cd(parent_dir) do
system('tar', '-cjf', archive_filename, build)
cmd('tar', '-cjf', archive_filename, build)
if options[:archive_keep] == false
info "Removing \"#{build}\" directory from #{parent_dir}"
@@ -600,11 +614,6 @@ class Build
response.body
end
def run_cmd(*args)
out "CMD: #{args.join(' ')}"
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
end
def effective_version
@effective_version ||= begin
case ref
@@ -651,6 +660,15 @@ class Build
end
end
if %w[emacs-28 emacs-29].include?(effective_version)
if options[:posix_spawn]
p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
"patches/#{effective_version}/posix-spawn.patch"
}
end
end
if effective_version == 'emacs-27'
p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
@@ -741,6 +759,7 @@ end
class AbstractEmbedder
include Output
include System
attr_reader :app
@@ -751,23 +770,27 @@ class AbstractEmbedder
end
def invocation_dir
File.join(app, 'Contents', 'MacOS')
@invocation_dir ||= File.join(app, 'Contents', 'MacOS')
end
def bin
File.join(invocation_dir, 'Emacs')
@bin ||= File.join(invocation_dir, 'Emacs')
end
def bin_dir
File.join(invocation_dir, 'bin')
@bin_dir ||= File.join(invocation_dir, 'bin')
end
def lib_dir
File.join(invocation_dir, 'lib')
@lib_dir ||= frameworks_dir
end
def frameworks_dir
@frameworks_dir ||= File.join(app, 'Contents', 'Frameworks')
end
def resources_dir
File.join(app, 'Contents', 'Resources')
@resources_dir ||= File.join(app, 'Contents', 'Resources')
end
end
@@ -777,11 +800,11 @@ class CLIHelperEmbedder < AbstractEmbedder
target = File.join(bin_dir, 'emacs')
dir = File.dirname(target)
info "Adding \"emacs\" CLI helper to #{dir}"
info 'Adding "emacs" CLI helper to Emacs.app'
FileUtils.mkdir_p(dir)
FileUtils.cp(source, target)
FileUtils.chmod('+w', target)
run_cmd('cp', '-pRL', source, target)
run_cmd('chmod', '+w', target)
end
end
@@ -807,7 +830,7 @@ class CSourcesEmbedder < AbstractEmbedder
rel = f[src_dir.size + 1..-1]
target = File.join(resources_dir, 'src', rel)
FileUtils.mkdir_p(File.dirname(target))
FileUtils.cp(f, target)
cmd('cp', '-pRL', f, target)
end
return if File.exist?(site_start_el_file) &&
@@ -828,14 +851,14 @@ end
class LibEmbedder < AbstractEmbedder
attr_reader :lib_source
attr_reader :extra_libs
attr_reader :embed_eln_files
attr_reader :relink_eln_files
def initialize(app, lib_source, extra_libs = [], embed_eln_files = true)
def initialize(app, lib_source, extra_libs = [], relink_eln_files = true)
super(app)
@lib_source = lib_source
@extra_libs = extra_libs
@embed_eln_files = embed_eln_files
@relink_eln_files = relink_eln_files
end
def embed
@@ -845,15 +868,20 @@ class LibEmbedder < AbstractEmbedder
binary ||= bin
FileUtils.cd(File.dirname(app)) do
rel_path = Pathname.new(lib_dir).relative_path_from(
Pathname.new(File.dirname(binary))
).to_s
rpath = File.join('@executable_path', rel_path)
set_rpath(binary, rpath)
copy_libs(binary)
copy_extra_libs(extra_libs, binary) if extra_libs.any?
if eln_files.any?
if relink_eln_files && 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) } if embed_eln_files
eln_files.each { |f| copy_libs(f) }
end
end
end
@@ -864,21 +892,19 @@ class LibEmbedder < AbstractEmbedder
@eln_files ||= Dir[File.join(app, 'Contents', '**', '*.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
def set_rpath(exe, rpath)
return if rpath.nil? || rpath == ''
rpath = File.join('@executable_path', rel_path)
rpaths = `otool -l "#{exe}" | grep -A 2 'cmd LC_RPATH' | grep 'path'`
return if rpaths.include?(rpath)
unless rpaths.include?(rpath)
while_writable(exe) do
system('install_name_tool', '-add_rpath',
File.join('@executable_path', rel_path), exe)
end
while_writable(exe) do
cmd('install_name_tool', '-add_rpath', rpath, exe)
end
end
def copy_libs(exe)
exe_file = File.basename(exe)
`otool -L "#{exe}"`.split("\n")[1..-1].each do |line|
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
@@ -886,41 +912,37 @@ class LibEmbedder < AbstractEmbedder
while_writable(exe) do
if match[2] == exe_file
system('install_name_tool', '-id',
File.join('@executable_path', rel_path, match[2].to_s), exe)
cmd('install_name_tool', '-id',
File.join('@rpath', match[2].to_s), exe)
else
system('install_name_tool', '-change', match[1],
File.join('@executable_path', rel_path, match[2].to_s), exe)
cmd('install_name_tool', '-change', match[1],
File.join('@rpath', match[2].to_s), exe)
end
end
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(File.join(lib_dir, match[2].to_s), rel_path)
cmd('cp', '-pRL', match[1], lib_dir)
copy_libs(File.join(lib_dir, match[2].to_s))
end
end
def copy_extra_libs(extra_libs, exe, rel_path = nil)
rel_path ||= Pathname.new(lib_dir).relative_path_from(
Pathname.new(File.dirname(exe))
).to_s
def copy_extra_libs(extra_libs, exe)
extra_libs.each do |lib|
lib_file = File.basename(lib)
target = "#{lib_dir}/#{lib_file}"
unless File.exist?(target)
FileUtils.mkdir_p(lib_dir)
FileUtils.cp(lib, lib_dir)
cmd('cp', '-pRL', lib, lib_dir)
end
while_writable(target) do
system('install_name_tool', '-id',
File.join('@executable_path', rel_path, lib_file), target)
cmd('install_name_tool', '-id',
File.join('@rpath', lib_file), target)
end
copy_libs(target, rel_path)
copy_libs(target)
end
end
@@ -929,7 +951,7 @@ class LibEmbedder < AbstractEmbedder
File.chmod(0o775, file)
yield
ensure
File.chmod(mode, file)
File.chmod(mode, file) if File.exist?(file)
end
end
@@ -954,10 +976,12 @@ class GccLibEmbedder < AbstractEmbedder
end
FileUtils.mkdir_p(File.dirname(target_dir))
FileUtils.cp_r(source_dir, target_dir)
run_cmd('cp', '-pRL', 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)
run_cmd('chmod', '-R', 'u+w', target_dir)
if source_darwin_dir != target_darwin_dir
run_cmd('mv', source_darwin_dir, target_darwin_dir)
end
env_setup = ERB.new(NATIVE_COMP_ENV_VAR_TPL).result(gcc_info.get_binding)
return if File.exist?(site_start_el_file) &&
@@ -1045,7 +1069,7 @@ class GccInfo
end
def relative_lib_dir
@relative_lib_dir ||= relative_dir(lib_dir, root_dir)
@relative_lib_dir ||= relative_dir(lib_dir, File.join(root_dir, 'lib'))
end
def darwin_lib_dir
@@ -1060,7 +1084,9 @@ class GccInfo
end
def relative_darwin_lib_dir
@relative_darwin_lib_dir ||= relative_dir(darwin_lib_dir, root_dir)
@relative_darwin_lib_dir ||= relative_dir(
darwin_lib_dir, File.join(root_dir, 'lib')
)
end
# Sanitize folder name with full "MAJOR.MINOR.PATCH" version number to just
@@ -1218,6 +1244,10 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:no_titlebar] = true
end
opts.on('--posix-spawn', 'Apply posix-spawn patch (default: disabled)') do
cli_options[:posix_spawn] = true
end
opts.on('--no-frame-refocus',
'Apply no-frame-refocus patch (default: disabled)') do
cli_options[:no_frame_refocus] = true

View File

@@ -14,6 +14,7 @@ var DefaultEmacsEntitlements = []string{
"com.apple.security.cs.allow-jit",
"com.apple.security.network.client",
"com.apple.security.cs.disable-library-validation",
"com.apple.security.cs.allow-dyld-environment-variables",
"com.apple.security.automation.apple-events",
}

View File

@@ -50,6 +50,7 @@ var entitlementsTestCases = []struct {
"com.apple.security.cs.allow-jit",
"com.apple.security.network.client",
"com.apple.security.cs.disable-library-validation",
"com.apple.security.cs.allow-dyld-environment-variables",
"com.apple.security.automation.apple-events",
},
//nolint:lll
@@ -64,6 +65,8 @@ var entitlementsTestCases = []struct {
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.automation.apple-events</key>
<true/>
</dict>
@@ -78,6 +81,7 @@ func TestDefaultEmacsEntitlements(t *testing.T) {
"com.apple.security.cs.allow-jit",
"com.apple.security.network.client",
"com.apple.security.cs.disable-library-validation",
"com.apple.security.cs.allow-dyld-environment-variables",
"com.apple.security.automation.apple-events",
},
DefaultEmacsEntitlements,