Debian 8.5 + GCC 5.4 + LLVM Clang 3.8.1 + Vim 8.0 配置YouCompleteMe 解决不能对C++代码补全的问题

一:系统安装与配置

虚拟机软件:Virtualbox 5.1.8(已安装相应扩展包)

虚拟机:Debian 8.5 64位


系统安装完成之后,用root用户登录终端(因为Debian 8默认没有安装sudo),用如下命令编辑软件源配置文件,把安装DVD介质注释掉,以便于能从官方网络源更新软件:

nano /etc/apt/sources.list


然后更新软件列表:apt-get update


安装编译用的基础工具包:apt-get install build-essential


用如下命令来安装Virtualbox 扩展工具包:

apt-get install module-assistant
m-a prepare

mount /media/cdrom

sh /media/cdrom/VBoxLinuxAdditions.run

安装完成之后重启系统


二:编译安装GCC


重启之后用如下命令安装必要的依赖包和工具:

apt-get install python-dev zip flex bison libncurses5-dev libgnome2-dev libgnomeui-dev libbonoboui2-dev libcairo2-dev libx11-dev libxpm-dev libxt-dev ruby-dev mercurial git-all sudo


然后执行事先写好的编译安装GCC 5.4的shell脚本,build_gcc,脚本内容如下:


注意:脚本中配置很多依赖库的目录名要根据实际情况而定,具体的安装过程可参照我的另一篇文章,只是版本不一样,其它没什么区别,这里,你可以选择目前最新的工具包。


#!/bin/sh
cd /home/guo/gmp/
./configure --prefix=/usr
make -j2
make install
cd /home/guo/mpfr/
./configure --prefix=/usr
make -j2
make install
cd /home/guo/mpc/
./configure --prefix=/usr
make -j2
make install
ldconfig 
cd /home/guo/libedit/
./configure --prefix=/usr
make -j2
make install
cd /home/guo/pcre/
./configure --prefix=/usr
make -j2
make install
cd /home/guo/swig/
./configure --prefix=/usr
make -j2
make install
cd /home/guo/gawk/
./configure --prefix=/usr
make -j2
make install
ldconfig 
mkdir /usr/lib/gcc/x86_64-linux-gnu/5.4.0
cd /home/guo/gcc/
./configure --prefix=/usr/lib/gcc/x86_64-linux-gnu/5.4.0 --enable-vtable-verify --enable-werror --disable-multilib
make -j2
make install
cd /usr/bin/
rm cpp
rm g++
rm gcc
rm gcc-ar
rm gcc-nm
rm gcc-ranlib
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/cpp cpp
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/g++ g++
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/gcc gcc
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/gcc-ar gcc-ar
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/gcc-nm gcc-nm
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/bin/gcc-ranlib gcc-ranlib
cd /usr/lib/x86_64-linux-gnu/
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib64/libstdc++.so.6.0.21 libstdc++.so.6


三:编译安装LLVM Clang和Vim

GCC安装完成之后,执行编译安装LLVM Clang 3.8.1的shell脚本,build_clang,脚本内容如下:

关于LLVM的目录结构:将Clang源码解压到llvm/tools下,将clang-tools-extra解压到llvm/tools/clang/tools/下,将compiler-rt、libc++、libc++abi、test-suite解压到llvm/projects下

