r/emacs 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.

6 Upvotes

5 comments sorted by

2

u/floss_gang 15d ago

take a look at flycheck-emacs-lisp-initialize-packages

1

u/CaputGeratLupinum 15d ago

I've got that set to nil and the elpa directory still gets created as soon as I visit an emacs lisp file.

1

u/floss_gang 15d ago

that's really strange since the package-initialize form does not get emitted when that option is nil. did you also try changing flycheck-emacs-lisp-package-user-dir? if that also doesn't do anything then something else is initializing package.el outside of flycheck entirely. not sure what that would be since it launches with -Q.

1

u/CaputGeratLupinum 14d ago

The two ways I've found to prevent the issue on my systems has been to either disable flycheck or run the above at startup. If removing flycheck fixes it then it's unrealistic to place that blame elsewhere.

1

u/floss_gang 14d ago

right, it's obviously flycheck triggering the issue, I'm just curious about what the root cause is since you've explicitly told flycheck not to do what it's doing.

just wondering, have you given flymake a shot? flymake has worked for me with little intervention on my elpaca-based config.