來源:使用ctags和OmniCppComplete-taglist- cscope-global http://blog.chinaunix.net/uid-11770217-id-323264.html
代碼自動補全和代碼跳轉閱讀,應該是作為程式員最常用的功能之一了,具體二者是指什麼我就不解釋了。微軟的Visual Studio就是靠這兩樣必殺技牢牢佔據著廣大windows程式員的心(這裡面要有強大的VS外掛程式Visual Assistant X一份功勞)。。。但是Linux程式員其實更幸福,不花錢就能搞定這兩大功能。
從本質上說,這二者的實現都依賴於一樣東西:tag。tag就是程式中的關鍵詞,在C++中主要包括:變數、函數名、類名等。代碼自動補全實際上是tag的匹配(例如,程式員輸入cla時,由於存在class這個c++的tag,就可以用class匹配cla);代碼跳轉閱讀實際上是tag的尋找(例如,程式員要尋找一個函數func(),只需要在別的檔案中尋找這個func這個tag的位置即可)。
【準備】
我現在的系統是Ubuntu Desktop 10.04 LTS版本。當然,一切工作的前提是你能上網,而且配置好了一個可用的源。
1. 安裝Vim和Vim基本外掛程式
我們需要首先安裝好Vim和Vim的基本外掛程式。這些使用apt-get安裝即可:
sudo apt-get install vim vim-doc vim-scripts
其中vim-scripts是vim的一些基本外掛程式,包括文法高亮的支援、縮排等等。
2. Vim設定檔
Vim強大的功能,其來源基本上就兩個地方:外掛程式,以及設定檔。
上面已經下載了Vim的基本外掛程式,下面說一下Vim的基本配置。Vim本身的系統設定檔夾是在/usr/share/vim/和/etc/vim/兩個檔案夾下,我們一般不要去改變這些,改了以後不容易恢複。我們需要在使用者檔案夾下建立自己的設定檔。假設使用者的名字是user。進入使用者檔案夾(/home/user/)之後,用gedit建立一個名叫.vimrc的檔案:
3. ctags安裝和使用
在這裡下載ctags:http://sourceforge.net/projects/ctags/files/
或者
sudo apt-get install exuberant-ctags (不能是emacs的ctags)(建議使用這個)
ctags的作用就是把c/c++檔案分割成tag,並預設儲存在一個叫tags的檔案中。假設我們現在有一些.h/.c/.cpp檔案在/home/user/code/檔案夾下,那麼在這個檔案夾下執行下面的命令就能產生此項目的tags檔案:
ctags -R --c++-kinds=+p --fields=+iaS --extra=+q
此時在這個目錄下就能找到一個叫tags的檔案了。
4. 代碼跳轉
經過上面的步驟之後,就可以在本項目內實現代碼跳轉了,但不能跳轉到不是在本項目的代碼中定義的tag。例如在上面的圖中,本地定義了一個類A,在main函數中定義了一個A類的對象,我們可以按“Ctrl+]”按鍵組合跳轉到class A那一行。然後可以按“Ctrl+O”跳回來。
如果想實現跳轉到非本項目的tag,則必須讓Vim知道這些tag在哪。剛才的項目在/home/user/code/目錄下,現在假設又有一個項目在/home/user/program/下,那麼我們需要在此項目下產生program這個項目的tags檔案(還是用上面的ctags命令)。
產生之後,要告知Vim,需要在Vim的設定檔中(/home/user/.vimrc)添加下面的內容:
" -- ctags setting --set tags=tagsset tags+=./tags " add current directory's generated tags fileset tags+=~/program/tags " add new tags file
最後一行就表示在搜尋tags檔案的時候,也要搜尋/home/user/program/檔案夾下的tags檔案。儲存以後重啟,此時應該就能實現不同項目間的跳轉了。這是因為我們經常會基於一些庫開發軟體,我們需要查看庫中函數或者類的定義的時候,會經常需要此功能。
5. 自動補全的安裝
自動補全功能的實現,可以通過一個Vim外掛程式實現:OmniCppComplete。可以在這裡下載到:http://www.vim.org/scripts/script.php?script_id=1520
這個外掛程式是基於ctags資料庫即tags檔案實現的。
上面我們也介紹了如何獨立於系統設定檔之外,建立自己的Vim設定檔。當我們自己下載Vim外掛程式的時候,也可以另外建立目錄,放置我們自己的外掛程式。這個目錄一般為/home/user/.vim,另外還需要建立一個外掛程式子目錄,一個外掛程式文檔子目錄,以上的可以進入/home/user目錄下通過下面的命令執行:
mkdir .vimcd .vimmkdir pluginmkdir doc
然後將下載到的zip檔案放到.vim目錄下,直接解壓(外掛程式也包括兩個目錄,一個plugin,一個doc,所以它會自動放置到對應的目錄)。
注意,我在ubuntu10.10把omnicppcomplete-0.41.zip解壓後有三個檔案夾:after, autoload, doc我直接把這三個檔案夾放在 .vim這個檔案夾下,並沒有放在plugin檔案夾裡面,因為我把這三個檔案夾放在plugin檔案夾下面開啟vim也就是用vim編輯一個檔案的時候會又出錯資訊,但是放在 .vim也可以正常自動補全,兩種方法都試一下看看。
unzip omnicppcomplete-0.41.zip
外掛程式這就算安裝完了。然後再到vim設定檔中加入如下的配置:
"-- omnicppcomplete setting --set completeopt=menu,menuonelet OmniCpp_MayCompleteDot = 1 " autocomplete with .let OmniCpp_MayCompleteArrow = 1 " autocomplete with ->let OmniCpp_MayCompleteScope
= 1 " autocomplete with ::let OmniCpp_SelectFirstItem = 2 " select first item (but don't insert)let OmniCpp_NamespaceSearch = 2 " search namespaces in this and included fileslet OmniCpp_ShowPrototypeInAbbr = 1 " show function prototype in popup windowlet OmniCpp_GlobalScopeSearch=1let
OmniCpp_DisplayMode=1let OmniCpp_DefaultNamespaces=["std"]
(前幾行就是提供了C++中的./->/::等操作符的提示和自動完成)。
6. 自動補全功能的測試
C++開發中經常會用到C++標準庫的代碼,因此STL的自動補全很重要。可以下載一份C++標準庫的原始碼來測試一下自動補全功能。
sudo apt-get install build-essential
然後在/usr/include/c++下就可以找到標準庫的標頭檔了。在此檔案夾下產生tags檔案,並添加到vim的設定檔中(不再重複上面的內容),然後在編程的時候就可以使用自動補全功能了。
我直接把/usr/include/下的所有檔案都做了ctags,也就是說如果你想把哪個類庫加入到vim的代碼提示功能下面,你只需要在這個類庫的最底層檔案夾下面執行 ctags -R --c++-kinds=+p --fields=+iaS --extra=+q ,這時候會在這個檔案夾下面產生一個tags檔案,然後把這個tags檔案加入到/home/user/.vimrc設定檔中(請參考上面)
下面展示了一張vector的函數補全的:
PS:在自動補全的點,Vim必須知道可能補全的定義。比如說,在namespace std命名空間下的變數和函數,必須要用using namespace std;暴露出來,否則是不能補全的。在.cpp檔案中還可以,在.h檔案中這樣就不是好的做法了。暫時不知道這個問題是由於我自己配置錯誤還是程式沒有實現。
以上引用自:http://xiaozhi.de/2010/code-auto-complete-and-jump-to-under-vim
1.其他的VIM外掛程式的功能和使用:
taglist 精幹,需要ctags的支撐 ,直接可以在左邊列出函數列表,全域參數列表。(可以排序)
cscope 比較強大,可以對函數以及部分類型定義進行跳轉,但有些BUG,好像在某些條件下無法正確找到分析枚舉的定義。也就是查看你所使用的類型的定義。
global新版本可以嵌入vim使用,提供比較完整解析和類型索引,和cscope比,稍微差些的就是對類型引用的列印列表中沒有標識這個引用在什麼函數中進行的。其實我的感覺global可能不是為vim所生,它的主要目的是用html的方式進行表達相關的關聯關係和索引,使用起來感覺沒有cscope的那麼貼切。
cscope和global都是查看你所使用的類型的定義。以上已經說出了兩者的區別。
大家可以根據自己的需求和實際情況進行安裝,以上的外掛程式都是基於ctags的基礎上的,因此必須先裝ctags再裝其他外掛程式。
2、相關的擴充的安裝
代碼
apt-get install exuberant-ctags cscope global
cppcomplete 和 taglist 要到www.vim.org的擴充列表中下載。
taglist 的:
http://www.vim.org/scripts/script.php?script_id=273
cppcomplete 的:
http://www.vim.org/scripts/script.php?script_id=527
然後在 建立目錄
代碼
$HOME/.vim/plugin
將下載的cppcomplete.vim 和 taglist.vim拷貝到$HOME/.vim/plugin中。
安裝了global後,最新4.8.6 以上版本有帶vim的擴充,將它也拷貝到 $HOME/.vim/plugin
debian sid 版本global安裝後擴充檔案在
代碼
/usr/share/doc/global/examples/gtags.vim.gz
需要拷貝到$HOME/.vim/plugin後解壓,解壓方法:
代碼
gzip -d gtags.vim.gz
3、使用這些工具
1)準備工作,先修改一下$HOME/.vimrc檔案
為了更好的使用cscope請添加如下內容,這樣Ctrl-]的跳轉將由cscope的tags進行分析。
代碼
if has("cscope")
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
" add any database in current directory
if filereadable("cscope.out")
cs add cscope.out
" else add database pointed to by environment
elseif $CSCOPE_DB != ""
cs add $CSCOPE_DB
endif
set csverb
set cscopetag
set cscopequickfix=s-,g-,c-,d-,t-,e-,f-,i-
endif
2)使用cscope
cscope的tag產生最簡單的方法是:
c中:cscope -Rbq
在你的開發工程的最上層目錄執行cscope-indexer,它會遍曆下面的所有目錄,產生兩個檔案,一個是cscope.files,這個檔案記錄需要產生tags的檔案名稱,可以手工修改,另一個是cscope格式的tags檔案cscope.out。
c++中使用cscope
-R: 在產生索引檔案時,搜尋子目錄樹中的代碼
-b: 只產生索引檔案,不進入cscope的介面
-k: 在產生索引檔案時,不搜尋/usr/include目錄
-q: 產生cscope.in.out和cscope.po.out檔案,加快cscope的索引速度
#!/bin/sh
find . -name "*.h" -o -name "*.c" -o -name "*.cc" -name "*.cpp" > cscope.files
cscope -bkq -i cscope.files
ctags -R
完成後,你在產生了cscope.out的目錄開啟工程的任意檔案,就可以使用Ctrl-]跳轉尋找類型定義了。
代碼
進入vim後第一件事是要把剛才產生的cscope檔案匯入到vim中來, 用下面的命令:
:cs add /home/wooin/vim71/cscope.out /home/wooin/vim71
上面這條命令很重要, 必須寫全, 不能唯寫前半句:
:cs add /home/wooin/vim71/cscope.out
cs f s xxxx 尋找xxxx出現的地方,它能詳細列出哪些檔案的哪行的哪個函數引用,以及該行的內容,比較不錯
cscope find的用法:
cs find c|d|e|f|g|i|s|t name
0 或 s 尋找本 C 符號(可以跳過注釋)
1 或 g 尋找本定義
2 或 d 尋找本函數調用的函數
3 或 c 尋找調用本函數的函數
4 或 t 尋找本字串
6 或 e 尋找本 egrep 模式
7 或 f 尋找本檔案
8 或 i 尋找包含本檔案的檔案
cscope find得捷徑:
添加到~/.vimrc中, 並重啟vim:
nmap <C-c><C-k> :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-c><C-g> :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-c><C-l> :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-c><C-t> :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-c><C-e> :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-c><C-f> :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-c><C-i> :cs find i ^<C-R>=expand("<cfile>")<CR><CR>
nmap <C-c><C-d> :cs find d <C-R>=expand("<cword>")<CR><CR>
它的所有命令的使用請參考:
代碼
help cscope
3)使用taglist
taglist的功能是即時產生當前檔案的函數列表和全域變數列表,便於索引。
在vim中命令模式下使用
Tlist 開啟或者關閉當前檔案的索引;
TlistSync 立即在開啟的索引視窗中定位當前的游標所在位置屬於哪個函數或者結構定義中。
還有其他命令,請參考它的協助檔案。
4)ctags的使用
其實cscope是用來替代ctags功能的,ctags的應用廣泛,還有其他很多的軟體依賴它。
例如要產生cppcomplete需要的tags檔案的話,需要運行下面的命令:
代碼
ctags -n -f cppcomplete.tags --fields=+ai --C++-types=+p * -L cscope.files
注意,我在最後使用了參數"-L cscope.files" 這僅僅是借用拉cscope產生的檔案索引來協助ctags去查詢相關工程檔案產生tags。
5)使用cppcomplete
cppcomplete的使用我只是簡單的發現它可以根據上述方法產生的tags檔案來自動補全類型成員。
使用很簡單,就是在你需要補全類型成員時,按F8鍵就可以拉。它一般第一次使用時,需要讓你確認是使用已有的tags檔案還是再產生一次。一般我們自己控制產生tags檔案的時機,它就使用就行拉。
但它也受到ctags的分析能力比較差的限制,可能不是每次都能幫到你。
6)使用global
在工程的最上層目錄執行命令:
gtags
等待它完成所有需要的global自己格式的tags的產生
產生完後,需要的就是在產生tags的目錄開啟你的工程的任意檔案,用如下命令查詢相互關聯類型引用和關聯關係:
代碼
Gtags xxxx 尋找xxxx的定義
Gtags -r xxxx 尋找xxxx的引用
Gtags -s xxxx 尋找xxxx出現的地方
它的提示資訊很有顯,不如cscope更直觀,但對大型分析的比較完整。
有時它無法正常分析的類型 可以試試用帶-s 的參數的方式找找類型定義。再不行,我就不清楚拉 smile.gif
indent -kr -nut -ts2 -i3 -l-1 *.c
valgrind --leak-check=full --leak-resolution=high --show-reachable=yes
在你的開發工程的最上層目錄執行cscope-indexer
ctags -n -f cppcomplete.tags --fields=+ai --C++-types=+p * -L cscope.files
:!ctags -R
Tlist 開啟或者關閉當前檔案的索引;
TlistSync 立即在開啟的索引視窗中定位當前的游標所在位置屬於哪個函數或者結構定義中。
u 更新taglist視窗中的tag
s 更改排序方式,在按名字排序和按出現順序排序間切換
[[ 跳到前一個檔案
]] 跳到後一個檔案
將游標停放在函數或者變數的位置,gd會高亮出當前檔案中所有的函數或者變數,按n查看下一個
gg游標返回到檔案的頂部
ctrl + p : 自動匹配 補齊
ctrl +] :跳轉 ctrl + T : 返回跳轉
把游標移到"stdio.h"的任一字元上,鍵入"gf",則Vim會自動開啟/usr/include/stdio.h檔案。使用"Ctrl-O" 可返回到原先的檔案中。
"cscope find"的用法:
cs find c|d|e|f|g|i|s|t name
0 或 s 尋找本 C 符號(可以跳過注釋)
1 或 g 尋找本定義
2 或 d 尋找本函數調用的函數
3 或 c 尋找調用本函數的函數
4 或 t 尋找本字串
6 或 e 尋找本 egrep 模式
7 或 f 尋找本檔案
8 或 i 尋找包含本檔案的檔案
:cw 在視窗中顯示
vim :
複製5行: y5y , p
游標在單詞間移動 w b
行移動: 0(行首) $(行尾)
分割視窗: :split 切換 ctrl + w
向下滾屏: ctrl +D ctrl +u
替換 : %s/four/4/g
刪除多行 n dd