#!/bin/sh
mkdir /home/guo/build/
cd /home/guo/build/
rm -rf /home/guo/gcc/
../llvm/configure --with-clang-srcdir=../llvm/tools/clang/ --with-gcc-toolchain=/usr/lib/gcc/x86_64-linux-gnu/5.4.0/ --enable-optimized --enable-targets=host-only
make
make install
cd ../llvm/projects/libcxx/lib/
./buildit
cp ./libc++.so.1.0 /usr/lib/x86_64-linux-gnu/
cd /usr/lib/x86_64-linux-gnu/
ln -sf libc++.so.1.0 libc++.so
ln -sf libc++.so.1.0 libc++.so.1
cd /home/guo/llvm/projects/libcxxabi/lib
./buildit
cp ./libc++abi.so.1.0 /usr/lib/x86_64-linux-gnu/
cd /usr/lib/x86_64-linux-gnu/
ln -sf libc++abi.so.1.0 libc++abi.so
cd /usr/lib/x86_64-linux-gnu/
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib64/libstdc++.so.6.0.21 libstdc++.so.6
cd /home/guo/vim80/
./configure --with-features=huge --enable-multibyte --enable-fontset --enable-sniff --enable-xim --enable-rubyinterp --enable-pythoninterp --with-python-config-dir=/usr/lib/python2.7/config --enable-perlinterp --enable-luainterp --enable-gui=gtk2 --enable-cscope --prefix=/usr
make VIMRUNTIMEDIR=/usr/share/vim/vim80
make install
mkdir -p /home/guo/.vim/colors
chown -R guo:guo /home/guo/.vim/
mkdir -p /root/.vim/colors
touch /home/guo/.vimrc
chown guo:guo /home/guo/.vimrc
cp /home/guo/solarized/vim-colors-solarized/colors/solarized.vim /home/guo/.vim/colors/
cp /home/guo/solarized/vim-colors-solarized/colors/solarized.vim /root/.vim/colors
cat /home/guo/vimrcusr > /home/guo/.vimrc
cat /home/guo/vimrcroot > /etc/vim/vimrc
cd /usr/bin/
ln -sf vim vi
cp /usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib64/libstdc++.so.6.0.21 /usr/lib/x86_64-linux-gnu/
cd /usr/lib/x86_64-linux-gnu/
ln -sf libstdc++.so.6.0.21 libstdc++.so.6
cd /home/guo/binutils-2.27
./configure --prefix=/usr
make -j2
make install
cd /home/guo/gdb-7.11.1
./configure --prefix=/usr
make -j2
make install
cd /home/guo/cmake-3.6.2
./configure --prefix=/usr
make -j2
make install
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib64/libstdc++.so.6.0.21 /usr/lib/x86_64-linux-gnu/libstdc++.so.6



注意:最新的YouCompleteMe要求Vim版本为7.4.143+,所以我就安装最新的Vim(可以从这里下载),上面红色标记的命令用到的文件我把其内容贴在下面,至于 solarized,可以从这里下载也许在安装完GCC之后需要再次对GCC 最新的动态库进行链接(也许有操作让该库恢复到旧版本),才能正常编译安装Clang。用如下命令:

cd /usr/lib/x86_64-linux-gnu/
ln -sf /usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib64/libstdc++.so.6.0.21 libstdc++.so.6


vimrcusr:


syntax enable
syntax on
set number
set nocompatible
set backspace=indent,eol,start
set background=dark
set tabstop=2
set expandtab
%retab!
colorscheme solarized

filetype off


let g:ycm_global_ycm_extra_conf = '~/.ycm_extra_conf.py'
let g:ycm_error_symbol='>>'
let g:ycm_warning_symbol='>*'
inoremap <expr> <CR>       pumvisible() ? "\<C-y>" : "\<CR>"
"设置跳转的快捷键,可以跳转到definition和declaration
nnoremap <leader>gc :YcmCompleter GoToDeclaration<CR>
nnoremap <leader>gf :YcmCompleter GoToDefinition<CR>
nnoremap <leader>gg :YcmCompleter GoToDefinitionElseDeclaration<CR>
"nmap <F4> :YcmDiags<CR>
"开启基于tag的补全,可以在这之后添加需要的标签路径
let g:ycm_collect_identifiers_from_tags_files = 1
"开启语义补全
let g:ycm_seed_identifiers_with_syntax = 1
"在接受补全后不分裂出一个窗口显示接受的项
set completeopt-=preview
"不显示开启vim时检查ycm_extra_conf文件的信息
let g:ycm_confirm_extra_conf=0
"每次重新生成匹配项,禁止缓存匹配项
let g:ycm_cache_omnifunc=0
"在注释中也可以补全
let g:ycm_complete_in_comments=1
"输入第一个字符就开始补全
let g:ycm_min_num_of_chars_for_completion=1
"不查询ultisnips提供的代码模板补全,如果需要,设置成1即可
let g:ycm_use_ultisnips_completer=1

let g:ycm_collect_identifiers_from_comments_and_strings = 1

let g:ycm_key_invoke_completion = '<C-a>'

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" alternatively, pass a path where Vundle should install plugins
"call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'

" The following are examples of different formats supported.
" Keep Plugin commands between vundle#begin/end.
" plugin on GitHub repo
Plugin 'tpope/vim-fugitive'
" plugin from http://vim-scripts.org/vim/scripts.html
Plugin 'L9'

Plugin 'Valloric/YouCompleteMe'

" All of your Plugins must be added before the following line
call vundle#end()            " required
filetype plugin indent on    " required
" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append `!` to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line

vimrcroot:


