I want to be able to compile c++ code from within vim without running a new terminal and calling the compiler. **How can I do it ** please
(I've answered this question so many times that I've lost the count, and impossible to find a complete answer in the lot... I'll bookmark this answer this time...)
Everything starts with Vim quickfix feature which permits to integrate compilation, and to navigate error messages. The starting point is
:make. To navigate error messages, you'll need ,
:cclose... In short, read documentation about Vim
:h quickfix feature.
:!g++ whatever, or
:!make sometarget, instead of
:make sometarget (without the bang
!) is what we used to do 20ish years ago with vi -- we had no choice at the time. Vim integrates call to compilation chains. Let's take advantage of it (in particular in C++ where we can have an extremely long compiler output when templates are involved or when no matching
operator<< is found)
Now. There are several use cases:
1. Mono-file projects, everywhere but on MinGW
This is the main use case for users doing competitive programming.
TL;DR: To compile
foo.cpp, (or even
foo.f95...) we just need to type
:make %<. And... that's all!.
No need to write a
Makefile, nor to tweak
'makeprg' option. Thanks to gnumake default configuration, there is nothing more to do.
Actually, a little bit more is required to pass options. It can be done separately through the main following gnumake options:
$CXXcompiler for C, or C++ (respectively)
$FFLAGSflags used to compile C, C++ and Fortran programs
$LDFLAGSflags to pass to the linker
$LDLIBSlibraries to link the executable with
:let $CXX = 'clang++' :let $CXXFLAGS = '-std=c++17 -O2 -Wall -Wextra -Ipath/to/my/boost/include` :let $LDFLAGS = '-Lpath/to/my/boost/lib' :let $LDLIBS = '-lboost_datetime'
Everything is with the expectation current working directory is the one where the current file is stored. Some minor tweaking may be required otherwise.
These variables could also be exported in our shell, where we could compile with
Actually, everything I've just said works in the console as well, and that's what this Vim solution relies upon to work. For instance:
CXX='clang++' CXXFLAGS='-std=c++17 -Wall -Wextra -g -fno-omit-frame-pointer -fsanitize=address,undefined' make foo
PkgConfigplugin can automatically set these variables from the pkg config files present on our system. It's in two parts: the autoload plugin, the plugin, and the library plugin it depends upon.
Some other non gnu-systems may not support this solution either.
I have hinted it: any language for which gnumake has default implicit variables and implicit rules is supported with this approach. I'm using it for C and C++, IIRC I've also used it for Fortran but I'm not sure, and it seems that Pascal compilers compatible with
pcare supported as well (let me know if you have more info).
" (with the expectation current working directory is the one where the file is stored) " " either :!./%< " or (which is not compatible with redirections with non-neo Vim at this time) :term ./%<
Need for mappings?
" Compile nnoremap <silent> <F7> :<c-u>make %<<cr> " Execute nnoremap <silent> <c-f5> :<c-u>term ./%<<cr>
Chain compilation with execution
This one is a little bit more complex. We can trick Vim with
:make %< && ./%< which will also send the execution results into the quickfix window. I've never tested it with interactive programs (i.e. that read from
For a better integrated solution, a little bit of vim scripting is required. See this related answer on SO: https://stackoverflow.com/a/56991040/15934
2. Mono-file projects, on MinGW
Sorry the previous solution won't work with MinGW. The problem is that gnumake default configuration isn't shipped with MinGW packets.
Unless we patch gnumake configuration, we have to set
'makeprg'. A typical setting is
" To compile the current file: " Define the following once :let &makeprg = 'g++ -Wall -Wextra -std=c++17 % -o %<.exe' " Then compile with :make " Or to compile the specified target -- '$*' has a special meaning for :make :let &makeprg = 'g++ -Wall -Wextra -std=c++17 $* -o $*.exe' :make foo " foo.cpp -> foo :make %< " current
Note: This solution would also work elsewhere. Yet, I wouldn't bother to change
'makeprg' if I can avoid it. As we would have to play with ftplugins/autocommands if we want to have a
'makeprg' for C and another for C++. i.e. if we want to work with mono-file projects in C and in C++.
Of course, with other programming languages we will have to set (locally!) this option, with
:compiler command typically. BTW, to use VisualStudio/MSDev compiler,
'makeprg' (and the error format:
'errorformat') can be configured with
3. Multi-file projects
In this use case we usually have a
Makefile (traditional solution), in which case we have to type
:make target as we would have type
make target in the console.
When there is a
Makefile, it takes the priority over gnumake default settings (i.e. solution 1), as it does in the console.
4. CMake based projects
More is required. At least
:let &l:makeprg = 'cd buildir && make $*' -- this shouldn't be set in buffers that don't belong to the project...
I'm maintaining a plugin, build-tools-wrapper that tries to autodetect the out-of-source build directory -- which is typical of CMake -- with various heuristics. It even permits to swap the build dir -- the idea is to model build modes (debug, release, release with debug info, sanitized...)
:make, the compilation is modal: it blocks vim user interface until it's finished. On mono-file projects this is not a problem, on real projects it can quickly become really annoying.
Since the late versions of Vim7.4-2xxx, we can finally compile in background an see the quickfix window being populated with messages as the compilation is going on. Alas, there is no standard/vanilla command in Vim to do that. It has to be done through vim scripting.
In other words, background compilation requires the support of plugins. Several exist. Again there is my build-tools-wrapper plugin. There is also AsynchRun (IIRC) and many more.
Vim is a text editor, not a shell. Although, Vim 8.1 has a built-in terminal that can be opened with the
:term command. It would look something like this:
To exit, you can use
exit command to quit from the integrated shell.
There's an alternative way and probably it's what you're looking for. You need to hit Esc and type the following:
! g++ -std=c++14 -o hello hello.cpp && ./hello
The output will be:
If you use Makefiles, you can just call
:make from inside vim. If not, the behavior of the
:make can be customized by setting
You can also customize the way the output is interpreted in case there are errors, e.g., to Automatically open quickfix window on make. The entire system is fairly flexible, although in some cases creating a custom key-binding to make a call via the shell (using
:!<cmd>) is easier. You can always go back to the output using
CTRL-Z and return to vim using