Skip to content

Compiling and running scripts in Emacs

by mickey on May 29th, 2012

I’ve talked about running shells and executing shell commands in Emacs before, but that’s mostly used for ad hoc commands or spelunking; what if you want to compile or run your scripts, code or unit tests?

There’s a command for that…

Not surprisingly, Emacs has its own compilation feature, complete with an error message parser that adds syntax highlighting and “go to next/prev error” so you can walk up and down a traceback in Python, or jump to a syntax error, warning or hint in GCC.

There are two ways of using the compilation feature in Emacs: the easiest is invoking M-x compile followed by the compile command you want Emacs to run. So, for Python, you can type M-x compile RET python myfile.py RET and a new *compilation* buffer will appear with the output of the command. Emacs will parse the output and look for certain patterns — stored in the variables compilation-error-regexp-alist[-alist] — and then highlight the output in the compilation buffer with “hyperlinks” that jump to the file and line (and column, if the tool outputs it) where the error occurred.

One annoying thing about compile is its insistence on wanting to save every. single. unsaved buffer before continuing. It’s there to keep you from accidentally compiling a mix of newly saved and old, stale files, which would lead to unexpected behavior, and the only reason it’s still there — and why it insists on saving files unrelated to what you are compiling — is the complete lack of a proper, integrated project management suite in Emacs. But I’ll save that rant for later.

Anyway, if it offends you as much as it offends me, you can add this to your emacs file to shut it up:

There is nothing stopping you from customizing compilation-save-buffers-predicate to take into account the files or directories so its save mechanism is cleverer, but I personally never bothered.

If compilation is successful — and like most things in the UNIX world, this is governed by the exit code — the modeline and compilation buffer will say so; likewise, if an error occurred, this is also displayed.

You can jump to the next or previous error ([next/previous]-error) with M-g M-n and M-g M-p — they’re bound to more keys, but I think those are the easiest ones to use. Similarly, in the compilation buffer itself (only), you can go to the next/previous file (compilation-[next/previous]-file) with M-g M-} and M-g M-{, respectively, and RET jumps to the location of the error point is on.

There is an undocumented convention in Emacs that commands like dired, grep, and compile can be rerun, reverted or redisplayed by typing g in the buffer.

By default the compilation buffer is just a dumb display and you cannot communicate with the background process. If you pass the universal argument (C-u) you can; the buffer is switched to comint mode, and you can converse with the process as though you were running it in the shell.

Python Debugging with Compile

I work mostly in Python, and quite often I have to debug the script I am writing with pdb, the Python debugger. I use breakpoints a lot, and I have a command bound to F5 that imports pdb and calls pdb.set_trace() — a standard Python debugging idiom. What it also does is highlight the line in bright red so I don’t miss it. And if I call compile from a Python buffer, it checks if there is a breakpoint present in the file: if there is, it switches to the interactive comint mode automagically; if there isn’t, it defaults to the “dumb” display mode. Having it switch automagically is perhaps a slightly pointless flourish, but screw it I’m using Emacs, not vim :)

This is the code I use. Feel free to adapt it for other languages. Send me an e-mail if you do something neat with it.

There’s a Minor Mode for that…

The compile workflow isn’t for everyone; some people want everything in one place: their shell. Well, good news then — you can have your cake and eat it. The minor mode M-x compilation-shell-minor-mode is designed for comint buffers of all sizes and works well with M-x shell and most modes that use comint. You get the same benefits offered by compile without altering your workflow. If you compile or run interpreted stuff in your Emacs shell you’ll feel like a modern-day Prometheus with this minor mode enabled!

Add this to your emacs file and the compilation minor mode will start when shell does.

7 Comments
  1. felix permalink

    Thanks for yet another great post :)

    Quick question: Is there a binding I’m missing to `recompile’ in a compilation buffer that was started with comint mode?

    • In the compile buffer you can hit “g” and it will recompile it for you.

      There are modes as well for running both py.test and nose in a compile buffer. I ported the nose support to py.test. The code is in marmelade and on bitbucket (http://bitbucket.org/elarson/pytest.el)

      As an aside, I also use compile mode for tailing files so I don’t have to start up another shell-mode buffer.

      • mickey permalink

        Have you tried auto-revert-tail-mode ?

      • felix permalink

        Right, that’s what I’m used to, but when in comint mode, this isn’t as easy ;)

  2. Anonymous permalink

    Great tutorial.

    I just want to mention that instead of going to the compilation buffer and pressing

    to recompile it, you can also use

    that will rerun the last command used by

    .

    The advantage of

    is that it works on any buffer (you don’t need to jump over to the compilation buffer) and it also works if you have deleted your compilation buffer.

  3. I recommend quickrun.el for such case. quickrun.el is a extension to execute editing buffer. You can execute
    only M-x quickrun.

    quickrun.el execute not only script languages(Perl, Ruby, Python etc), but also compiling languages(C, C++, Go, Java etc)

    Please see my repository

    https://github.com/syohex/emacs-quickrun

    Thanks

  4. Sue D. Nymme permalink

    I have bound “compile” to M-g c, and “recompile” to M-g r. It totally simplifies everything!

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS