emacshaxeflymake

Flymake specify location of Makefile


I'm trying to feed flymake output from Haxe compiler, but I don't know how to tell it where the make file lives (ideally, I'd use nxml file instead). So far I have this in the Makefile:

BIN = ./bin
MAIN = com.wunderwafer.Main
SWF = wunderwafer.swf
SWFSETTINGS = -debug -swf-version 10 -swf-header 800:600:31
HFLAGS = -main $(MAIN) $(SWFSETTINGS) -cp ./src -swf $(BIN)/$(SWF)
HC = haxe

default: compile

compile: $(HC) $(HFLAGS)

clean:
    $(RM) -r $(BIN)/*

.PHONY: check-syntax

check-syntax:
    $(HC) $(HFLAGS)

If I run it later like so:

$ make -k check-syntax

It produces the expected output. However flymake isn't able to find the Makefile (or so it seems) because the files I'm trying to check are deeper inside the src directory.

What is the way to configure flymake so it knows where the makefile is? (or, even better, just execute a shell command, because the common way to compile Haxe code is by using *.nxml settings file.

EDIT:

It looks like I'm getting closer, lots of thanks, but flymake is doing something strange, and I can't understand what exactly it does, so, here's the log:

received 65 byte(s) of output from process 967
file /home/wvxvw/projects/wafer/src/com/wunderwafer/map/Battlefield.hx, init=haxe-flymake-init
parsed 'Error : Invalid class name /home/wvxvw/projects/wafer/build.nxml', no line-err-info
file /home/wvxvw/projects/wafer/src/com/wunderwafer/map/Battlefield.hx, init=haxe-flymake-init
process 967 exited with code 1
cleaning up using haxe-flymake-cleanup
deleted file /tmp/flymake-Battlefield-855Cad.hx
Battlefield.hx: 0 error(s), 0 warning(s) in 0.15 second(s)
switched OFF Flymake mode for buffer Battlefield.hx due to fatal status CFGERR, warning Configuration error has occurred while running (haxe /home/wvxvw/projects/wafer/build.nxml)

The command I'm trying to make it run looks like this:

(defun haxe-flymake-get-cmdline (source base-dir)
  "Gets the cmd line for running a flymake session in a Haxe buffer.
This gets called by flymake itself. The output is a list of two elements:
the command to run, and a list of arguments.  The resulting command is like:

  $ haxe ${project-root}/build.nxml

"
  (message "base-dir %s" (file-name-as-directory base-dir))
  (list *haxe-compiler*
        (list
     (concat (file-name-as-directory base-dir)
         *build-nxml*))))

The message printed looks like this:

base-dir /home/wvxvw/projects/wafer/

So, as far as I could understand, the resulting command should be:

haxe /home/wvxvw/projects/wafer/build.nxml

But it looks like flymake either adds something in front of the argument or afterwards, which makes Haxe compiler generate the error "Error : Invalid class name" - this error would be given if there was one extra argument, which the compiler would have understood as an extra class to compile. But the log doesn't show what is being sent...

EDIT 2:

I've added:

#!/usr/bin/env bash

echo "$@" > /home/wvxvw/projects/wafer/log

And made flymake invoke this script instead of the compiler, and it passes only one argument, just as I would expect it... sigh


Solution

  • It's a good question. I don't know a simple way of adding in a new "flavor" of make tool into flymake. I know of a way, it's just not simple. This is what I did for php codesniffer - it will be similar for any arbitrary make tool.

    First, define an install fn.

    (defun fly/phpcs-install ()
      "install flymake stuff for PHP CodeSniffer files."
      (add-to-list
       'flymake-err-line-patterns
       (list fly/phpcs-error-pattern 1 2 3 4))
    
      (let* ((key "\\.php\\'")
             (phpentry (assoc key flymake-allowed-file-name-masks)))
        (if phpentry
            (setcdr phpentry '(fly/phpcs-init fly/phpcs-cleanup))
          (add-to-list
           'flymake-allowed-file-name-masks
           (list key 'fly/phpcs-init 'fly/phpcs-cleanup)))))
    

    This installs a new entry into the flymake alist, keyed on .php as a file extension. The entry in flymake's list basically relates the file extension to a pair of functions, one for init and one for cleanup.

    The init fn simply returns the command to run to check syntax. This can be a shell command, with the appropriate arguments. For codesniffer this fn looks like this:

    (defun fly/phpcs-init ()
      "initialize flymake for PHP using the PHP CodeSniffer tool."
      (let ((create-temp-f 'fly/phpcs-create-temp-intemp)
            (use-relative-base-dir t)
            (use-relative-source t)
            (get-cmdline-f 'fly/phpcs-get-cmdline)
            args
            temp-source-file-name)
        (setq temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)
              args (flymake-get-syntax-check-program-args
                    temp-source-file-name "."
                    use-relative-base-dir use-relative-source
                    get-cmdline-f))
        args))
    

    Yikes! Down the rabbit hole we go. The get-cmdline fn looks like this:

    (defun fly/phpcs-get-cmdline (source base-dir)
      "Gets the cmd line for running a flymake session in a PHP buffer.
    This gets called by flymake itself. The output is a list of two elements:
    the command to run, and a list of arguments.  The resulting command is like:
    
      php.exe -d auto_append_file="" -d auto_prepend_file="" phpcs\scripts\phpcs --report=emacs file.php
    
    "
      (list fly/phpcs-phpexe
            (list
             "-d" "auto_append_file=''"
             "-d" "auto_prepend_file=''"
             (concat (file-name-as-directory fly/phpcs-phpcs-dir)
                     "scripts\\phpcs")
             (concat "--standard="  fly/phpcs-standard)
             "--report=emacs"
             "-s" ;; show the fullname of the rule being violated
             (expand-file-name source))))
    

    You can see the full elisp at http://www.emacswiki.org/emacs/flyphpcs.el

    There's probably a simpler way. I just don't know it.