1

If I try to call an autoloaded function inside my init.el file, it will get executed normally.

However, the byte compiler will give me warnings about undeclared functions. This applies for all user-defined functions or functions from installed packages.

This does not apply for autoloaded built-in functions (defined in /usr/share/emacs/29.1/lisp/loaddefs.el.gz), which instead get recognized correctly from the bytecompiler.

With package-quickstart t, the ~/.config/emacs/package-quickstart.el file is generated which contains the autoloads from all the installed packages.

Would it be possible to tell flymake/the bytecompiler to load this file before anything else? I already tried putting the following:

(load "/home/xxxxx/.config/emacs/package-quickstart.el" 'noerror 'nomessage)

At the beginning of the init file, but the functions are still seen as undeclared. I can't require the file since it does have multiple (provide ...) and it would be impractical to load them all.

Otherwise, is there another practical way to achieve this? Please note that my main goal is to avoid declaring or autoloading, either explicitly or implicitly (with macros like use-package), functions that are already autoloaded by they source files. Also, I'd like not to suppress any warning.

cidra
  • 135
  • 5

1 Answers1

3

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.

d125q
  • 1,418
  • 5
  • 9
  • Thank you for answering! I actually already tried once to `setq elisp-flymake-byte-compile-load-path load-path` (ensuring that `load-path` is populated) but with no good results. Now I also tried your code, again with no good results. I try typing in `(vertico-mode 1)` but flymake keeps marking as undefined function. – cidra Aug 03 '23 at 20:43
  • On the oher hand, I figured out that flycheck does not give me such warning. Furthermore, flycheck has the `flycheck-emacs-lisp-initialize-packages`. Why is that? – cidra Aug 03 '23 at 20:44
  • 1
    You’re right that even when inheriting the `load-path`, Flymake seems to struggle with packages. See my edit on how to mimic `flycheck-emacs-lisp-initialize-packages`. – d125q Aug 04 '23 at 10:30
  • Thank you, it works! Yesterday I've submitted a feature request on bug-gnu-emacs regarding the porting of the flycheck-emacs-lisp-initialize-packages variable on flymake. https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-08/msg00145.html You could submit your patch if you want – cidra Aug 04 '23 at 13:58