# VIM神级补全插件YouCompleteMe安装详细步骤
YouCompleteMe(以下简称YCM)是Google搜索组程序员Valloric开发的VIM代码自动补全插件,与其它补全插件相比,最大的特点是能够基于语义完成补全,支持多种语言(智能补全支持Python/C家族/JS/Rust等)。对于C/C++语言,该插件能够利用Clang前端编译器的语义补全接口对当前代码产生符合上下文的智能补全提示,且其补全结果排名应用了搜索引擎的结果排序技术。
效果如下
该插件是属于用VIM编码的杀手级插件,使用该插件以后,自动完成功能秒杀sublime text,notepad++等文本编辑器,直逼Visual Studio.
虽然好用,但是该插件出了名的难装,因为需要自己编译。
关于如何从Clang源码开始安装该插件,网上有数篇blog解释了具体步骤,但是经过一一实验,由于系统环境不同,全部失败了。为了安装该插件,本人找资料、编译(共编译了cmake 3.4.3/gcc 4.8.2/llvm 3.9/glibc 2.21/YCM等5个组件,历时大半天)。 整个安装配置过程前后花了至少一天半,现将安装的曲折过程全程记录如下。
安装编译过程主要参考了以下两篇资料
Full Installation Guide
compile-llvm-against-a-custom-glibc
$ rpm --query centos-release
centos-release-6-4.el6.centos.10.x86_64
$ gcc --version # 原版本4.4, 后来自己手动编译了4.8以支持C++ 11
gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
第一次安装不使用完全安装,直接按照YCM官网的指南直接输入
python install.py --clang-completer
python run_tests.py
结果编译链接过程出现以下错误
[ 98%] Building CXX object ycm/tests/CMakeFiles/ycm_core_tests.dir/main.cpp.o
[100%] Building CXX object ycm/tests/CMakeFiles/ycm_core_tests.dir/TestUtils.cpp.o
Linking CXX executable ycm_core_tests
../../clang+llvm-3.6.0-x86_64-linux-gnu/lib/libclang.so: undefined reference to `posix_spawn@GLIBC_2.15'
../../clang+llvm-3.6.0-x86_64-linux-gnu/lib/libclang.so: undefined reference to `memcpy@GLIBC_2.14'
collect2: error: ld returned 1 exit status
make[3]: *** [ycm/tests/ycm_core_tests] Error 1
make[2]: *** [ycm/tests/CMakeFiles/ycm_core_tests.dir/all] Error 2
make[1]: *** [ycm/tests/CMakeFiles/ycm_core_tests.dir/rule] Error 2
make: *** [ycm_core_tests] Error 2
Traceback (most recent call last):
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 196, in
Main()
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 189, in Main
BuildYcmdLibs( GetCmakeArgs( args ) )
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 152, in BuildYcmdLibs
_err = sys.stderr )
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 1021, in __call__
return RunningCommand(cmd, call_args, stdin, stdout, stderr)
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 486, in __init__
self.wait()
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 500, in wait
self.handle_command_exit_code(exit_code)
File "/home/user/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 516, in handle_command_exit_code
raise exc(self.ran, self.process.stdout, self.process.stderr)
sh.ErrorReturnCode_2:
RAN: '/usr/bin/make -j 8 ycm_core_tests'
STDOUT:
STDERR:
输入以下命令查看依赖库
strings ~/.vim/bundle/YouCompleteMe/third_party/ycmd/libclang.so.3.8 | grep -i glibc
发现是liclang.so.3.8需要至少Glibc 2.15, GlibCXX 3.4.19, Centos 6.4自带的Glibc版本2.12版本太低,无法满足最低版本要求。
于是去LLVM官网上下载了一个针对Centos6编译好的Clang3.8,然后按照完全安装指南指定编译选项
cmake -G "Unix Makefiles" -DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp
结果问题依旧。需要系统更高版本Glibc的问题依然未解决。接着尝试了下载针对Fedora 18预编译的YCM所支持的最早Clang版本3.3,结果一样,链接失败。
由于YCM官网强烈不推荐自己编译Clang,于是本人尝试直接使用包管理器安装老版本Clang
sudo yum install -y clang
结果使用-DEXTERNAL_LIBCLANG_PATH选项编译好YCM以后进入vim输入’:YcmToggleLogs stderr’发现不能用,YCM需要Clang3.8版本,晕死。
目前为止除非直接下载新版Glibc并替换系统库,否则无法继续下去。该问题的关键原因是可执行文件链接的库路径是直接硬编码在文件中的,具体原理可以参考这里。但是, 替换系统核心库Glibc是一件极其容易导致系统崩溃的行为,Google了一下发现已经有好几个人这么弄中招了。公司72服务器上有MySQL服务器保存了数T的用户行为数据,不能冒这个险。因此,唯一的选择只能是从源码重新编译Clang+llvm,并链接指定的Glibc库。
总结: 由于10.200.8.72(以下简称72)上安装的64位Centos 6.4系统版本太老不支持直接安装YCM自带的预编译的的llvm+clang(要求GLibc >= 2.15且GLibCXX >= 3.4.19, 其中72上自带的Glibc 2.12为系统核心组件无法替换,因此只能重新编译clang3.8或以上的版本并链接下载的新版GLibc)
## 成功编译过程
cd ~
wget https://cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.tar.gz
tar -zxf cmake-3.4.3-Linux-x86_64.tar.gz
cd ~
mkdir -p ~/gcc4.8/src
wget https://ftp.gnu.org/gnu/gcc/gcc-4.8.2/gcc-4.8.2.tar.gz
tar -zxf gcc-4.8.2.tar.gz -C ~/gcc4.8/src
cd ~/gcc4.8/src/
mkdir gcc-build-4.8.2
cd gcc-build-4.8.2
../gcc-4.8.2/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
make -j 6 # 2.3G+, 事后可删除gcc-build目录
sudo cp -fp ./x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.18 /usr/lib64/
mv /usr/lib64/libstdc++.so.6.0.18 /usr/lib64/libstdc++.so.6 # ln -sf ./lib/gcc/x86_64-redhat-linux/4.8.2/libstdc++.so /usr/lib64/
编译gcc大约需要半小时,为了节省时间,make时使用’-j 6’指定了6个核心
mkdir -p ~/code/glibc
wget http://ftp.gnu.org/gnu/glibc/glibc-2.21.tar.gz
tar -zxf glibc-2.21.tar.gz -C ~/code/glibc
cd ~/code/glibc/glibc-2.21
mkdir build
cd build
export LD_FLAGS='-Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib64:/usr/lib64'
../configure --with-binutils=/usr/local/bin --prefix=/usr/local/glibc/glibc-2.21
make -j 6
sudo make install
安装过程会出现如下警告
/home/rstudio2/code/glibc/glibc-2.21/build/elf/ldconfig: Warning: ignoring configuration file that cannot be opened: /usr/local/glibc/glibc-2.21/etc/ld.so.conf: No such file or directory
make[1]: Leaving directory `/home/user/code/glibc/glibc-2.21'
不用理会,直接忽略
mkdir ~/code
cd ~/code/llvm_source_tree
git clone http://llvm.org/git/llvm.git
cd ~/code/llvm_source_tree/llvm/tools
git clone http://llvm.org/git/clang.git
cd ~/code/llvm_source_tree/llvm/projects
git clone http://llvm.org/git/compiler-rt.git
git clone http://llvm.org/git/test-suite.git # 1.8G+
cd ~/code/llvm_source_tree/llvm
git config branch.master.rebase true
mkdir -p ~/code/llvm_source_tree/build
cd ~/code/llvm_source_tree/build
export CXXFLAGS='-std=c++11 -Wl,--rpath=/usr/local/glibc/glibc-2.21/lib:/lib64:/usr/lib64 -Wl,--dynamic-linker=/usr/local/glibc/glibc-2.21/lib/ld-linux-x86-64.so.2'
~/cmake-3.4.3-Linux-x86_64/bin/cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE='Release' ~/code/llvm_source_tree/llvm/
make -j 6 # 1.5G+, 事后可删除build目录
sudo make install
编译llvm大约需要半小时,为了节省时间,make时使用’-j 6’指定了6个核心
首先安装vim包管理插件vundle, 关于该插件如何安装,可以Google, 例如这里
接着正式开始安装YCM插件
Plugin 'Valloric/YouCompleteMe' # bundle required
cd .vim/bundle/YouCompleteM
cmake28 -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so.3.9 . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp
cmake28 --build . --target ycm_core
python install.py --clang-completer
sudo pip install --upgrade pip
sudo pip install flake8 nose future mock PyHamcrest
python run_tests.py
----------------------------------------------------------------------
Ran 221 tests in 6.323s
OK (SKIP=3)
echo | cpp -Wp,-v
echo | /usr/local/bin/clang -std=c++11 -stdlib=libc++ -v -E -x c++ -
将这两个命令的输出添加至YCM配置文件
‘/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py’
在flags编译器选项加入以下行
'-I',
'/usr/include/c++/4.8.2',
'-I',
'/opt/rh/devtoolset-2/root/usr/include/c++/',
'-I',
'/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include',
'-I',
'/usr/local/include/',
其中/opt/rh/devtoolset-2/root/usr 是写本文之前下载的gcc4.8.2源码的文件路径,当时编译的libstdc++.so.*已经找不到了,为了演示在开始步骤重新下载编译了gcc 4.8.2,这次放在了~/gcc目录下。
~/.vimrc
let g:ycm_auto_trigger = 1
" for ycm
let g:ycm_error_symbol = '>>'
let g:ycm_warning_symbol = '>*'
let g:ycm_autoclose_preview_window_after_completion = 1
let g:ycm_autoclose_preview_window_after_insertion = 1
let g:ycm_global_ycm_extra_conf = "~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py"
nnoremap gl :YcmCompleter GoToDeclaration
nnoremap gf :YcmCompleter GoToDefinition
nnoremap gg :YcmCompleter GoToDefinitionElseDeclaration
nnoremap :YcmDiags
inoremap
let g:ycm_semantic_triggers = {
\ ' c' : ['->', ' ', '.', ' ', '(', '[', '&'],
\ 'cpp,objcpp' : ['->', '.', ' ', '(', '[', '&', '::'],
\ 'perl' : ['->', '::', ' '],
\ 'php' : ['->', '::', '.'],
\ 'cs,java,javascript,d,vim,python,perl6,scala,vb,elixir,go' : ['.'],
\ 'ruby' : ['.', '::'],
\ 'lua' : ['.', ':']
\ }