FlyMake

FlyMake performs on-the-fly syntax checks on the files being edited using the external syntax check tool (usually the compiler). Highlights erroneous lines and displays associated error messages.

The project has been part of Emacs since Emacs 23, was then abandoned/maintained in various projects outside of Emacs for some years, but has recently had a revival in Emacs 26, so that many major modes now are supported out of the box, if you just enable Flymake.

As of version 1.2, Flymake supports displaying project-wide diagnostics using the built-in library project.el.

Flymake can be used by LSP clients for placing their messages.

Much of this page is probably obsolete after the Emacs 26 revival?

Keyboard support for showing the errors

Type “C-h .” This is the standard shortcut for help-at-point. By customizing the variable help-at-pt-display-when-idle using the Customize menu, you can display such help messages automatically in the Echo Area. Note that this command is not specifically for Flymake, and works with positioned message from many libraries.

Flymake’s messages can also be displayed in a tool-tip when hovering over a highlighted area with the mouse.

Language Support

Flymake works by running checkers listed in the hook variable flymake-diagnostic-functions. For example, in emacs-lisp-mode, the buffer-local value of this hook will include the checkers elisp-flymake-byte-compile and elisp-flymake-checkdoc. Therefore, checkers can be disabled by using the function remove-hook on this variable.

The Flymake manual includes an annotated example for creating custom checkers.

Built-in checkers are provided for:

with other checkers currently available as third-party packages. Some are listed here:

Spellchecking

Flymake also allow for spellchecking using tools like LanguageTool with help from flymake-languagetool

Hints And Questions

Long Checks

