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. Flymake is part of Emacs 23 and some of the tips below works out-of-the-box there.

Unfortunately, this project is outdated and last change was 3 years ago.

For a modern alternative, check out Flycheck

Currently new and improved version of Flymake is maintained by Sam Graham and available on github:

More info here:

From its home page:

“Flymake is implemented as an Emacs minor mode. It runs the syntax check tool in the background, passing it a temporary copy of the current buffer, and parses the output for known error/warning message patterns. Flymake then highlights erroneous lines (that is, lines for which at least one error or warning has been reported), and displays an overall buffer status in the mode line.”

Flymake’s author is PavelKobiakov?

Language Support

PHP
FlymakePhp for PHP
Ruby
FlymakeRuby for Ruby
Fortran G95
Flymake Fortran G95
Javascript
FlymakeJavaScript for JavaScript
Actionscript 3
FlymakeActionscriptThree for Actionscript 3, more than just syntax checking; full incremental compilation
Haskell
FlymakeHaskell for Haskell
Erlang
FlymakeErlang for Erlang
Lua
FlymakeLua for Lua
Shell
FlymakeShell for *nix shell programming (Bash)
Elisp
FlymakeElisp for EmacsLisp
CSS
FlymakeCSS for Cascading Style Sheets
Java
FlymakeJava with Make or JDEE
C#
FlymakeCsharp for C#
VB.NET
included in VbDotNetMode
Python
See PythonMode
D
FlyMakeD for the D programming language.
FlymakeTex
TeX and LaTeX
FlymakeHtml
HTML markup

Hints And Questions

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

SeanFisk’s script has some problem because relative path issue. I re-wrote it in python at HERE. It should work out of the box now.

– Chen Bin

I re-write pycmake-flymake in elisp. It’s called cpputils-cmake now and released at Marmalade as package which you can install through Emacs’ own package manager. Here is its github site with documentation and sample configuration. CMake is powerful and Flymake is cool. Why not let this couple and my elisp code do everything automatically for you?! For lazy programmers only, minimum configuration (you just need copy my sample configuration code).

– 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

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