" All system-wide defaults are set in $VIMRUNTIME/debian.vim (usually just
" /usr/share/vim/vimcurrent/debian.vim) and sourced by the call to :runtime
" you can find below.  If you wish to change any of those settings, you should
" do it in this file (/etc/vim/vimrc), since debian.vim will be overwritten
" everytime an upgrade of the vim packages is performed.  It is recommended to
" make changes after sourcing debian.vim since it alters the value of the
" 'compatible' option.

" This line should not be removed as it ensures that various options are
" properly set to work with the Vim-related packages available in Debian.
runtime! debian.vim

" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'.  Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible

" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
"syntax on

" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
"set background=dark

" Uncomment the following to have Vim jump to the last position when
" reopening a file
"if has("autocmd")
"  au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
"endif

" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
"if has("autocmd")
"  filetype plugin indent on
"endif

" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd		" Show (partial) command in status line.
"set showmatch		" Show matching brackets.
"set ignorecase		" Do case insensitive matching
"set smartcase		" Do smart case matching
"set incsearch		" Incremental search
"set autowrite		" Automatically save before commands like :next and :make
"set hidden             " Hide buffers when they are abandoned
"set mouse=a		" Enable mouse usage (all modes)

" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif

syntax enable
syntax on
set number
set nocompatible
set backspace=indent,eol,start
set background=dark
set tabstop=2
set expandtab
%retab!
colorscheme solarized

filetype off

注意,在配置完成Vim之前不要打开Vim。


如果你要用clang++来编译含有C++11语法的C++代码,编译时用如下形式:

clang++ --std=c++11 -stdlib=libc++ -lc++abi test.cpp


到这里,GCC 5.4 和 Clang 3.8.1还有一些工具就安装好了,接下来主要配置YouCompleteMe


四:配置YouCompleteMe


安装Vim插件Vundle:

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim


安装.vimrc配置文件中的Vim插件和下载YouCompleteMe(这个过程可能要花较长时间,具体情况根据你的网络质量而定):

vim +PluginInstall +qall

这个过程可能会花很长时间,YouCompleteMe大概有100M左右。

也可以用Git来clone YouCompleteMe:

cd ~/.vim/bundle
git clone https://github.com/Valloric/YouCompleteMe.git
cd YouCompleteMe
git submodule update --init --recursive

用如下命令来编译YouCompleteMe


cd ~
mkdir ycm_build
cd ycm_build
cmake -G "Unix Makefiles" -DEXTERNAL_LIBCLANG_PATH=/usr/local/lib/libclang.so . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp
make -j2

还可以有第二种方法来编译YouCompleteMe:

cd ~/.vim/bundle/YouCompleteMe/
./install.py --clang-completer --system-libclang

应用YouCompleteMe配置文件:

mv ycm_extra_conf.py .ycm_extra_conf.py


.ycm_extra_conf.py的内容为:

# This file is NOT licensed under the GPLv3, which is the license for the rest
# of YouCompleteMe.
#
# Here's the license text for this file:
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>

import os
import ycm_core

# These are the compilation flags that will be used in case there's no
# compilation database set (by default, one is not set).
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-DNDEBUG',
# You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM
# source code needs it.
'-DUSE_CLANG_COMPLETER',
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
# language to use when compiling headers. So it will guess. Badly. So C++
# headers will be compiled as C headers. You don't want that so ALWAYS specify
# a "-std=<something>".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=c++11',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x',
'c++',
'-I',
'/home/guo/Algoritbms/ch-8/',
'-isystem',
'/usr/local/include/c++/v1',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0/x86_64-unknown-linux-gnu',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0/backward',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib/gcc/x86_64-unknown-linux-gnu/5.4.0/include',
'-isystem',
'/usr/local/include',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib/gcc/x86_64-unknown-linux-gnu/5.4.0/include-fixed',
'-isystem',
'/usr/include/x86_64-linux-gnu',
'-isystem',
'/usr/include'
'-isystem',
'../BoostParts',
'-isystem',
# This path will only work on OS X, but extra paths that don't exist are not
# harmful
'/System/Library/Frameworks/Python.framework/Headers',
'-isystem',
'../llvm/include',
'-isystem',
'../llvm/tools/clang/include',
'-I',
'.',
'-I',
'./ClangCompleter',
'-isystem',
'./tests/gmock/gtest',
'-isystem',
'./tests/gmock/gtest/include',
'-isystem',
'./tests/gmock',
'-isystem',
'./tests/gmock/include',
]


# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# You can get CMake to generate this file for you by adding:
#   set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
# to your CMakeLists.txt file.
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
  database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
  database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():
  return os.path.dirname( os.path.abspath( __file__ ) )