Flymake doesn’t interrupt itself if you change the buffer while it’s checking. I use the following to get around it:

  (defun interrupting-flymake-start-syntax-check (base-function)
    (when (and (boundp 'flymake-syntax-check-process) (process-live-p flymake-syntax-check-process))
      (setq flymake-check-was-interrupted t)
      (flymake-kill-process flymake-syntax-check-process))
    (funcall base-function)
    (let ((proc (car flymake-processes)))
      (set-process-query-on-exit-flag proc nil)
      (set (make-local-variable 'flymake-syntax-check-process) proc)
      (setq flymake-check-was-interrupted t)
      (setq flymake-is-running nil)))
  (advice-add 'flymake-start-syntax-check :around #'interrupting-flymake-start-syntax-check)

--DaveAbrahams

Ada

The following works with Gnat:

  ;; Flymake for Ada
  (require 'flymake)
  (defun flymake-ada-init ()
      (flymake-simple-make-init-impl
        'flymake-create-temp-with-folder-structure nil nil
        buffer-file-name
        'flymake-get-ada-cmdline))
  (defun flymake-get-ada-cmdline (source base-dir)
    `("gnatmake" ("-gnatc" "-gnatwa" ,(concat "-I" (expand-file-name base-dir)) ,source)))
  (push '(".+\\.adb$" flymake-ada-init) flymake-allowed-file-name-masks)
  (push '(".+\\.ads$" flymake-ada-init) flymake-allowed-file-name-masks)
  (push '("\\([^:]*\\):\\([0-9]+\\):[0-9]+: \\(.*\\)"
	  1 2 nil 3)
        flymake-err-line-patterns)

Automake

When using a moderately complex automake project, the trivial option of adding a check-syntax rule on every “interesting” Makefile is no longer enough, as you might have, for example, target-dependant compile flags, as well as files that must be compiled with different compilers.

Instead, you can create a flymake.mk file (defining the check-syntax rule) somewhere on your project, and include it on every Makefile.am that you want to add syntax check support to:

  include $(top_srcdir)/flymake.mk

Then, the flymake.mk file, would look something like:

  get_cs_flags = $(foreach target,$(subst .,_,$(subst -,_,$($(2)))),$($(target)_$(1)FLAGS))
  get_cs_all_flags = $(foreach type,$(2),$(call get_cs_flags,$(1),$(type)))
  get_cs_compile = $(if $(subst C,,$(1)),$($(1)COMPILE),$(COMPILE))
  get_cs_cmdline = $(call get_cs_compile,$(1)) $(call get_cs_all_flags,$(1),check_PROGRAMS bin_PROGRAMS lib_LTLIBRARIES) -fsyntax-only
  check-syntax:
  	s=$(suffix $(CHK_SOURCES));\
  	if   [ "$$s" = ".c"   ]; then $(call get_cs_cmdline,C)	 $(CHK_SOURCES);\
  	elif [ "$$s" = ".cpp" ]; then $(call get_cs_cmdline,CXX) $(CHK_SOURCES);\
  	else exit 1; fi
  .PHONY: check-syntax

Lluís

If your build directory is in a different location from your project directory, you’ll need to tell flymake where to find your Makefiles. I use this:

(defadvice flymake-find-buildfile
  (around advice-find-makefile-separate-obj-dir
	  activate compile)
  "Look for buildfile in a separate build directory"
  (let* ((source-dir (ad-get-arg 1))
	 (bld-dir (ac-build-dir source-dir)))
    (ad-set-arg 1 bld-dir)
    ad-do-it))

(defun ac-find-configure (source-dir)
  (locate-dominating-file source-dir "configure"))

(defvar project-build-root nil
  "top build directory of the project")

(defun ac-build-dir (source-dir)
  "find the build directory for the given source directory"
  (condition-case nil
      (let* ((topdir (ac-find-configure source-dir))
	     (subdir (file-relative-name (file-name-directory source-dir) topdir))
	     (blddir (concat (file-name-as-directory project-build-root) subdir)))
	blddir)
    (error source-dir)))

and set project-build-root in my top-level source directory’s .dir-locals.el

-brendan

SCons/bjam

Can Flymake work if SCons/bjam is used instead of make? – Tennis

By providing a makefile which invokes SCons/bjam. Not perfect but a viable alternative until Flymake has more configuration options

Here is how I customized flymake to compile with scons :

	(defun flymake-get-make-cmdline (source base-dir)
	  (string-match "src/\\(.*\\)\\." source)
	  (list "scons"
	    (list "-u" 
	          (concat "#obj/" 
	                  (match-string 1 source)
	                  ".o"))))

This is the case if you put VariantDir(obj,src) in your SConstruct.

– Ounim

CMake

Using flymake for CMake is not difficult, the trick is to generate Makefiles using information provided by cmake. This page contains explanation and scripts to do that. It is possible the provided scripts would work immediately for your CMake project, if not you will surely get the idea.

– Nil Geisweiller

Nil’s scripts didn’t work for me out of the box, so I’ve modified them to generate the correct Makefiles. You can find my modified scripts on GitHub.

SeanFisk

Please use cpputils-cmake. It is a pure Elisp plugin actively maintained since year 2012.

– Chen Bin

There’s another trick. Right before loading flymake mode (M-x flymake-mode), open ielm (M-x ielm) and add the following line

(defun flymake-simple-make-init () (list “make” (list “-C” MY_CMAKE_BUILD_DIR)))

where MY_CMAKE_BUILD_DIR is the root of the build directory of your project. For faster flymake you can even take the build dir corresponding to the file. Note that with that trick you need to save your file to activate flymake (it actually gets activated anyway when you type but on the old unsaved file, so the errors aren’t reported in your buffer).

I think having to save the file is acceptable, besides it provides an advantage, what you compile for flymake is not wasted, basically when you are done with your coding, chances are that you code is already compiled.

An improvement of that would be to write a elisp function that look for the right build dir automatically.

– Nil Geisweiller

I’ve made a CMake minor-mode, cmake-project, that fixes up Flymake to support builds via CMake. If anything doesn’t work as it should or there are features you would like, please report a new issue.

AlexanderLamaison

Mozart/Oz

Here are instructions how to make flymake work with Mozart/Oz: http://code.google.com/p/oz-code/downloads/list

WolfgangMeyer

XSL-Mode

Use Flymake’s XML syntax-checking on files with a .xsl extension.

    (require 'flymake)
    (push '(".+\\.xsl$" flymake-xml-init) flymake-allowed-file-name-masks)
    (add-hook 'xsl-mode-hook
	      (lambda () (flymake-mode t)))

JavaScript with Google Closure

1. Download the Google Closure compiler and unzip (http://dl.google.com/closure-compiler/compiler-latest.zip). 2. Create a shell script to run closure on a file. I called mine “closure.sh”:

java -jar ~/bin/compiler.jar --warning_level VERBOSE --js $1 --js_output_file /dev/null

3. Add the following to your .emacs file (change closure.sh path to match your system):

(when (load "flymake" t)
  (defun flymake-closure-init ()
    (let* ((temp-file (flymake-init-create-temp-buffer-copy
		       'flymake-create-temp-inplace))
           (local-file (file-relative-name
                        temp-file
                        (file-name-directory buffer-file-name))))
      (list "~/bin/closure.sh" (list local-file))))
    
  (add-to-list 'flymake-allowed-file-name-masks
               '("\\.js\\'" flymake-closure-init)))

1. Don’t forget to start flymake mode by adding (flymake-mode t) to your javascript mode hook.

RFringe: Display the number and location of flymake errors/warnings on the fringe

See rfringe.el to display the buffer-relative positions of flymake errors and warnings on the fringe . This works with any language. Just add this to your .emacs:

    (require 'rfringe)
  

Example appearance:

http://i.imgur.com/34ceS.png

flymake-cursor.el : Display flymake messages in the minibuffer

FlymakeCursor automatically displays the flymake error for the current line in the minibuffer. The default flymake behavior is to display the message on mouse hover, so the FlymakeCursor thing is nice for keyboard jockeys and those who use nox / no-window. It works with any language. Just require it, and it works.

Example:

http://i.imgur.com/CK6kg.png

Note the highlights, and the error message for the current line, shown beneath the modeline.

More Tips and Questions

Wine build system

It works really well! You need some makefile magic though, this is what I used for the Wine build system:

check-syntax:
	$(MAKE) syntax-target SYNTAX="-fsyntax-only"

syntax-target: $(SOURCES:.c=.o)

-MikeHearn

In my simple project I use the following target in the Makefile:

.PHONY: check-syntax
check-syntax:
	$(CXX) -Wall -Wextra -pedantic -fsyntax-only $(CHK_SOURCES)

This works out-of-the-box with GNU Emacs 22.0.90.

Using temp dir

Does anybody know how to change flymake so that it sticks all of its junk files (*_flymake.*) in /tmp?

For example, you’re editing the source to a folder which you do not have write permissions on. Flymake breaks because it cannot save the _flymake file to the same directory as the source. Plus this leads to ugly _flymake files all over the place if it fails to delete them.

I use the trick documented in this blog to make temporary copies in my ~/.emacs.d/tmp dir, I’ve also integrated this tweak and others into a patched version of FlyMake available at https://github.com/illusori/emacs-flymake which may be easier to install. – SamGraham

I use the following hook so flymake can write temporary files, but if it can’t, it just doesn’t activate and gives a minor warning to the user.

(defun cwebber/safer-flymake-find-file-hook ()
  "Don't barf if we can't open this flymake file"
  (let ((flymake-filename
         (flymake-create-temp-inplace (buffer-file-name) "flymake")))
    (if (file-writable-p flymake-filename)
        (flymake-find-file-hook)
      (message
       (format
        "Couldn't enable flymake; permission denied on %s" flymake-filename)))))

(add-hook 'find-file-hook 'cwebber/safer-flymake-find-file-hook)

ChrisWebber

Newer flymake seems to have an option to store temporary files in a tempdir:

;; Nope, I want my copies in the system temp dir.
(setq flymake-run-in-place nil)
;; This lets me say where my temp dir is.
(setq temporary-file-directory "~/.emacs.d/tmp/")

Check https://github.com/flymake/emacs-flymake#use-the-system-temporary-directory-for-temp-files

Resource consumption?

What about resource consumption ? Does it eat all the CPU or RAM ? How Emacs is running when this is activated ? Except these questions, it really seems a killer-app 😊 – XavierMaillard

RAM use is negligible, CPU consumption in the current version can be excessive if you have several hundred buffers open in flymake-mode as it creates a timer for every buffer, I have a patched version at https://github.com/illusori/emacs-flymake that addresses this issue. – SamGraham

When is flymake run?

I’ve tried it (linux, stock emacs).. GREAT.. but.. I found that the buffer is only updated after I save the buffer, even if flymake is running gcc very often… is it normal?

No, it is supposed to run automatically – VagnJohansen
Re: “the buffer is only updated…” Yes, if you are speaking about saving the buffer to its backing file, it is normal. Flymake saves the buffer to a temp file, then compiles that. The real file that backs your edited buffer doesn’t get saved until you explicitly save it. – DinoChiesa

Underline errors instead of highlight

add this lines in .emacs

(custom-set-faces
 '(flymake-errline ((((class color)) (:underline "red"))))
 '(flymake-warnline ((((class color)) (:underline "yellow")))))

Using CEDET tools for unsupported modes

If you have a mode that flymake does not support (and you can’t/won’t add flymake support for it), then you can use lmcompile.el/linemark.el from the CEDET tools (CollectionOfEmacsDevelopmentEnvironmentTools) to at least get automatic highlighting after compiles.

Assuming that cedet is properly configured you can use

  (require 'lmcompile)
  (add-hook 'compilation-finish-functions 'vj-compilation-finish-highlight)
  (defun vj-compilation-finish-highlight (buffer result-str)
    (interactive)
    (lmcompile-do-highlight))

On my system the lmcompile-do-highligth call changes point to the last highlight entry (bug?). I had to use a delayed call:

(defun vj-compilation-finish-highlight (buffer result-str)
  (interactive)
  (run-at-time "1 sec" nil 'lmcompile-do-highlight))

VagnJohansen

Showing error messages in without a mouse

If you do not want to use mouse hover to check out the error messages, I’ve made a small modification that puts them in as overlays [1]. You may need to patch it a bit to get it to run though.

JorikBlaas

Jorik, you can use FlymakeCursor to address that. --DinoChiesa

Quickly show next err-menu

  ;; flymake
  (defun my-flymake-show-next-error()
    (interactive)
    (flymake-goto-next-error)
    (flymake-display-err-menu-for-current-line)
    )
  (local-set-key "\C-c\C-v" 'my-flymake-show-next-error)

Similarly, I like to have M-n and M-p move the point to the next and previous flymake error and then echo the error message at that point to the mini buffer. The following is a minor mode to achieve that. – MatthewKennedy

(defvar my-flymake-minor-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\M-p" 'flymake-goto-prev-error)
    (define-key map "\M-n" 'flymake-goto-next-error)
    map)
  "Keymap for my flymake minor mode.")

(defun my-flymake-err-at (pos)
  (let ((overlays (overlays-at pos)))
    (remove nil
            (mapcar (lambda (overlay)
                      (and (overlay-get overlay 'flymake-overlay)
                           (overlay-get overlay 'help-echo)))
                    overlays))))

(defun my-flymake-err-echo ()
  (message "%s" (mapconcat 'identity (my-flymake-err-at (point)) "\n")))

(defadvice flymake-goto-next-error (after display-message activate compile)
  (my-flymake-err-echo))

(defadvice flymake-goto-prev-error (after display-message activate compile)
  (my-flymake-err-echo))

(define-minor-mode my-flymake-minor-mode
  "Simple minor mode which adds some key bindings for moving to the next and previous errors.

Key bindings:

\\{my-flymake-minor-mode-map}"
  nil
  nil
  :keymap my-flymake-minor-mode-map)

;; Enable this keybinding (my-flymake-minor-mode) by default
;; Added by Hartmut 2011-07-05
(add-hook 'haskell-mode-hook 'my-flymake-minor-mode)

To use in console/tty emacs you could try the following:

    (defun next-flymake-error ()
      (interactive)
      (let ((err-buf nil))
        (condition-case err
            (setq err-buf (next-error-find-buffer))
          (error))
        (if err-buf
            (next-error)
            (progn
              (flymake-goto-next-error)
              (let ((err (get-char-property (point) 'help-echo)))
                (when err
                  (message err)))))))

I bind to C-` (for cperl only at the moment) which suits the way I work. If you don’t care about the whole next-error thing then something like:

    (flymake-goto-next-error)
    (let ((err (get-char-property (point) 'help-echo)))
      (when err
        (message err)))

might be all you need. – PhilJackson

Another solution worth mentioning made by Nafai can be found at [2]. From the comment to this code:

Additional functionality that makes flymake error messages appear
in the minibuffer when point is on a line containing a flymake
error. This saves having to mouse over the error, which is a
keyboard user’s annoyance

RichardRiley: The solution below was from Dave Love on gnu.emacs.help:-

 (defun my-flymake-show-help ()
   (when (get-char-property (point) 'flymake-overlay)
     (let ((help (get-char-property (point) 'help-echo)))
       (if help (message "%s" help)))))

 (add-hook 'post-command-hook 'my-flymake-show-help)

The above my-flymake-show-help will work, when you cursor very slowly. But let’s suppose you hold the arrow key continuously; what happens in that case is everything slows down. Scrolling goes very very slowly. See http://www.emacswiki.org/emacs/flymake-cursor.el

Something rather similar is used in nXhtml where (colored) flymake errors are shown in the echo area by default when point enters the flymake error marking. nXhtml also adds support for some of the above that are not part of Emacs 23 (like CSS, Javascript and an enhanced version for Java).

Has anyone got this to work with tramp (i.e. for remote files)? I’ve seen something on a mailing list (for example at http://groups.google.com/group/gnu.emacs.help/browse_thread/thread/dda14275ce2b8b02/d58b601f2b3be223) that says “In ‘flymake-start-syntax-check-process’ of flymake.el, ‘start-process’ is called. This does not work on remote hosts. Instead of, ‘start-file-process’ shall be used.” but there’s no indication a bug report was ever made (AFAICT), what version the problem occured in, or anything useful like that.

The version of FlyMake distributed with Emacs 23 can work with files over tramp but has a few bugs that might crop up resulting in the appending of “login messages” to the end of the buffer you’re editing. My fork of FlyMake at https://github.com/illusori/emacs-flymake patches this with more robust Tramp support. – SamGraham


CategoryModes CategoryProgrammerUtils