One of the convenient things I quite like about Sublime Text is the easy to
setup build system1. It is pretty easy to add a custom build
setup with Sublime Text, to compile a single C++17 source file, for example.
Once configured it is very efficient and keyboard friendly to compile and run a
C++ program with a single key press, F7
with default key bindings.
This blog post is about how to configure Emacs in a similar vein.
The use case I had in mind was to configure Emacs to compile and run single file
C++ programs without having to write a Makefile
. It is pretty easy to invoke
shell commands within Emacs, so if you have a build setup with make
and the
like, it is not difficult to to build and run programs within Emacs. However,
what I wanted was to build and run one off C++ source files.
Compile Command
Emacs compile command to the rescue2!
Default compile command for C/C++ mode is make -k
, which is not what I want
in this case. Compile command can be customised on a per-mode basis.
Following is the compile command I configured for compiling one off C++ source files. This command builds and runs C++ source files based on the current buffer name. For our purposes, buffer name is equivalent to the file name of the C++ source file.
(add-hook 'c++-mode-hook
(lambda ()
(set (make-local-variable 'compile-command)
(format "g++ -std=c++17 -Wall %s -o a.out && ./a.out" (shell-quote-argument (buffer-name))))))
- We are supplying the file name which can be found out from
buffer-name
elisp function as the input file parameter for g++ compiler. Note that this command will work on macOS as well. - We need to quote the file name to be run as a shell command, which is what the
shell-quote-argument
does.
Once setup up, to compile the current source file you are editing can be
accomplished by invoking compile
command in Emacs (M-x compile
).
Since the compile command is differentiated based on the mode it is bound to, you can have custom compilation commands for different programming languages.
Per-file (or per-directory) customisation
Pretty cool thing about the compile-command
is that it can be set and
customised on a per-file basis, using Emacs file variables3.
These variables are set when visiting a file, or when setting the major of a buffer, and
makes them local to the buffer.
Following is an example local variable specification on a C++ file, customising
the executable name, C++ version, etc. Make sure to quote compile command as a
string. Emacs makes it pretty easy to add them as well - use
make-local-variable
4 command and Emacs will insert the
right type of commented variable declaration automatically!
// Local Variables:
// compile-command: "g++ -std=c++11 -Wall hello-world.cpp -o hello && ./hello"
// End:
Similar customisations can be applied on a directory basis with .dir-local.el
files5. With directory local variables, you can set the compile
command on a project basis, instead of relying on the global configuration as
shown with the add-hook
method, or having to specify on a per-file basis as
shown in the example above.
As can be seen from above examples, Emacs offers a couple of ways to customise builds. Emacs’ malleability reminds me of the following classic xkcd6!