Original answer
There is no need to handle package-quickstart
specifically. What you want instead is for Flymake to inherit your running Emacs’ load path. Out of the box, Flymake uses the default load path (hence why built-in functions are recognized) along with elisp-flymake-byte-compile-load-path
, which by default includes the default directory of the buffer being compiled.
You can achieve this with the following piece of code:
(defun elisp-flymake-byte-compile-inherit-load-path (old-fun &rest args)
;; checkdoc-params: (old-fun args)
"Make Flymake inherit the `load-path' of the running Emacs."
(let ((elisp-flymake-byte-compile-load-path (append elisp-flymake-byte-compile-load-path load-path)))
(apply old-fun args)))
(advice-add 'elisp-flymake-byte-compile :around #'elisp-flymake-byte-compile-inherit-load-path)
Edit
It seems that the above solution is indeed not sufficient when dealing with functions autoloaded from package-quickstart-file
. I’m afraid you’ll have to override elisp-flymake-byte-compile
and insert a call to package-initialize
:
(defun elisp-flymake-byte-compile-with-packages (report-fn &rest _args)
"A Flymake backend for elisp byte compilation.
Spawn an Emacs process that byte-compiles a file representing the
current buffer state and calls REPORT-FN when done."
(when elisp-flymake--byte-compile-process
(when (process-live-p elisp-flymake--byte-compile-process)
(kill-process elisp-flymake--byte-compile-process)))
(let ((temp-file (make-temp-file "elisp-flymake-byte-compile"))
(source-buffer (current-buffer))
(coding-system-for-write 'utf-8-unix)
(coding-system-for-read 'utf-8))
(save-restriction
(widen)
(write-region (point-min) (point-max) temp-file nil 'nomessage))
(let* ((output-buffer (generate-new-buffer " *elisp-flymake-byte-compile*")))
(setq
elisp-flymake--byte-compile-process
(make-process
:name "elisp-flymake-byte-compile"
:buffer output-buffer
:command `(,(expand-file-name invocation-name invocation-directory)
"-Q"
"--batch"
;; "--eval" "(setq load-prefer-newer t)" ; for testing
,@(mapcan (lambda (path) (list "-L" path))
elisp-flymake-byte-compile-load-path)
"-f" "package-initialize"
"-f" "elisp-flymake--batch-compile-for-flymake"
,temp-file)
:connection-type 'pipe
:sentinel
(lambda (proc _event)
(unless (process-live-p proc)
(unwind-protect
(cond
((not (and (buffer-live-p source-buffer)
(eq proc (with-current-buffer source-buffer
elisp-flymake--byte-compile-process))))
(flymake-log :warning
"byte-compile process %s obsolete" proc))
((zerop (process-exit-status proc))
(elisp-flymake--byte-compile-done report-fn
source-buffer
output-buffer))
(t
(funcall report-fn
:panic
:explanation
(format "byte-compile process %s died" proc))))
(ignore-errors (delete-file temp-file))
(kill-buffer output-buffer))))
:stderr " *stderr of elisp-flymake-byte-compile*"
:noquery t)))))
(advice-add 'elisp-flymake-byte-compile :override #'elisp-flymake-byte-compile-with-packages)
If you’re additionally adding paths to load-path
in your init file, make sure to also add them to elisp-flymake-byte-compile-load-path
; e.g., if you have
(add-to-list 'load-path "/path/to/lisp")
make sure to also add the corresponding
(add-to-list 'elisp-flymake-byte-compile-load-path "/path/to/lisp")
omitting any package directories since they will be taken care of by package-initialize
.