@@ -408,6 +408,7 @@ class Build
408408 fatal 'Tarball extraction failed.' unless result
409409
410410 patches . each { |patch | apply_patch ( patch , target ) }
411+ apply_macos_startup_patch ( target )
411412
412413 # Keep a copy of src after patches have been applied. This will be used to
413414 # embed C sources into the output Emacs.app bundle.
@@ -900,6 +901,93 @@ class Build
900901 File . write ( filename , content )
901902 end
902903
904+ MACOS_STARTUP_EL_CONTENT = <<~ELISP
905+ ;;; macos-startup.el --- macOS specific startup actions -*- lexical-binding: t -*-
906+
907+ ;; Maintainer: Jim Myhrberg <[email protected] > 908+ ;; Keywords: macos, internal
909+ ;; Homepage: https://github.com/jimeh/build-emacs-for-macos
910+
911+ ;; This file is not part of GNU Emacs.
912+
913+ ;;; Commentary:
914+
915+ ;; This file contains macOS specific startup actions for self-contained
916+ ;; macOS *.app bundles. It enables native-compilation via a bundled
917+ ;; libgccjit, and for bundled C-sources to be found for documentation
918+ ;; purposes,
919+
920+ ;;; Code:
921+
922+ (defun macos-startup--in-app-bundle-p ()
923+ "Check if invoked from a macOS .app bundle."
924+ (and (eq system-type 'darwin)
925+ invocation-directory
926+ (string-match-p ".+\\ .app/Contents/MacOS/?$" invocation-directory)))
927+
928+ (defun macos-startup--set-source-directory ()
929+ "Set `source-directory' so that C-sources can be located."
930+ (let* ((src-dir (expand-file-name "../Resources/src" invocation-directory)))
931+ (when (file-directory-p src-dir)
932+ (setq source-directory (file-name-directory src-dir)))))
933+
934+ (defun macos-startup--setup-library-path ()
935+ "Configure LIBRARY_PATH env var for native compilation on macOS.
936+
937+ Ensures LIBRARY_PATH includes paths to the libgccjit and gcc libraries
938+ which are bundled into the .app bundle. This allows native compilation
939+ to work without any external system dependencies aside from Xcode."
940+ (let* ((new-paths
941+ (list (expand-file-name "../Frameworks/gcc/lib" invocation-directory)
942+ (expand-file-name "../Frameworks/gcc/lib/apple-darwin" invocation-directory)
943+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"))
944+ (valid-paths (delq nil (mapcar (lambda (path)
945+ (when (file-directory-p path)
946+ path))
947+ new-paths)))
948+ (existing-paths (split-string (or (getenv "LIBRARY_PATH") "") ":" t))
949+ (unique-paths (delete-dups (append valid-paths existing-paths))))
950+
951+ (when unique-paths
952+ (setenv "LIBRARY_PATH" (mapconcat 'identity unique-paths path-separator)))))
953+
954+ (defun macos-startup--init ()
955+ "Perform macOS specific startup operations."
956+ (when (macos-startup--in-app-bundle-p)
957+ (macos-startup--set-source-directory)
958+ (when (and (fboundp 'native-comp-available-p)
959+ (native-comp-available-p))
960+ (macos-startup--setup-library-path))))
961+
962+ (add-hook 'after-pdump-load-hook #'macos-startup--init)
963+
964+ ;;; macos-startup.el ends here
965+ ELISP
966+
967+ def apply_macos_startup_patch ( target )
968+ macos_startup_el = File . join ( target , 'lisp' , 'macos-startup.el' )
969+
970+ unless File . exist? ( macos_startup_el )
971+ info 'Adding macos-startup.el to lisp sources...'
972+ FileUtils . mkdir_p ( File . dirname ( macos_startup_el ) )
973+ File . write ( macos_startup_el , MACOS_STARTUP_EL_CONTENT )
974+ end
975+
976+ loadup_el = File . join ( target , 'lisp' , 'loadup.el' )
977+ loadup_content = File . read ( loadup_el )
978+
979+ return if loadup_content . include? ( '(load "macos-startup")' )
980+
981+ info 'Patching loadup.el to load macos-startup.el...'
982+ File . write (
983+ loadup_el ,
984+ loadup_content . gsub (
985+ '(load "startup")' ,
986+ "(load \" startup\" )\n (load \" macos-startup\" )"
987+ )
988+ )
989+ end
990+
903991 def meta
904992 return @meta if @meta
905993
@@ -1068,6 +1156,20 @@ class Build
10681156 else
10691157 apply_patch ( { file : patch_file } , target )
10701158 end
1159+ elsif patch [ :source ]
1160+ patch_dir = "#{ target } /macos_patches"
1161+ run_cmd ( 'mkdir' , '-p' , patch_dir )
1162+
1163+ patch_file = File . join ( patch_dir , 'patch-{num}.diff' )
1164+ num = 1
1165+ while File . exist? ( patch_file . gsub ( '{num}' , num . to_s . rjust ( 3 , '0' ) ) )
1166+ num += 1
1167+ end
1168+ patch_file = patch_file . gsub ( '{num}' , num . to_s . rjust ( 3 , '0' ) )
1169+
1170+ File . write ( patch_file , patch [ :source ] )
1171+
1172+ apply_patch ( { file : patch_file } , target )
10711173 elsif patch [ :replace ]
10721174 fatal 'Patch replace input error' unless patch [ :replace ] . size == 3
10731175
@@ -1198,12 +1300,6 @@ class CLIHelperEmbedder < AbstractEmbedder
11981300end
11991301
12001302class CSourcesEmbedder < AbstractEmbedder
1201- PATH_PATCH = <<~ELISP
1202- ;; Allow Emacs to find bundled C sources.
1203- (setq source-directory
1204- (expand-file-name ".." (file-name-directory load-file-name)))
1205- ELISP
1206-
12071303 attr_reader :source_dir
12081304
12091305 def initialize ( app , source_dir )
@@ -1228,15 +1324,6 @@ class CSourcesEmbedder < AbstractEmbedder
12281324 src_dir , target_dir , File . join ( '**' , '*.{awk,c,cc,h,in,m,mk}' )
12291325 )
12301326 end
1231-
1232- if File . exist? ( site_start_el_file ) &&
1233- File . read ( site_start_el_file ) . include? ( PATH_PATCH )
1234- return
1235- end
1236-
1237- debug "Patching '#{ relative_app_path ( site_start_el_file ) } ' to allow " \
1238- 'Emacs to find bundled C sources'
1239- File . open ( site_start_el_file , 'a' ) { |f | f . puts ( "\n #{ PATH_PATCH } " ) }
12401327 end
12411328
12421329 private
@@ -1252,10 +1339,6 @@ class CSourcesEmbedder < AbstractEmbedder
12521339 run_cmd ( 'cp' , '-pRL' , f , target )
12531340 end
12541341 end
1255-
1256- def site_start_el_file
1257- @site_start_el_file ||= File . join ( resources_dir , 'lisp' , 'site-start.el' )
1258- end
12591342end
12601343
12611344class LibEmbedder < AbstractEmbedder
@@ -1521,49 +1604,13 @@ class GccLibEmbedder < AbstractEmbedder
15211604
15221605 FileUtils . rm ( Dir [ File . join ( target_dir , '**' , '.DS_Store' ) ] , force : true )
15231606
1524- if target_darwin_dir != sanitized_target_darwin_dir
1525- run_cmd ( 'mv' , target_darwin_dir , sanitized_target_darwin_dir )
1526- end
1527-
1528- env_setup = ERB . new ( NATIVE_COMP_ENV_VAR_TPL ) . result ( gcc_info . get_binding )
1529- if File . exist? ( site_start_el_file ) &&
1530- File . read ( site_start_el_file ) . include? ( env_setup )
1531- return
1532- end
1607+ return unless target_darwin_dir != sanitized_target_darwin_dir
15331608
1534- debug 'Setting up site-start.el for self-contained native-comp Emacs.app'
1535- File . open ( site_start_el_file , 'a' ) { |f | f . puts ( "\n #{ env_setup } " ) }
1609+ run_cmd ( 'mv' , target_darwin_dir , sanitized_target_darwin_dir )
15361610 end
15371611
15381612 private
15391613
1540- NATIVE_COMP_ENV_VAR_TPL = <<~ELISP
1541- ;; Set LIBRARY_PATH to point at bundled GCC and Xcode Command Line Tools to
1542- ;; ensure native-comp works.
1543- (when (and (eq system-type 'darwin)
1544- (string-match-p "\\ .app\\ /Contents\\ /MacOS\\ /?$"
1545- invocation-directory))
1546- (let* ((library-path-env (getenv "LIBRARY_PATH"))
1547- (devtools-dir
1548- "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
1549- (gcc-dir (expand-file-name
1550- "<%= app_bundle_target_lib_dir %>"
1551- invocation-directory))
1552- (darwin-dir (expand-file-name
1553- "<%= app_bundle_target_darwin_lib_dir %>"
1554- invocation-directory))
1555- (lib-paths (list)))
1556-
1557- (if library-path-env
1558- (push library-path-env lib-paths))
1559- (if (file-directory-p devtools-dir)
1560- (push devtools-dir lib-paths))
1561- (push darwin-dir lib-paths)
1562- (push gcc-dir lib-paths)
1563-
1564- (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":"))))
1565- ELISP
1566-
15671614 # Remove all rpaths from Mach-O library files except for @loader_path.
15681615 def tidy_lib_rpaths ( directory )
15691616 Dir [ File . join ( directory , '**' , '*.{dylib,so}' ) ] . each do |file_path |
@@ -1607,10 +1654,6 @@ class GccLibEmbedder < AbstractEmbedder
16071654 def source_darwin_dir
16081655 gcc_info . darwin_lib_dir
16091656 end
1610-
1611- def site_start_el_file
1612- @site_start_el_file ||= File . join ( resources_dir , 'lisp' , 'site-start.el' )
1613- end
16141657end
16151658
16161659class GccInfo
0 commit comments