;;; default.el --- Site-wide Initialization -*- lexical-binding: t -*- ;; Installed by editors/emacs and editors/emacs-devel. ;; ;; This file depends on variables defined in site-start.el, and is loaded after ;; the user's init file in the Emacs initialization sequence. ;; ;; FreeBSD elisp (USES=emacs) ports only install .el source files under ;; %%PREFIX%%/share/emacs/site-lisp/. This file arranges for those files to be ;; compiled and cached per-user, following the same pattern used by ELPA. No ;; root privileges are required after package installation. ;; ;; For Emacs builds with native compilation: .eln files are cached in ;; ~/.emacs.d/eln-cache/ by Emacs's existing machinery. ;; ;; For Emacs builds without native compilation: .elc files are cached in ;; ~/.emacs.d/freebsd-elc-cache/, with the cache directory prepended to ;; load-path so compiled files take precedence over .el source. ;; ;; To disable native compilation of all third-party elisp, including FreeBSD ;; ports elisp and ELPA packages, set `native-comp-jit-compilation' to nil. ;; ;; To disable byte-compilation of ports elisp (non-native-compilation builds ;; only), set `freebsd-inhibit-byte-compile' to t. ;;; Code: (defun freebsd--elc-cache-dest (el-file) "Map EL-FILE under `freebsd-site-lisp-dir' to its cache path. The subdirectory structure of `freebsd-site-lisp-dir' is mirrored under `freebsd-elc-cache-dir' to avoid filename collisions across ports and to allow per-subdirectory load-path entries." (let* ((relative (file-relative-name el-file freebsd-site-lisp-dir)) (dest-el (expand-file-name relative freebsd-elc-cache-dir))) (concat (file-name-sans-extension dest-el) ".elc"))) (defun freebsd--elc-cache-valid-p () "Return non-nil if the elc cache was built by the current Emacs version. Reads a version stamp file from `freebsd-elc-cache-dir' and compares it to `emacs-version'. If missing or mismatched, the cache is considered stale and is cleared." (let ((stamp (expand-file-name "emacs-version" freebsd-elc-cache-dir))) (if (file-exists-p stamp) (string= (with-temp-buffer (insert-file-contents stamp) (buffer-string)) emacs-version) nil))) (defun freebsd--elc-cache-clear () "Remove all .elc files from `freebsd-elc-cache-dir'." (when (file-directory-p freebsd-elc-cache-dir) (dolist (elc (directory-files-recursively freebsd-elc-cache-dir "\\.elc\\'")) (delete-file elc)))) (defun freebsd--elc-cache-write-stamp () "Write the current Emacs version to the cache stamp file." (let ((stamp (expand-file-name "emacs-version" freebsd-elc-cache-dir))) (with-temp-file stamp (insert emacs-version)))) (defun freebsd--setup-byte-compile-cache () "Set up the byte-compilation cache and prepend it to `load-path'. Creates `freebsd-elc-cache-dir' mirroring the subdirectory structure of `freebsd-site-lisp-dir', then prepends the cache root and all subdirectories to `load-path' so cached .elc files take precedence over .el source files." (make-directory freebsd-elc-cache-dir t) (when (file-directory-p freebsd-site-lisp-dir) (dolist (dir (directory-files freebsd-site-lisp-dir t "^[^.]")) (when (file-directory-p dir) (make-directory (expand-file-name (file-relative-name dir freebsd-site-lisp-dir) freebsd-elc-cache-dir) t)))) (add-to-list 'load-path freebsd-elc-cache-dir) (let ((default-directory freebsd-elc-cache-dir)) (normal-top-level-add-subdirs-to-load-path))) (defun freebsd--byte-compile-site-lisp () "Byte-compile FreeBSD ports elisp into `freebsd-elc-cache-dir'. Runs once on an idle timer to avoid blocking Emacs startup. First removes any stale .elc files whose corresponding .el source no longer exists in `freebsd-site-lisp-dir', then recompiles any .el files that are newer than their cached .elc, following the same pattern used by ELPA." (run-with-idle-timer 3 nil (lambda () (unless (freebsd--elc-cache-valid-p) (freebsd--elc-cache-clear)) (freebsd--elc-cache-write-stamp) (when (file-directory-p freebsd-elc-cache-dir) (dolist (elc (directory-files-recursively freebsd-elc-cache-dir "\\.elc\\'")) (let* ((relative (file-relative-name elc freebsd-elc-cache-dir)) (el (expand-file-name (concat (file-name-sans-extension relative) ".el") freebsd-site-lisp-dir))) (unless (file-exists-p el) (delete-file elc))))) (dolist (el (directory-files-recursively freebsd-site-lisp-dir "\\.el\\'")) (let ((base (file-name-nondirectory el))) (unless (member base '("site-start.el" "subdirs.el")) (let ((elc (freebsd--elc-cache-dest el))) (when (or (not (file-exists-p elc)) (file-newer-than-file-p el elc)) (let ((byte-compile-log-level 0) (byte-compile-dest-file-function #'freebsd--elc-cache-dest)) (byte-compile-file el)))))))))) (defun freebsd--load-autoloads () "Load all autoloads files installed by FreeBSD elisp ports. This mirrors what package.el does for ELPA packages, ensuring that autoloaded functions are available without requiring users to explicitly load each package." (when (file-directory-p freebsd-site-lisp-dir) (dolist (autoloads (directory-files-recursively freebsd-site-lisp-dir ".*-autoloads\\.el\\'")) (load autoloads t t)))) (defun freebsd--clean-stale-eln-dirs () "Remove eln-cache subdirectories from previous Emacs builds. Emacs native compilation writes .eln files into a hash-named subdirectory of eln-cache specific to the running binary. Old subdirectories from previous builds are never cleaned up automatically. This function removes all subdirectories that do not match `comp-native-version-dir'." (let ((cache-dir (expand-file-name "eln-cache" user-emacs-directory)) (current-dir comp-native-version-dir)) (when (file-directory-p cache-dir) (dolist (dir (directory-files cache-dir t "\\`[^.]")) (when (and (file-directory-p dir) (not (string= (file-name-nondirectory dir) current-dir))) (delete-directory dir t)))))) ;;; Entry point ;; When running in batch mode (e.g. during port builds), skip all ;; compilation machinery to avoid interference with the build environment. (unless noninteractive (freebsd--load-autoloads) (if (native-comp-available-p) (when native-comp-jit-compilation (freebsd--clean-stale-eln-dirs) (native-compile-async freebsd-site-lisp-dir 'recursively)) (unless freebsd-inhibit-byte-compile (freebsd--setup-byte-compile-cache) (freebsd--byte-compile-site-lisp)))) ;;; default.el ends here