A while ago, I was trying to work around the emacs maintainers’ curious decision to always load a .elc file in preference to a .el file, even if the .el file is newer.
I didn’t want to settle for that. My solution was to recompile my emacs lisp files prior to running emacs.
I see now that there is a better alternative: replace the built-in require
with my own version. And it is not just because it is open source that I can do this. I can fix it as a user too.
(require feature &optional filename noerror)
require performs the following steps:
- do nothing if the feature has already been loaded (this protects against recursive loads)
- finds the appropriate file in load-path
- loads either the .el or .elc file
- throws an error if the required feature is not provided
- provides a mechanism for supressing errors
- provides a mechanism to load a feature from a specific file
If I wanted a drop-in replacement, I should do all of those things, and replicate the function signature. However, I don’t need the error suppression or loading from a specific file. I also like to be able to force a load even if a library has been loaded previously. If this doesn’t match your requirements, it should be easy to adapt the code below.
(defun require* (feature &optional force) (when (or force (not (featurep feature))) (setq feature (symbol-name feature)) (let ((path load-path) (found-filename nil) head el-attribs elc-attribs) (while (and (not found-filename) path) (setq head (pop path)) (let ((el-filename (format "%s/%s.el" head feature)) (elc-filename (format "%s/%s.elc" head feature))) ;; if .el and .elc both exist, pick the newest ;; otherwise pick the one that exists if any (cond ((and (file-exists-p el-filename) (file-exists-p elc-filename)) (if (file-newer-than-file-p el-filename elc-filename) (setq found-filename el-filename) (setq found-filename elc-filename))) ((file-exists-p el-filename) (setq found-filename el-filename)) ((file-exists-p elc-filename) (setq found-filename elc-filename))) ;; load file if found (when found-filename (message (format "Found: [%s]" found-filename)) (let ((load-suffixes ())) (load found-filename))))) (unless found-filename (error "Unable to find %s" feature)))))
The brave might choose to do (defun require ...)
instead of (defun require* ...)
Leave a comment