I’m gonna show you how to get a nice and modern C++ setup for VIM. I’ll talk about my setup in specific, which is OS X based, and should be similar in *nix platforms, and more or less in Windows.
The tools
- Command Line Tools for Xcode
- Git
- Clang built from sources
- libc++ built from sources (optional)
- PCKeyboardHack
- MacVim, plus:
- vim pathogen
- vimprj, from official mercurial repository
- NERD tree
- Command-T
- clang_complete, from my fork.
- SingleCompile
- UltiSnips
- SuperTab
- Auto Pairs
- Cpp11-Syntax-Support
- cSyntaxAfter
Results
While building my environment I didn’t stop where the tools didn’t work properly, I fixed them, or searched for help, and learned a lot. In the end I learned Python and VimScript, languages I never touched before, and I liked.
Let’s review those tools, one by one:
Command Line Tools for Xcode
This will install initial precompiled tools, like compilers, libraries,
and also header files, so that you are able to compile Clang.
You can just download Xcode from App Store for free and then install it
from Preferences > Downloads > Components, or you can just install it
from the OS X Leopard installation media. For Lion and Mountain Lion users,
you can get the tools from https://developer.apple.com/downloads,
this requires registration to get the download links. As of august 2012,
the direct links are the following:
- OS X Lion Command Line Tools for Xcode, august 2012
- OS X Mountain Lion Command Line Tools for Xcode, august 2012
Git
A modern VIM configuration needs to take advantage of Git, a great amount of plugins lives on GitHub now. Adding a plugin to your installation, that gets persisted on the web, is just a matter of cloning a plugin repository, or even better, turning it into a submodule of your main VIM repository. Managing plugins is managing modules, updating your installation and all plugins at once is just a git command! vim pathogen will help maintaining everything organized. I’ll talk about that later.
Clang
First, take a look at this:
A comparison of C++11 language support in VS2012, GCC 4.7 and Clang 3.1.
So, do you want to really feel how it is to program in C++11? Use Clang! forget the rest.
Clang not only does the job of compiling, it provides compiler services,
like syntax checking and completion, and that’s also why I use it, it’ll
do the job of C++11 completion for VIM with a little help from the
clang_complete plugin.
One thing you need to do is to compile it from sources, directly from trunk.
The official repository is SVN, but there’s an official Git mirror.
You must build it from sources because I got involved
in some annoying completion bugs, which are currently fixed on trunk!
I’m using /usr/local to save and install projects I compile from sources.
As stated in the homebrew FAQ:
Apple has conformed to POSIX and left this directory for us. Which means there is no /usr/local directory by default, so there is no need to worry about messing up existing tools.
I save project’s sources at /usr/local/src. For example, I cloned LLVM
sources to /usr/local/src/llvm. When installing, I install them to
/usr/local.
There’re two things that must be done in OS X to make such a setup work well:
- edit
/etc/pathsand put/usr/local/binat the top, this will make tools installed at/usr/local/bintake precedence over others. This is specially needed for Clang, because your system will contain other installation at/usr/bin. -
your permissions may be messed up at
/usr/local. There’s no need for sudo install in this directory, so to keep things clean, I recursively changed owner and group (group to admin as in homebrew):sudo chown -R francisco:admin /usr/localLook that
franciscois my user, you should put your own.
I then cloned the git mirrors for LLVM and Clang to /usr/local/src with:
git clone http://llvm.org/git/llvm.git /usr/local/src/llvm
git clone http://llvm.org/git/clang.git /usr/local/src/llvm/tools/clang
and built and installed everything by:
mkdir /usr/local/src/llvm/build
cd /usr/local/src/llvm/build
../configure --enable-optimized --disable-assertions --enable-targets=host-only
make -j`getconf _NPROCESSORS_ONLN` install
LLVM’s configure script will install at /usr/local by default, so no need to set --prefix.
From here on, I compile everything with this compiler, not the one at /usr/bin.
libc++
libc++ is the new LLVM’s C++ standard library implementation. I’ve chosen to use it,
but you are not obligated to do the same. I even build MacVim with it.
I’ve followed the documentation for installation, the steps
are simple, and you can also clone from a git mirror instead of the default SVN:
git clone http://llvm.org/git/libcxx.git /usr/local/src/llvm/tools/libcxx
I then followed the steps in documentation, with one difference, you should not
put the include files in /usr/include/c++/v1, your just installed Clang won’t look
there, you must put it in /usr/local/lib/c++/v1. Just as the documentation suggests, I’ve
just made symbolic links after building. Also, I symlinked the libs to /usr/local/lib,
not /usr/lib as suggested.
PCKeyboardHack
This one is vital for Mac VIM users, it’ll turn your useless caps lock key into esc’s. download it now!
MacVim
Since I’ve chosen a newer Ruby as default at my setup, I needed to compile MacVim from sources
to make it use the newer one.
MacVim uses an Xcode project, so you’ll need to download it from App Store first, it’s free.
The advantage of compiling it from sources is that you can optimize compilation. I’ve open up
MacVim.xcodeproj and changed it to use Clang and libc++ at compilation. Also, by building
from sources you can make document icons available, so that when you set a filetype to aways
open with VIM, it won’t show a generic VIM icon in Finder, but a specific one for the file type.
You can find more information at the MacVim GitHub wiki.
I’ve set MacVim as my editor of choice for a huge number of file types by using
RCDefaultApp.
I’ve cloned MacVim to /usr/local/src/macvim and then, after building, just created a bunch
symlinks to install it:
ln -s /usr/local/src/macvim/src/MacVim/build/Release/MacVim.app /Applications/MacVim.app
ln -s /usr/local/src/macvim/src/MacVim/mvim /usr/local/bin/mvim
ln -s /usr/local/bin/mvim /usr/local/bin/mvimdiff
ln -s /usr/local/bin/mvim /usr/local/bin/vim
ln -s /usr/local/bin/mvim /usr/local/bin/vimdiff
mvim is a smart shell script to launch MacVim in GUI or command line mode, you can find more
information by invoking the help: :h macvim-start. I’ve tweaked this script a bit to make
the GUI launcher (mvim or mvimdiff) to aways use a running instance to open a file in a
new buffer, instead of opening a new MacVim instance:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
vim pathogen
Once you start to use it, you know how essential it is. vim pathogen
makes using VIM plugins so much easer. Before it, plugins just dropped its files in a
confusing manner at the VIM directory, afterwards, how do you know which files comes from
which plugin? By using vim pathogen every plugin stays in its own directory, it’ll recognize
the vim directory structure inside the plugin’s directory and load it without the need to
merge plugin files inside a single directory structure.
After learning of vim pathogen, I’ve made a cleanup at my .vim directory. I started again
with an empty one, turned it into a git repository, and added plugins as git modules:
git submodule add git://github.com/tpope/vim-pathogen.git bundle/vim-pathogen
git submodule add git://github.com/scrooloose/nerdtree.git bundle/nerdtree
git submodule add git://git.wincent.com/command-t.git bundle/command-t
git submodule add git://github.com/SirVer/ultisnips.git bundle/ultisnips
git submodule add git://github.com/ervandew/supertab.git bundle/supertab
git submodule add git://github.com/jiangmiao/auto-pairs.git bundle/auto-pairs
git submodule add git://github.com/vim-scripts/Cpp11-Syntax-Support.git bundle/cpp11
git submodule add git://github.com/xuhdev/SingleCompile.git bundle/SingleCompile
git submodule add git@github.com:oblitum/clang_complete.git bundle/clang_complete
git submodule add git@github.com:oblitum/vimprj.git bundle/vimprj
git submodule add git@github.com:oblitum/dfrank_util.git bundle/dfrank_util
git submodule add git@github.com:oblitum/bufkill.git bundle/bufkill
git submodule add git@github.com:oblitum/cSyntaxAfter.git bundle/cSyntaxAfter
git submodule add git://github.com/tpope/vim-markdown.git bundle/vim-markdown
git submodule add git://github.com/vim-scripts/ScrollColors.git bundle/ScrollColors
git submodule add git://github.com/flazz/vim-colorschemes.git bundle/colorschemes
Some of these submodules are from my personal copies at https://github.com/oblitum, they need to, and I’ll explain it in their own sections.
The only setup for vim pathogen at my .vimrc is the default:
1 2 3 | |
vim pathogen takes care of loading itself, and the other plugins, all living in their own directories.
EDIT 1:
As usual in all things VIM, there’re options, Rodrigo Delduca, aka skhaz
just made me remember of Vundle. It builds upon ideas from
pathogen and others, currently I don’t use it, feel free to try.
EDIT 2:
Also, I just recalled of VAM too.
vimprj
vimprj is neat, it’s a minimalist plugin that does the job of cascade sourcing of vim configurations in a directory tree. What can you do with that?
Let’s say I have a boost-samples directory with some C++ files that must link
against boost_system to build. I use the SingleCompile plugin for simple compilations and
have set a variable to store compiler options for it. This variable has a default value at
my .vimrc, but at my boost-samples directory I want to append -lboost_system to the
compiler options, how to do that? With vimprj I can just create a .vimprj file at my
boost-samples directory and I can just append the extra compiler option to the variable!
Contents for boost-samples/.vimprj:
1
| |
Done! .= appends strings in Vim Script, now when I open a C++ file living somewhere in
the boost-samples directory, or any subdirectory, the “virtual .vimrc” loaded for
that file will have the .vimprj file sourced!
But, let’s say there’s a boost-samples/chrono-samples directory, where I need not only
to link against boost_system, I need to link against boost_chrono too, what to do?
Contents for boost-samples/chrono-samples/.vimprj:
1
| |
Done! For the files living in boost-samples/chrono-samples, boost-samples\.vimprj will
get sourced and then boost-samples/chrono-samples/.vimprj too! It’s all the flexibility
of Vim Script being sourced in cascade =D
This is not all the truth, but is enough to explain the point. The truth is that SingleCompile in specific can’t get configured just by setting a variable, a function like the following must be called to get it’s configuration updated:
1 2 3 4 5 6 7 8 9 10 11 | |
Did you see the g:single_compile_options variable being used right there? ok. Let’s say
we put this function at our central .vimrc, what we need now is a vimprj hook that calls
this function everytime a .vimprj file ends being sourced, so that changes to
g:single_compile_options take effect. And we could not expect less from such a smart
plugin, just putting this at our beloved .vimrc:
1 2 3 4 5 6 7 8 9 | |
Now g:single_compile_options will aways get a default value and changes to it will
aways take effect after sourcing a .vimprj file, and when not sourcing too ;-)
You should get .vimprj not from vim.org,
but go directly to the mercurial repository, or
even my github copy, the OnAfterSourcingVimprj hook was added after some hacking I was
doing that in the end turned in a request to the vimprj author, which he kindly accepted.
NERD tree
Well, I think I don’t need to explain it, this plugin is so popular. It’ll create a
neat buffer to let you browse your filesystem. The only caveat with it I think, is when
you begin deleting buffers and the NERD tree buffer takes all the screen. To solve it
I employed bufkill, it’s a
plugin to provide buffer deleting commands that preserves the VIM’s window layout.
Also, I’ve employed some protection for the NERD tree buffer so that I don’t delete it
by accident. These are my mappings relating to NERD tree:
1 2 3 4 5 6 7 8 9 10 | |
Command-T
Command-T is another smart file browser for VIM, this one uses fuzzy input to look for files, and it’s a very fast way of doing that in a project tree. This plugin is built upon Ruby and a fast C library for Ruby. I got it from the official git repository and just followed documentation. Just remember it’s a VIM plugin, and as such, must be compiled with the same environment as VIM. This one requires a C library to be compiled, I compiled it with Clang and libc++, as I compiled MacVim.
Ruby
You may chose the Ruby version you’ll use, the important thing is that VIM must be compiled with the same Ruby version as the one you’ll employ in your system. VIM can be compiled with Ruby and Python script support, Ruby is needed for Command-T for example, and Python is needed for clang_complete. I use RVM for managing Rubies, and used Ruby 1.9.3 for my setup.
clang_complete
Well, I’ve applied so many tweaks to
this project, that I’ll just advice you to clone/fork (or just download it) from
my repository instead of the official one.
I’ve applied several performance patches that now, are still to be merged in the official.
This project started as a Vim Script plugin that just used Clang binaries to do completion
and syntax checking, afterwards it evolved to use libclang and its python bindings to
perform much faster than calling an external process. The problem is that, to my taste, the
python part of clang_complete was not well developed.
After applying all the performance tweaks, I still feel there’s much room for improvement at other areas, for example, completion for include files should be very easy to do. libclang is evolving, currently it supports completion that gathers doxygen comments! but clang_complete doesn’t support it yet. Also, libclang could be used for other coding stuff beyond trivial completion and code checking. For that I don’t blame clang_complete, it deserves its own project.
So, as I was saying, clone my fork and then checkout my experimental branch if you want to taste a speedy completion. At this branch I expect to evolve things I mentioned, do refactorings, and make its python code more polished. I expect to do it faster and not willing too much to merge changes in the official repository.
These are configurations I have in my .vimrc that relates to clang_complete:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | |
Two things above that are specific of my experimental branch are g:clang_memory_percent
and g:ClangBackgroundParse().
g:clang_memory_percent is a setting I’ve created to control the amount of RAM VIM can
use to maintain translation units. When Clang parses a file, it can take a considerable
amount of RAM for each file parsed, once the amount of RAM being used reaches a given
percentage of the total memory, clang_complete will start to deallocate old translation
units to leave room for new ones. This is a hint for the maximum of memory that can be
used for translation units. This feature requires installation
of the psutil python
module.
g:ClangBackgroundParse() is a function I’ve created to issue reparsing in background
of the source file being edited, as it takes some seconds. It’s mostly useful only when
you touch your include headers because Clang precompiles your include section to provide
faster completion, and if you change it, you should issue a reparsing to get really
fast again.
I’ve created a key mapping for this background reparsing, and also one for the syntax
checking feature.
Also, talking about precompilation, currently for it to happen, your source file must exist in the file system. Creating a new file without saving it at last once will not give optimal completion results, once you save it and issue a precompilation, completion is optimal. Completion is optimal while the include section is not touched, once touched, issue a parse. A first parse aways happen after opening a file, so no need to do it manually after opening an existing file. No need to save an existing file after touching includes, just issue a reparse.
g:clang_auto_user_options is a clang_complete setting that has a default value that just
caused me problems. This one provides some automatic sources for include headers. I just
don’t use it, as I use vimprj to control include directories and stuff like that by setting
g:clang_user_options.
I’ll let you read about the other options from documentation ok?
Last, but not least, currently there’s a proposal for a kind of Clang services daemon. The future of completion and syntax checking? Who knows.
SingleCompile
I started using this one for ingenuous compilation of C++ samples, It’s working for that job very well. It can be used with make files, cmake, I don’t know, I haven’t looked into that yet. As already mentioned, I employ cascaded configurations for it using vimprj.
Ultisnips
Ultisnips is a very well supported snippets plugin, contrary to the competition like SnipMate. It works well with other plugins like SuperTab and clang_complete by not using the same key mappings by default, avoiding conflicts.
SuperTab
Don’t like to force completion with ctrl-x ctrl-u? SuperTab to the rescue, with it you can use tab most of the time for completion without problems. I’ve set it up like this to get forced Clang completion with tab:
1 2 3 4 5 6 | |
The <c-p> at the end of the <c-x><c-u> is to issue a “control previous” after a completion,
this avoids auto selection of itens from the popup menu. I don’t like auto selection.
You can use tab and shift-tab to browse completion entries in the popup menu, tab to browse through
function parameters in normal mode (when g:clang_snippets_engine='clang_complete'), to complete
a word in the middle, you got it.
Auto Pairs
Auto Pairs will create automatic pairs for [], {}, (), "", etc.
I’ve requested a small correction for
it, so I advice you to get a recent copy. Also, if you are an OS X Lion user,
or Mountain Lion user like us,
there’s a weird behavior with alt/option keys, also know as meta keys in VIM. An alt key
combination will produce a special character, for example, alt-p produces π, alt-m produces
∑, and there’s a bunch of others. Auto Pairs uses a bunch of meta key mappings that just
won’t work because of that. The solution I found was to map this special characters at my
.vimrc and it does works:
1 2 3 4 5 6 | |
Cpp11-Syntax-Support
This one is to provide minimal support for syntax highlighting of the new standard. I didn’t look too further of what highlighting it does, just installed.
cSyntaxAfter
Most VIM colorschemes doesn’t provide highlighting for operators of C based languages, I think this
is most due to the lack of a syntax highlighting group for that. This small plugin will put operators
in a new syntax highlighting group and turn highlighting for them.
I started using it very recently, and applied two small tweaks, one is that I changed it so that it
doesn’t highlight < or > when there’s a sequence as <# or #>. <# and #> are used by
clang_complete snippets as placeholder marks, and they can be concealed (hidden from user view). The
problem is that if highlighting get it, they cease to be concealed. So I’ve used some VIM regex to
exclude these special cases.
The other small tweak is that it was highlighting { and } with hardcoded yellow, which wasn’t
looking good with light colorschemes. So I changed it to use a default color for operators.
You can get it with the changes from my GitHub repo.
Results
My .vimrc
You can check my .vimrc from this gist. It’s contains what I’ve
already talked about plus yet more usage of vimprj for example, which can illustrate things better.
This is what you get
Ok, I’ve prepared a 12 minutes video covering some usage of the above environment editing some C++ files
using Poco, Boost, STL, variadic templates, new range for syntax, uniform initialization, etc. Sorry for
the slow typing, I was copying text from my cellphone :P and I’m still a beginner in VIM. I tried to
cut/edit with iMovie but it just messed with the quality, so I uploaded it raw. If you don’t want to take
a look at the whole video, the following links may be of interest:
- Editing files using Poco
- Editing boost::asio samples
- Editing a boost::chrono V2 sample
- Compiling and running the boost::chrono sample
- Fuzzy browsing with Command-T
- Using asio with C++11
- Running the asio sample
- File browsing with NERD tree
- C++11 completion showcase
- Syntax checking C++11
- vimprj all over the place
Bonus
Now, if you got here and think VIM does not have potential, go get your Winchester! but I’ll stick with my 45: