Build Systems in Vim: make

If you use a dedicated IDE designed for a specific language or platform, you probably have some built-in shortcuts for compiling, building, running your project. But if you’re using a more general-use editor such as Vim, or even Sublime Text, Atom, VS Code, etc., you’ll need to set that kind of thing up yourself. This article shares some ideas on how to do that within Vim.

As you know, in Vim, it’s super easy to set up pretty much any key combination to take pretty much any action. So creating a simple launcher is really easy. Say you have a JavaScript based project that has a package.json script called build. This does all the babel stuff or webpack stuff or whatever else you’re using to compile your project.

Remember that :! will allow you to run any system command from within Vim. So calling out to npm is really easy:

1
:!npm run build

It’s easy to set this up as a mapped shortcut. Just choose your favorite function (or other) key and say:

1
nnoremap <F5> :!npm run build<CR>

That will work beautifully. The problem is, you’re putting something very project-specific in your global Vim configuration. If that’s the only project you ever work on, or all your projects are set up the same way, maybe that works for you. But what if you have a Ruby project, or Python project, or C or Java or even another JavaScript project that doesn’t have an npm script named build? You could start setting up other function keys to build different types of projects, but that can get a bit crazy.

My ideal scenario would be to have F5 as the global key that can build any project. So we need to have F5 do something generic, and put something into the project that knows the specific steps to take to build that specific project.

One solution could be a shell script. Make a file called build.sh or something, that looks like this:

1
2
#! /bin/bash
npm run build

Then chmod +x it to make it executable. That’s assuming you’re using bash and that’s your path to bash. Adjust as needed. Then set up your build key:

1
nnoremap <F5> :!./build.sh<CR>

Now, for every project you want to be able to build with F5, you just create a build.sh script with the right commands to do the build, and make it executable. Maybe the other scripts will run gcc or javac or a gulp or grunt file. Or who knows what else. All told, this solution is not too bad.

But another, probably better way is to use the program, make. make is a program that is designed to run custom build scripts. It has built-in integration with Vim, so it’s really easy to launch from within your project.

make may be already installed on your system. Run make -v in the terminal to check. If not, you can install it quite easily with apt or homebrew or whatever package manager your system has. I guarantee it’s there.

Now you set up your launch key:

1
nnoremap <F5> :make<CR>

Note that Vim already knows about make internally, so you don’t have to say :!make. Just :make will do.

When you run make, it looks for a file called makefile in the current directory, and if so, executes the commands within it. Makefiles have a specific format and can allow for very complex, multi-part build scenarios. It was really designed for C programs where you might need to compile a bunch of different files into separate “.o” files and then link them together. Maybe even run a preprocessor on them, link other external libraries, etc. You can set up different targets for each phase of the build, and each target can have dependencies, which can kick off other targets, etc. You can read all about it here.

But we can start off pretty simple here. For our npm example, our makefile would have a single default target and look like this:

1
2
default:
npm run build

No need to make it executable or anything. And if you have a Java project it might look like:

1
2
default:
javac main.java

Or something like that. You get the idea. You can also set up other targets like so:

1
2
3
4
5
default:
npm run server

clean:
rm -rf build

You can pass a target name into make, so you can set up a clean key like so:

1
nnoremap <F6> :make clean<CR>

Another cool thing about Vim’s make integration is that it doesn’t even have to use make. Say you’re super old school and you love Apache Ant. In your Vim config, say:

1
set makeprg=ant

… or however you launch ant on your system. It’s been so long, I forget. Anyway, now running :make will instead launch ant and run your ant build file.