作者:winterTTr 转载请注明
我想,很多人都希望能够在vim或者emacs中实现C++的自动补全,我个人也不例外。
折腾过ctags,etags,cscope,最后也折腾过cedet。说实话,cedet还是可以实现补全的,只是速度有点让人难以忍受。
上面的几种工具,都是通过对源代码进行预处理,分析出其包含的代码信息。但是,大部分程序都是通过静态分析代码,这点在代码或者头文件频繁变更的情况下,是非常让人头痛的事情。像Visual Stuido中代码补全功能,基本上全是动态的,当头文件发生变化后,补全也会马上跟着变化。
我们是否也能实现这样的功能呢?
在clang这个llvm的C++前端出现之前,或许只能说遗憾了。静态的ctags补全必须完全扫描所有的文件,这样的效率是不可以接受的。
不过现在有了clang,这为我们系提供了非常好的工具,来实现这个愿望。
准备工作
1. 不用说了,肯定是需要clang了。
clang需要自己编译。由于我使用的是windows,所以,这里有一个我自己编译的版本。
https://github.com/winterTTr/emacs-of-winterTTr/tree/master/.emacs.d/extra-bin/clang
有关环境的设置,可以参考上篇文章。
- (wttr/prepend-to-exec-path "~/.emacs.d/extra-bin/clang")
(wttr/prepend-to-exec-path "~/.emacs.d/extra-bin/clang")
2. auto-complete和auto-complete-clang.el
auto-complete是一个非常好用的emacs扩展,而auto-complete-clang就是在这个扩展的基础上完成的。所以两者必须同时安装:
这里是我现在正在使用的auto-complete扩展,已经包含了clang。
https://github.com/winterTTr/emacs-of-winterTTr/tree/master/.emacs.d/plugins/auto-complete-1.3.1
配置
首先是加载auto-complete扩展:
- ;; 加载auto-complete
- (wttr/prepend-to-load-path "~/.emacs.d/plugins/auto-complete-1.3.1")
- (require 'pos-tip)
- (require 'auto-complete)
- (require 'auto-complete-config)
- (add-to-list 'ac-dictionary-directories "~/.emacs.d/plugins/auto-complete-1.3.1/dict")
- (ac-config-default)
- (global-auto-complete-mode t)
- ;; 使用Ctrl+enter按键触发自动补全
- (define-key ac-mode-map [(control return)] 'auto-complete)
;; 加载auto-complete
(wttr/prepend-to-load-path "~/.emacs.d/plugins/auto-complete-1.3.1")
(require 'pos-tip)
(require 'auto-complete)
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/plugins/auto-complete-1.3.1/dict")
(ac-config-default)
(global-auto-complete-mode t)
;; 使用Ctrl+enter按键触发自动补全
(define-key ac-mode-map [(control return)] 'auto-complete)
下面设置auto-complete-clang
- ;; 加载clang
- (require 'auto-complete-clang)
- ;; 添加c-mode和c++-mode的hook,开启auto-complete的clang扩展
- (defun wttr/ac-cc-mode-setup ()
- (make-local-variable 'ac-auto-start)
- (setq ac-auto-start nil) ;auto complete using clang is CPU sensitive
- (setq ac-sources (append '(ac-source-clang ac-source-yasnippet) ac-sources)))
- (add-hook 'c-mode-hook 'wttr/ac-cc-mode-setup)
- (add-hook 'c++-mode-hook 'wttr/ac-cc-mode-setup)
;; 加载clang
(require 'auto-complete-clang)
;; 添加c-mode和c++-mode的hook,开启auto-complete的clang扩展
(defun wttr/ac-cc-mode-setup ()
(make-local-variable 'ac-auto-start)
(setq ac-auto-start nil) ;auto complete using clang is CPU sensitive
(setq ac-sources (append '(ac-source-clang ac-source-yasnippet) ac-sources)))
(add-hook 'c-mode-hook 'wttr/ac-cc-mode-setup)
(add-hook 'c++-mode-hook 'wttr/ac-cc-mode-setup)
添加系统头文件的目录,这点非常重要,clang就是通过ac-clang-flags这个变量中的设置,来正确找到所有的系统头文件的。
但是请注意,不是添加头文件,是添加头文件的*目录*。
其实,这个变量就是命令行中clang所能接受的参数,-IPath代表include这个Path路径作为系统头文件路径。-DSome表示定义Some这个宏。
我想使用过gcc的人都了解,这个是编译器的命令行参数。
我使用windows下的mingw的头文件路径,所以设置如下:
- (setq ac-clang-flags (list
- "-IC:/MinGW/include"
- "-IC:/MinGW/lib/gcc/mingw32/4.6.1/include"
- "-IC:/MinGW/lib/gcc/mingw32/4.6.1/include/c++"
- "-IC:/MinGW/lib/gcc/mingw32/4.6.1/include/c++/mingw32"
- "-D__MSVCRT__="))
(setq ac-clang-flags (list
"-IC:/MinGW/include"
"-IC:/MinGW/lib/gcc/mingw32/4.6.1/include"
"-IC:/MinGW/lib/gcc/mingw32/4.6.1/include/c++"
"-IC:/MinGW/lib/gcc/mingw32/4.6.1/include/c++/mingw32"
"-D__MSVCRT__="))
好了,现在开启一个test.cpp文件可以试一下,由于我的设置,补全通过ctrl-enter触发。
不止能补全函数,还能补全参数,auto-complete是个非常好的框架。
PS:
wttr开头是所有的函数,是我自己定义的,可以参考这里。
https://github.com/winterTTr/emacs-of-winterTTr/blob/master/.emacs.d/wttr-config/wttr-utils.el