def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
  if not working_directory:
    return list( flags )
  new_flags = []
  make_next_absolute = False
  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
  for flag in flags:
    new_flag = flag

    if make_next_absolute:
      make_next_absolute = False
      if not flag.startswith( '/' ):
        new_flag = os.path.join( working_directory, flag )

    for path_flag in path_flags:
      if flag == path_flag:
        make_next_absolute = True
        break

      if flag.startswith( path_flag ):
        path = flag[ len( path_flag ): ]
        new_flag = path_flag + os.path.join( working_directory, path )
        break

    if new_flag:
      new_flags.append( new_flag )
  return new_flags


def IsHeaderFile( filename ):
  extension = os.path.splitext( filename )[ 1 ]
  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]


def GetCompilationInfoForFile( filename ):
  # The compilation_commands.json file generated by CMake does not have entries
  # for header files. So we do our best by asking the db for flags for a
  # corresponding source file, if any. If one exists, the flags for that file
  # should be good enough.
  if IsHeaderFile( filename ):
    basename = os.path.splitext( filename )[ 0 ]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists( replacement_file ):
        compilation_info = database.GetCompilationInfoForFile(
          replacement_file )
        if compilation_info.compiler_flags_:
          return compilation_info
    return None
  return database.GetCompilationInfoForFile( filename )


def FlagsForFile( filename, **kwargs ):
  if database:
    # Bear in mind that compilation_info.compiler_flags_ does NOT return a
    # python list, but a "list-like" StringVec object
    compilation_info = GetCompilationInfoForFile( filename )
    if not compilation_info:
      return None

    final_flags = MakeRelativePathsInFlagsAbsolute(
      compilation_info.compiler_flags_,
      compilation_info.compiler_working_dir_ )

    # NOTE: This is just for YouCompleteMe; it's highly likely that your project
    # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
    # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
    try:
      final_flags.remove( '-stdlib=libc++' )
    except ValueError:
      pass
  else:
    relative_to = DirectoryOfThisScript()
    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

  return { 'flags': final_flags }


配置文件中最重要的部分为:

flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-DNDEBUG',
# You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM
# source code needs it.
'-DUSE_CLANG_COMPLETER',
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
# language to use when compiling headers. So it will guess. Badly. So C++
# headers will be compiled as C headers. You don't want that so ALWAYS specify
# a "-std=<something>".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=c++11',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x',
'c++',
'-I',
'/home/guo/Algoritbms/ch-8/',
'-isystem',
'/usr/local/include/c++/v1',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0/x86_64-unknown-linux-gnu',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/c++/5.4.0/backward',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib/gcc/x86_64-unknown-linux-gnu/5.4.0/include',
'-isystem',
'/usr/local/include',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/include',
'-isystem',
'/usr/lib/gcc/x86_64-linux-gnu/5.4.0/lib/gcc/x86_64-unknown-linux-gnu/5.4.0/include-fixed',
'-isystem',
'/usr/include/x86_64-linux-gnu',
'-isystem',
'/usr/include'
'-isystem',
'../BoostParts',
'-isystem',
# This path will only work on OS X, but extra paths that don't exist are not
# harmful
'/System/Library/Frameworks/Python.framework/Headers',
'-isystem',
'../llvm/include',
'-isystem',
'../llvm/tools/clang/include',
'-I',
'.',
'-I',
'./ClangCompleter',
'-isystem',
'./tests/gmock/gtest',
'-isystem',
'./tests/gmock/gtest/include',
'-isystem',
'./tests/gmock',
'-isystem',
'./tests/gmock/include',
]



这部分是指定YouCompleteMe在补全时依赖的头文件声明,'-I'后面的路径是用户自己的项目头文件路径,'-isystem',后面的路径是系统默认的头文件路径。这里很关键的就是系统默认的头文件路径,可以在用gcc和g++编译自己的C和C++源代码时,加上"-v"选项,然后就会打印出搜索路径,把"搜索从这里开始"到"搜索列表结束"中的路径按照格式添加进去就可以了。注意:如果YouCompleteMe不能对C++代码进行补全,很有可能是没有添加'-isystem',
'/usr/local/include/c++/v1',这一项。

YouCompleteMe是根据头文件来补全的,也就是说它只能补全你源码里#include中的东西和一些基本的关键字,我在Vim的配置文件中配置了用CTL + A进行全局补全,比如printf之类的。

相关文章
相关标签/搜索