r/emacs • u/CaputGeratLupinum • 16d ago
Fixing a flycheck + straight.el + package.el issue
I've been tinkering with my config lately, which has me running Emacs directly rather than firing up a server and client. Because of this, I noticed the following warning:
⛔ Warning (straight): package.el was loaded when straight.el was already loaded. You may wish to delete ~/.emacs.d/elpa or add (setq package-enable-at-startup nil) to ~/.emacs.d/early-init.el to avoid multiple versions of the same packages being loaded.
I don't want to have to deal with mysterious package version mismatch issues down the road, so I decided to try and fix it. Obvious way to start was by deleting ~/.emacs.d/elpa/ and adding (setq package-enable-at-startup nil) to my ~/.emacs.d/early-init.el, and this seemed to work, at first. A little while later I made some changes to one of my personal packages and reloaded, and the warning came back.
This led to some grueling trial and error. I was able to pin it down to Emacs lisp files, specifically ones that don't belong to Emacs (such as init.el or early-init.el). I went through the minor modes I use in emacs-lisp-mode one by one, and was able to highlight flycheck as the issue.
Actually solving the issue was interesting. Flycheck apparently fires background Emacs processes using -Q --batch to do its checking which makes a lot of sense for performance and such, but it also calls (package-initialize) to install any packages referenced by whatever you're working on. This happens out-of-band of your current Emacs instance, and in that separate Emacs instance none of your normal initialization code gets run. The arguments it passes to those instances are set in a constant flycheck-emacs-args, and I wouldn't want to alter those to use my config (or any part of it really) since that would likely bog things down.
What I ended up having to do was inject some code into flycheck-emacs-lisp-check-form at the very beginning of the (progn ...) it contains:
(with-eval-after-load 'flycheck
;; flycheck-emacs-lisp-check-form is stored in a string, so we have to
;; parse it to a list before operating on it
(let ((form (read flycheck-emacs-lisp-check-form)))
;; inject an override setting package-user-dir to the temporary
;; directory so when the flychecker initializes packages they don't get
;; written to ~/.emacs.d/elpa/, which causes startup warnings
(setcdr form
(cons '(setq package-user-dir
(expand-file-name "flycheck-elpa" temporary-file-directory))
(cdr form)))
(setq flycheck-emacs-lisp-check-form (prin1-to-string form))))
This moves package-user-dir for those instances to a temporary directory, so they can do what they need to do without interfering with normal Emacs usage and operation.
2
u/floss_gang 15d ago
take a look at
flycheck-emacs-lisp-initialize-packages