系统:macOS Mojave 10.14.6
vim 版本:8.1 (高于 7.4.1578 且支持 Python2 或 Python3 即可)
CMake 的安装
CMake 是一个跨平台的项目管理工具。可以直接通过 brew
获取
brew install cmake
Vundle 的安装与使用
Vundle 是一个自动化的 vim 插件管理器。由于版本更新,Vundle 的配置方式和网上给出的半数教程不再一致。参考 Vundle 的 官方文档 ,可以使用以下命令安装 Vundle
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
下载完成后,就可以使用 Vundle 去下载和管理其他插件了。首先在 ~/.vimrc
中指明要使用 Vundle 管理的插件
set nocompatible
filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'
Plugin 'scrooloose/nerdtree'
Plugin 'jistr/vim-nerdtree-tabs'
Plugin 'vim-scripts/taglist.vim'
Plugin 'tomasr/molokai'
Plugin 'vim-syntastic/syntastic'
Plugin 'Valloric/YouCompleteMe'
call vundle#end()
filetype plugin indent on
Plugin
命令后的参数是要管理的插件在 github
的地址。保存好之后,打开 vim 并运行命令
:PluginInstall
Vundle 就会检查这些插件是否已经安装,如果没有安装则会自动到 github
上下载安装。
YCM 的安装
YouCompleteMe 也是一个插件,因此可以通过 Vundle 进行安装。不同点在于
- YCM 体积较大,下载速度慢,最好找一个访问
github
快的地方下载。 - YCM 需要编译,因此下载完成之后会报错,不用管他。
切换到 YCM 的下载目录运行安装脚本
cd ~/.vim/bundle/YouCompleteMe/
./install.py
如果需要对 C
家族进行语义补全,使用参数
./install.py --clang-completer
如果你足够幸运的话,这样应该就装好了。但是一般情况下是不行的(史上最难安装插件这个名头不是白来的😭)所以 YCM 官方文档 中给出了全手动安装的方法
1. 下载 YCM
这一步可以通过 Vundle 或手动拉取 git
仓库
cd ~/.vim/bundle/
git clone https://github.com/ycm-core/YouCompleteMe.git
git submodule update --init --recursive
需要注意的是,YCM 仓库中引用了很多第三方仓库。尤其是
~/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/cregex/
这个仓库,博主两次重装都没有拉取成功(不知道是不是设计如此)。据官网说 cregex
的安装是可选的,不下载可能也没关系。不过毕竟大头都下载完了,也不差这一点了
cd ~/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/
rm -rf ./cregex
git submodule update --init --recursive
2. 下载 libclang
这一步只对于 C
家族语义补全是必须的,不需要的用户可以跳过。直接前往 llvm 官网 下载 llvm 二进制文件即可
YCM 官方要求 llvm 版本不低于 8.0.0,但是最高版本 8.0.1 目前没有 macOS 版,因此就只能先下载这一版了。如果以后有了最新版还是最好下载新版本,免得因为 YCM 更新还要重新编译。
下载预编译 llvm 二进制文件是 YCM 官方推荐的做法,不过使用本机 llvm 也是可行的
brew install llvm
因为博主网速感人,死活下不下来,结果也就不得而知了。安装好的小伙伴可以试一下。
备份!!!
前面说过的两步可能是安装过程中耗时最长的了。因此在继续安装之前,最好把这些下载好的文件备份一下,以免后面安装失败还要重新下载。博主把下载好的文件放在百度网盘
压缩后有 600 MB 左右,大家可以斟酌一下速度选择性下载。
编译 ycm_core
接下来就是编译 YCM 的核心了,首先需要把解压好的 llvm 放到 ~/ycm_temp
目录下
/Users/lutingwang
└── ycm_temp
└── llvm_root_dir
├── bin
├── include
├── lib
├── libexec
└── share
然后切换到编译目录
cd ~
mkdir ycm_build
cd ycm_build/
开始编译
cmake -G "Unix Makefiles" -DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp
cmake --build . --target ycm_core --config Release
如果运行正常,你的 YCM 应该已经可以使用了。删除上面创建的临时路径不会影响 YCM 工作
cd ~
rm -r ycm_temp
rm -r ycm_build
编译 regex
这一步是可选的,目的是加快正则表达式的解析速度。编译过程与上面类似
cd ~
mkdir regex_build
cd regex_build
cmake -G "Unix Makefiles" . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/cregex
cmake --build . --target _regex --config Release
cd ~
rm -r regex_build
YCM 的配置
安装完成之后,还需要对 YCM 进行配置。如果使用 Vundle 进行管理(YCM 放在 ~/.vim/bundle/
目录下),请先确认~/.vimrc
中有没有
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" ...
Plugin 'Valloric/YouCompleteMe'
" ...
call vundle#end()
注意 YCM 的声明要放在 vundle#begin()
和 vundle#end()
之间。
然后修改 .ycm_extra_conf.py
这个文件的位置众说纷纭,我在安装的时候发现他就放在 YouCompleteMe/
目录下。估计又是一个更新过程中的变化。总之,找到这个文件然后在 import
语句后定义
# import os.path as p
# import subprocess
flags = [
'std=c++11',
'-x',
'c++',
'-I', '.',
'-isystem',
'/usr/local/include',
'-isystem',
'/Library/Developer/CommandLineTools/usr/include/c++/v1',
'-isystem',
'/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/include',
'-isystem',
'/Library/Developer/CommandLineTools/usr/include',
'-isystem',
'/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include',
'-isystem',
'/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks'
]
def FlagsForFile(filename):
return { 'flags': flags }
# DIR_OF_THIS_SCRIPT = p.abspath( p.dirname( __file__ ) )
# DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, 'third_party' )
注释掉的部分是原本就有的。可以看到这里我们定义了一个 flags
列表作为 FlagsForFile
函数的返回值。这个列表的作用相当于 gcc
命令后面跟的参数。先看 -isystem
的一系列值,这些值所包含的路径就是 #include < ... >
时编译器的搜索路径。虽然大体相同,但是不同电脑的路径可能还是有些许差异,可以通过命令查询
Lutings-MacBook-Air:ycm4mac lutingwang$ echo | clang -v -E -x c++ -
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
"/Library/Developer/CommandLineTools/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -E -disable-free -disable-llvm-verifier -discard-value-names -main-file-name - -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fno-strict-return -masm-verbose -munwind-tables -target-sdk-version=10.14 -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -target-linker-version 450.3 -v -resource-dir /Library/Developer/CommandLineTools/usr/lib/clang/10.0.1 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -I/usr/local/include -stdlib=libc++ -Wno-atomic-implicit-seq-cst -Wno-framework-include-private-from-public -Wno-atimport-in-framework-header -Wno-quoted-include-in-framework-header -fdeprecated-macro -fdebug-compilation-dir /Users/lutingwang/.Trash/ycm4mac -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fobjc-runtime=macosx-10.14.0 -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o - -x c++ -
clang -cc1 version 10.0.1 (clang-1001.0.46.4) default target x86_64-apple-darwin18.7.0
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/v1"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/Library/Developer/CommandLineTools/usr/include/c++/v1
/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks (framework directory)
End of search list.
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 373 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2
注意到其中有一行 #include <...> search starts here:
后面连续几行就是我们想要的信息。
编辑完 .ycm_extra_conf.py
,还需要修改 ~/.vimrc
。在 YCM 的 Plugin
语句后写上
let g:ycm_global_ycm_extra_conf='~/.vim/bundle/YouCompleteMe/.ycm_extra_conf.py'
相当于把刚刚修改的文件设置成全局 YCM 配置。这样 YCM 应该就可以工作了。随意打开一个源文件,在输入标识符时会自动弹出补全选项。如果没有反应,或者像博主一样在底线命令行提示 The ycmd server SHUT DOWN ...
,就还需要一点工序。
不过如果你安装成功了,那么恭喜,你的 vim 已经拥有了 IDE 级别的自动补全功能。如果需要的话,还可以在 ~/.vimrc
中配置
let g:ycm_key_list_select_completion=['<c-n>']
let g:ycm_key_list_previous_completion=['<c-p>']
let g:ycm_collect_indentifiers_from_tags_files=1
let g:ycm_seed_identifiers_with_syntax=1
let g:ycm_confirm_extra_conf=0 " 避免YCM每次加载都对用户提示是否加载
let g:ycm_autoclose_preview_window_after_completion=1
let g:ycm_complete_in_comments = 1 " 在注释输入中也能补全
let g:ycm_complete_in_strings = 1 " 在字符串输入中也能补全
let g:ycm_collect_identifiers_from_comments_and_strings = 1 " 注释和字符串中的文字也会被收入补全
YCM 安装常见问题
根据博主三天安装 YCM 的经历来看,这个插件之所以难装其实主要是因为下载速度慢。提前下载好 YouCompleteMe
仓库和 llvm 二进制文件的话,安装起来并不算慢(博主最后一次重装 5 分钟之内就运行完了)。因此在安装之前只要做好了备份,重装不是什么难事。下面就来说说我安装时遇到的问题
vim 闪退,报告 python 的 MemoryError
这个问题出现在我第一次使用 Vundle 安装 YCM 之后。那时一切都顺利得不可思议,Vundle 在不到半个小时就把 YCM 下载好了,还报了一个错误 MemoryError。只是那时的我以为这个错误就是传说中“正常”的报错,没有管他。等到一套安装流程走下来,我才发现我的 vim 再也用不了了……
后来查资料发现我安装的 Vundle 是旧版本,使用的命令都还是 Bundle 'Valloric/YouCompleteMe'
。可能是兼容问题之类,总之 vim 在处理 call vundle#rc()
时就会触发 MemoryError
。最后把 Vundle 删除了,重新安装一个就好了。
The ycmd server SHUT DOWN … Unexpected exit code -11 …
根据提示查看 log 发现是空的,在网上搜了很久也没有人说过 -11 这个码对应的问题是什么……可能真的是 Unexpected. 于是博主就使用了万能的补救方法
cd ~/.vim/bundle/
rm -rf ./YouCompleteMe
cp -r ~/Desktop/YouCompleteMe ./
cd YouCompleteMe/
./install.py --clang-completer
重新安装。然而重新装了两次之后我就放弃了,一般来说安装错误不会这么频繁的。后来在一个网站上看到网友提供的思路
- 使用命令
:YcmDiag
获取具体信息 - 注释掉
~/.vimrc
中let g:ycm_confirm_extra_conf=0
以确认编译正常
第一个方法其实相当于查看 log,只不过 log 都没有记录信息,而这个命令居然返回了 内置补全功能不能识别该文件类型
这样的报错。也正是因为这个报错信息,让我怀疑到 llvm 的安装(之前一直使用的是 install.py
没有想过自动下载也会出现问题)。
第二个方法稍微复杂一点。正常情况下,进入 vim 之后 YCM 都会在底线命令行提示询问是否加载某个 .ycm_extra_conf.py
文件,除非 ~/.vimrc
中禁用了这一功能(也就是上面那个命令的作用)。因此如果编译正常,应该会有相似的询问。即使出现错误,也应该在询问之后崩溃。但是博主的 vim 只要一进入就会提示 server shutdown,因此怀疑还是编译过程出了问题。
从结果来看,重装是必须的了,但是用脚本安装已经不靠谱了,所以我才选择了手动安装。不得不说官方文档还是要认认真真看,就算照着安装完还有问题,一般也不会致命。
Python 版本
网上问的最多的问题就是版本不一致。这里的不一致主要有 Python 版本和 llvm 版本两个方面。由于 llvm 我们是手动从官网下载的,因此不存在这方面问题。至于 Python 版本,博主也一直没有搞懂问题出在哪……不过结果就是,ycmd server 又 shutdown 了。这次倒不再是 Unexpected 了,而是提示我编译时与运行时使用的 Python 版本不同,需要在 ~/.vimrc
中给出 Python2 的安装路径。于是有了这么一句
let g:ycm_server_python_interpreter='/usr/bin/python2.7'
YCM 的使用
上文中提到,修改 ~/.vim/bundle/YouCompleteMe/.ycm_extra_conf.py
时增加了一个 flags
列表。这个列表中 -isystem
选项指定了系统头文件的搜索路径。而对于项目内部的头文件,则只有 '-I', '.'
这么一句。如果项目中使用了不在本目录下的头文件,就还需要来修改这个文件。但是很显然这样做效率很低。因此比较好的做法是,复制一份配置文件到工程源码的根目录下,将工程的头文件目录加入配置文件。由于 YCM 搜索 .ycm_extra_conf.py
时优先搜索当前目录,而后逐个父目录搜索,最后才会使用全局配置文件。因此,工程根目录的配置文件可以覆盖全局文件。这样就相当于为每个工程单独指定了一个配置,不会污染系统设置。
来源:https://blog.csdn.net/LutingWang/article/details/99485096