I am trying to come up with a way to handle C++ projects with Vim. I have sorted out syntax and code completion etc. to some extend. Now, I am curios to hear about how people handle their Build > Make > Run cycles for their projects.

This is what I have so far:

1) For the build stage I use CMake. I am invoking CMake either from a terminal open just under my Vim window or through Vim using the vim-dispatch plugin.

By doing something like this:

:Dispatch 'cd {my_project_dir}; rm -rf ./build/*; cd ./build; cmake ..'

This runs cmake and prepares the make files.

2) For the make stage, I am setting the makeprg option of Vim for my current project and I am executing it with vim-dispatch using the :Make wrapper.

It looks like that:

makeprg=cd {my_project_dir}/build && make

This compiles the code.

3) The final stage is running the compiled binary. For that I am using vim-dispatch as well. The run call looks like that:

:Dispatch {my_project_dir}/build/bin/myproject

All these stages seem to be working ok, what I am missing is an error check between those. Ideally, I would like to stop at stage (2) and not run the binary (which would be outdated) if the make stage fails.

What would be the best way to solve this problem? Is there some kind of an access to the exit codes for each of these stages?

  • I'm not sure if this will help, but after running my c++ binary I delete it, something like this ./binary && rm binary
    – fYre
    May 14, 2016 at 23:30
  • 2
    Why not just do :!make && /path/to/exe? That seems to be working fine for me.
    – DJMcMayhem
    May 14, 2016 at 23:40
  • You could check, after step 2, if the call to getqflist() returns an empty list, or not (you could even parse the list to see if there are errors in it - useful if you expect to have warnings).
    – VanLaser
    May 15, 2016 at 16:40

2 Answers 2


TL;DR try the asyncrun.vim plugin, it will allow you run shell commands in background and read output from quickfix window in realtime.

You can define shell scripts in your dotfiles repository and execute the script with F3:

nnoremap <F3> :AsyncRun -cwd=<root> sh /path/to/your/dotfiles/script/build_advanced.sh <cr>

The following shell environment variables are defined by AsyncRun:

$VIM_FILEPATH  - File name of current buffer with full path
$VIM_FILENAME  - File name of current buffer without path
$VIM_FILEDIR   - Full path of current buffer without the file name
$VIM_FILEEXT   - File extension of current buffer
$VIM_FILENOEXT - File name of current buffer without path and extension
$VIM_CWD       - Current directory
$VIM_RELDIR    - File path relativize to current directory
$VIM_RELNAME   - File name relativize to current directory 
$VIM_ROOT      - Project root directory
$VIM_CWORD     - Current word under cursor
$VIM_CFILE     - Current filename under cursor
$VIM_GUI       - Is running under gui ?
$VIM_VERSION   - Value of v:version
$VIM_COLUMNS   - How many columns in vim's screen
$VIM_LINES     - How many lines in vim's screen
$VIM_SVRNAME   - Value of v:servername for +clientserver usage

All the above environment variables can be used in your build_advanced.sh. By using these environment variables, the script can call the cmake and then make if cmake finished successfully.

See How do I compile a program (C++ or Java) in Vim, like Sublime Text (Ctrl+B)?

  • Yes. I have been exploring those options. I think task runners like gulp are good as well. I am playing around with different options. One of them is definitely asyncrun. Thanks.
    – mbilyanov
    May 1, 2018 at 10:24

I can't tell about the first step as I'm not using Dispatch, and my CMake integration is different. As this isn't something we do that often, this isn't an important issue -- Normally, this isn't required more than once per project and per build type to initialise a build configuration ; I know, sometimes we add variables and need to run (c)cmake again ; IMO this is best manually done in the console, or in nightly builds/CI)

Regarding the second step. Unfortunately, knowing when there is a compilation error isn't that trivial. In BuildToolWrappers, I use the following code, stolen from LaTeX-Suite:

" --- The following code is borrowed from LaTeXSuite
" close the quickfix window before trying to open it again, otherwise
" whether or not we end up in the quickfix window after the :cwindow
" command is not fixed.
let winnum = winnr()
 " if we moved to a different window, then it means we had some errors.
if winnum != winnr()

(actually, my code is a little bit complex than that)

Unfortunately, it's still far from perfection, for instance, it's doesn't detect link errors correctly.

Note, that Dispatch seems to be injecting completion information (see dispatch#complete). May be it hides somewhere what you are looking for.

  • Hi Luc, thanks for the information. That BTW framework seems to be quite extensive. I might give it a try.
    – mbilyanov
    May 17, 2016 at 16:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.