sd bio photo

sd

"passionate and serene, profound and simple, affectionate and proud, subtle and straightforward"

This is a updated version of the original post after I fixed my YouCompleteMe (or YCM) installation broke-down on Jan 3rd, 2017. Better configuration solution for bjam build system is appended at the end.

Preparation

To start with, visit the Github page and read through the section with the title “Mac OS X super-quick installation”. Particularly pay attention to the part that has something to do with C Family language, as I quote:

  • If you want C-family completion, you MUST have the latest Xcode installed along with the latest Command Line Tools (they are installed when you start Xcode for the first time).
  • Install CMake. Preferably with Homebrew, but here’s the stand-alone CMake installer.

Apart from these, another thing to check for is your Vim version. First, YouCompleteMe will only work with Vim version higher than 7.3.584. To check for your version, just run vi --version | head -1 or start Vim without specifying a file to open. Also, your Vim should have python2.x support. To check whether you have python2.x support, run vi --version | grep '+python'. If the output is not null, you’re good to go. The YouCompleteMe document requires you to use MacVim, but from my experience that does not matter much as long as the previous two requirements are met.

Installation

Having finished all these checks, it’s time to start install YCM. Basically YCM has two parts: the Vim plugin that interacts with Vim, and the clang backend that generates completion by compiling the source file. Hence, the installation will also proceed in two parts.

Vim Plugin

Install with Vundle. If you don’t use vundle, it’s worth to take some time to get familiar with it.

Clang Backend

I just charged ahead and used the simple installation script, which is just typing the following command to compile YCM:

cd ~/.vim/bundle/YouCompleteMe
./install.sh --clang-completer

The maintainer confused me somewhat by saying:

Please refer to the full Installation Guide below; the following commands are provided on a best-effort basis and may not work for you.

which seem to have meant that everyone should go through the procedure in the full Installation Guide, and yet he kept the quick installation guide for each OS. Persoanlly I tried both full and quick installation on my Mac OS X, and I don’t see any difference. But YMMV.

Configuration

.ycm_extra_conf.py file

OK. Now you have installed YCM, but this is not the end of the story. Because specially for YCM to work with C++ program, you’ll have to write a .ycm_extra_conf.py file in your project directory, to provide your plugin with all the headers and flags needed to compile the source. Fortunately you don’t really have to write it, at least most of the time – you can have it generated automatically, using YCM-Generator. Don’t attempt to use Vundle to install it, just git clone to somewhere and you are done.

What this generator does is reading the makefile in your project directory and translate the setup of your build into the setup of your auto-completion plugin. But still, there is a template file which you need to fill up, which points to your C++ standard library and so on. Now here is the problem: how would your plugin know where is your C++ standard library? Well the fact is your plugin won’t automatically know, and your YCM-Generator won’t either – you have to tell them.

So you’ll have to know where does the C++ library locate in your machine. Type echo | clang -v -E -x c++ - into your terminal, you should be able to get something like this:

Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.3.0

...

#include "..." search starts here:
#include <...> search starts here:
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.

The above directories listed are the places where your C++ compiler would search for when they build your C++ programs, so naturally, you should tell your auto-completion program to search the same place as well. To do this, go to your YCM-Generator directory and find template.py. As the name suggests, this is the “template” your generator use to generate your auto-completion comfiguration file. Find the flags variable (which is a python list) at the beginning of the source file, add your include directories like this:

flags = [
	'-isystem',
	'/path/to/your/first/system/include/directory',
	'-isystem',
	'/path/to/your/second/system/include/directory',
	...
	'-I',
	'/path/to/your/first/local/include/directory',
	...
]

In short, the -isystem tag precedes all the system library paths, while -I precedes all the local include directories. Keep in mind that this is a template so you shouldn’t add any project-specific paths in there. Personally, I only add . to the local include directories in template.py.

When you generate configuration files for your project with YCM-Generator, you should run:

/path/to/YCM-Generator/config_gen.py /path/to/project

That’s not too hard, isn’t it? Regretfully, when I write this post, YCMGenerator only supports four build systems: make cmake qmake and autotools. Now what should we do if we are using building systems other than these four? I used to use some guesswork to fill in the compilation flags, and as you can imagine things do not work as consistently as I hoped. And after two years I finally find a workaround.

(Optional) Use Bear To Generate Flags

Disclaimer: The .ycm_extra_conf.py config file I provided only works for bjam build system. If you need to make it work on other building systems, you may need to create your own config.

Credit: I found this solution here by Gavin Beatty. I also forked his YCM config file and made some small changes. Thanks.

From my understanding, Bear is a program that intercepts all the compilation commands incurred by a system build and formatting them into a compile_commands.json file, “for clang tooling”. I don’t really know why one would want to do that, but all we want is generating clang compilation flags for YCM, and it seems to do its job.

However, for OS X version later than 10.11 (El Capitan), Bear may not be as easy to setup as it is for others because it doesn’t like something called SIP in OS X. To make it work, you have to turn SIP off first. You can find a lot of tutorials that teach you how to do that. If you don’t want to turn SIP off, you may want to try scan-build, which contains some workaround specifically designed for that. But I’m only going to introduce Bear.

Setting up Bear on OS X itself is pretty straight-forward – there is a brew format so you can install it simply by calling:

brew install bear

What you’ll do next is generating the json file. Here is how you do it:

bear [build command]

For example, my command is:

bear ./bjam --with-boost=~/Workspace/moses/opt --with-cmph=~/Workspace/moses/opt --with-mm --with-probing-pt -j4 -a

You may see a warning about .dylb and code signing. Just ignore it.

The last step is to copy this YCM config file to your project root directory. It is designed to first go through compile_commands.json and collect flags for the source file you opened. If no flags are found in the json file, the script falls back to scanning your project folders and some guesswork. To make it cleverer, you can (and you should!) make changes in CustomFlags function to add some paths that you would like to include.

One last note: Bear does not assume build system, and it should also be pretty easy to change .ycm_extra_conf.py to accommodate your build system. So this solution should work for all the C++ build systems. Of course, I still recommend using YCM-Generator if possible such that you don’t have to tamper with your OS X security system.

(Optional) .vimrc Setup

YCM provides lots of hidden features in its configurations, which is simply too long for me to go through. So far I just picked some handy ones to add to my .vimrc file. If you know any other settings that are not included here, please let me know.

"" turn on completion in comments
let g:ycm_complete_in_comments=1
"" load ycm conf by default
let g:ycm_confirm_extra_conf=0
"" turn on tag completion
let g:ycm_collect_identifiers_from_tags_files=1
"" only show completion as a list instead of a sub-window
set completeopt-=preview
"" start completion from the first character
let g:ycm_min_num_of_chars_for_completion=1
"" don't cache completion items
let g:ycm_cache_omnifunc=0
"" complete syntax keywords
let g:ycm_seed_identifiers_with_syntax=1

This concludes our configuration for YCM. Open a C++ project and start Viming.