TopHome
<2023-05-15 Mon>techemacs

Compiling in Emacs

So, as with everything else, there are a number of ways to do a single thing - in this case compiling - in Emacs each with their own pros and cons.

For some reason, so far, I haven't moved the compiling/running portion of my development cycle into Emacs. But, I have many times run shell commands and processes from emacs using the likes of (async-)shell-command and (async-)start-process(-shell-command).

Now, there is the built-in M-x compile. Great! But what does it do differently from simply starting up (async) processes? What it does is interpret the output to extract filenames and line numbers to allow easy jumping to specific lines with warnings and errors.

If you actually try it out, you will quickly find out that it has a major flaw: it has no in-buffer markings that the kids are using these days. How will emacs compete with the editors of today?

Turns out, you need to actually use flycheck or flymake for this. They get you nice shiny ui bells. But, what is the difference between them? flymake is the in-built version which lacked at one point, but has now caught up in terms of features. If you go online, most users are today using flycheck because it comes out of the box with batteries and they already set it up to their liking. But, if you are starting out, maybe better to take the time out to configure flymake itself. Of course, in the Emacs way, you will have to put in some effort. https://github.com/mohkale/flymake-collection seems like a good place to start.

Now, with the entrance of LSP and Language Servers on the scene, things get even more muddied. In Emacs, you have to use one of lsp-mode or eglot as the frontend into LSP world. Now, they in turn may make use of fly(make|check) internally.

Now, all that circle done - let us come back to the humble compile. It gives the very basics - the simple, transparent, straightforward approach in comparison to all the heavyweights we just listed. You decided which approach is better.

Buried in this wonderful Mastering Emacs blog, there is something called compilation-shell-minor-mode that can be activated in comint buffers like shells. What this allows you to do is run your standard shell commands and then jump to the errors from this output.

Now, for both direct compile and shell routed compile, I saw that the mouse-clicks worked smoothly from the compilation output to the source buffer. The keybindings worked best when running direct compile - when the output is shown in a split window below the main buffer.

But, in both cases, the thing to note is that the warning output is what the system works around. So, if you arbitrarily move your cursor around and then try to jump to the next/previous entry, it moves froma reference of the compile output, not the source buffer. Initially, since I had fringe-mode off, I couldn't even see where I was. Turns out there is a small helpful marker highlighting the current warning/error.

With this structure, if you move your cursor around, go to the beginning/end of the buffer and try to go to the next/previous entry - the working is a bit non-intuitive. It almost feels like compile is from a time when you process entries one by one serially!

I think compile is a good place to start to build your own solution on top - better UI, better keybindings, faster moving around, displaying error underline in the minibuffer etc should all be easy to add with bits of elisp. Of course, it is possible that the fly* tools work exactly like that, I haven't checked their sources - but, there is something to be said about the philosophy of building your own things around strong fundamentals and avoiding opaque magic.

compile is one of those fundamentals because it is based on simple regex matching of outputs. It has no moving parts or hidden parts - it depends on outputs of commands that you can manually run. It is worth knowing and building upon. I look forward to shaping my own workflows on this base.

Addendum: in this post, we didn't go into the world of interactive execution or REPL based development. Emacs hackers would be familiar with executing snippets of elisp and the magic that is SLIME. But the support for ordinary REPL languages - the likes of Python - is extra-ordinary. You can send region/functions to a Python REPL using the basic in-built python-mode itself 1 or go to the other extreme have running code cells for a notebook like experience using things like https://github.com/astoff/code-cells.el.

Footnotes: