xyf问:
请教大哥一个ctags或cscope使用的问题,我的开发工程很大,有上百万行代码,
之前使用sourceinsight,每次编辑代码,会自动更新函数、变量等符号信息,使用vim替换sourceinsight后,每次修改源代码后,如果不手动更新一下tag和cscope.out,相关的跳转就会不正确了,但是更新的话又要很久,请问有没有增量更新tag或cscope.out,或者你是如何解决这个棘手的问题的?谢谢!
这个问题我在写vim使用进阶: 使用标签(tag)文件时也想过,当时在网上查找了很多资料,不过并没有找到一个好的解决方法。后来在开发的过程中,实时更新tag文件和cscope数据库的需求并不强烈,也就放下了。
刚好xyf问这个问题,我把当时我的一些想法写出来,供大家参考。这些都只是初步的想法,没有经过实际的验证。有兴趣的朋友可以试一下,把试验结果反馈给我。
我以Linux系统为例,在windows上应该也能够实现(借助cygwin,以及windows的计划任务)。
其实source insight自动更新函数、变量等信息都是在后台自动进行的,那么我们也可以考虑在后台自动更新tag文件和cscope数据库。
在Linux下,我们可以利用cron守护进程来完成后台自动更新的操作。思路是,让cron进程每隔15分钟(或者更短)扫描一下tag文件和cscope数据创建后发生改变的项目文件,然后为这些项目文件单独生成一个tag文件和cscope数据库。我们知道,在vi里我们可以同时添加多个tag文件和cscope数据库,我们只要把发生改变文件的tags和cscope数据库加到vim里,应该就可以查找、跳转新增的函数了。不过这样做有一个缺点:就是那些修改过的文件,会在vim的tag文件和cscope数据库中出现两次(在原有tag文件中以及新生成的tag文件中),也许会造成使用的不便。
另外,还可以在稍长的时间里(比如一小时)由cron自动为项目中全部文件生成一次tag文件和cscope数据库,并把修改文件的tags和cscope数据库清空。如果担心为全部项目生成tag文件太耗系统资源的话,可以使用Linux中的at守护进程来生成全部文件的tag和cscops数据库,at服务只在系统空闲时才会运行。
下面给一个demo脚本,来自动查找项目中最近改变的文件,并为其生成tag文件和cscope数据库(未经过测试):
#! /bin/sh # This demo script will find the modified files in your project, # and generate a ctags file and cscope database for these files. # This script is NOT tested yet! # by Easwy Yang, 2009/03/29 # vars PRJ_DIR=/home/easwy/prjtest PRJ_TAG_FILE=${PRJ_DIR}/tags PRJ_MOD_TAG_FILE=${PRJ_DIR}/newtags PRJ_MOD_CSCOPE_FILE=${PRJ_DIR}/newcscope.out MOD_FILES=${PRJ_DIR}/mod_files FIND=/usr/bin/find CTAGS=/usr/bin/ctags CSCOPE=/usr/bin/cscope # find modified files # you can modify this command to exclude the object files, etc. ${FIND} ${PRJ_DIR} -type f -newer ${PRJ_TAG_FILE} > ${MOD_FILES} # generate tag file ${CTAGS} -f${PRJ_MOD_TAG_FILE} -L${MOD_FILES} ${CSCOPE} -bq -f${PRJ_MOD_CSCOPE_FILE} -i${MOD_FILES}
在这个脚本里,/home/easwy/prjtest是项目所在的目录,tags文件则是参考文件,在项目目录中修改日期比tags文件更新的文件都会被find命令查找出来,并且为之生成tag文件和cscope数据库。
希望对大家有所帮助,更希望这一块砖头,能引出更好的玉。
你们这些问题,都被解决了,http://www.vim.org/scripts/script.php?script_id=5557
我觉得这个问题是vim唯一比别的商业软件逊色的地方,如果大家有什么好的解决方法,记得通知我,谢谢
lanquan.yang@163.com
@widon
我看了一下GNU Global的介绍,感觉很强大,等有时间了好好研究一下…
使用gnu global,自动更新就非常好实现了,因为支持增量更新
每次修改一个文件就更新一下数据库
在内核里面,这个操作也只要2s的时间
把gtags.vim gtags-cscope.vim移动进plugin
生成数据库的脚本
widon@widon-laptop:~$ cat /usr/local/bin/gt.sh
find . -name “*.[ch]” > gtags.files
gtags
.vimrc里面添加
function! UpdateGtags(f)
let dir = fnamemodify(a:f, ‘:p:h’)
” exe ‘silent !cd ‘ . dir . ‘ && global -u &> /dev/null &’
exec ‘cd ‘ . dir
exec ‘silent !global -u &’
exec ‘cd -‘
endfunction
autocmd BufWritePost *.[ch] call UpdateGtags(expand(”))
let g:GtagsCscope_Auto_Load = 1
let g:GtagsCscope_Auto_Map = 1
let g:GtagsCscope_Absolute_Path = 1
这样就可以完全替代cscope了。。
@karl
我现在的办法,在project顶层放置项目文件如:workspace.vim
在~/.vimrc中
“”””””””””””””””” load project related configuration
” workspace file base name
let s:WorkspaceFileName = “workspace.vim”
function! GetWorkspaceFileName()
let s:current_dir=getcwd()
let s:root_dir=’/’
let l:workspace_file_full_path=”/”
while s:current_dir != s:root_dir
let s:tmp_string=s:current_dir . “/” . s:WorkspaceFileName
if filereadable(s:tmp_string)
let l:workspace_file_full_path=s:tmp_string
break
endif
let s:index=strridx(s:current_dir, “/”)
” if s:current_dir==”/home”, s:index will == 0, but strpart() needs
” length == at least 1 to get ‘/’
if s:index == 0
let s:index=1
endif
” cut string, remove the characters after last ‘/’
let s:current_dir=strpart(s:current_dir, 0, s:index)
endwhile
“return the full path of workspace file if succeeds, otherwise ‘/’
return l:workspace_file_full_path
endfunction
” get full path of workspace file
let s:workspace_file_full_path=GetWorkspaceFileName()
if filereadable(s:workspace_file_full_path)
exec ‘source’ . s:workspace_file_full_path
endif
这样,每次执行vim的时候,会自动寻找并加载项目顶层的workspace.vim
@oldbee, 这个方法很赞,我用向上查找项目文件的方式写了个小插件。
https://code.google.com/p/jiazhoulvke/downloads/detail?name=myproject.vim
好东西呀,谢谢分享出来~~~
@fanhe
ctags文件其实也可以包含时间戳,因为tag文件中每个tag都是可以包含注释的。
发现现在对tag自动更新要求不太高,通常每天更新一次tag就可以满足我的需求了,呵呵
ctags的自动更新是一个很悲剧的问题,就一个tags来说,可以对以文件为单位,检查文件时间戳,如果更改了,就更新那些文件的tags,文本模式的查找替换理论上可以实现,但是貌似tags文件不保存文件时间戳。所以,CodeLite直接放弃文本的tags,采用sqlite3来保存tags信息,也把文件时间戳保存了,所以每次有文件保存的时候,只更新数据库中当前文件的tags,我觉得是很好的一个方案,不过和vim的集成肯定不是太好,这个工作我在做。反正,codelite的tags处理是相当之成功的了。
cscope update:
cscope.out ,好像不支援 append 的功能,如要更新,要全部重做一次。Automatically create and update cscope database提供了一組 Hot-Key,來幫忙不用退出vim,”一指”完成。
Hot-Key如下:
nmap :!find . -iname ‘*.c’ -o -iname ‘*.cpp’ -o -iname ‘*.h’ -o -iname ‘*.hpp’ > cscope.files
\ :!cscope -b -i cscope.files -f cscope.out
\ :cs reset
TagsParser : Automatic tagfile updating and tag viewer
http://www.vim.org/scripts/script.php?script_id=1535
看了博主系列文章,写得很详细,很有感触。关于ctags的自动更新,可以看下官方的TagsParser。下面这些可供参考
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
http://www.vim.org/scripts/script.php?script_id=100
http://www.vim.org/scripts/script.php?script_id=1343
http://stackoverflow.com/questions/155449/vim-auto-generate-ctags
说实在的,我也不知道哪个会更好点
@佳音
我看过这个tips,它每次保存都会更新一下tags,对我这种习惯随手保存的人来说不适用,因为保存时文件可能还不完整。
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file 可以这样配置自动更新
我的做法是写个shell更新tags/cscope.out,在vimrc里面绑定快捷键,需要时直接快捷键更新并自动在当前vim里面读取
是否可以用autocmd来实现?扑捉对文件的写入事件,当对文件有写入动作之后,重新生成Tag。或者直接用一个快捷键,就像IDE里的编译一样,按下键之后,就重新生成了。
又试了一下,可以了,之前可能敲错了。
@karl
taglist中文名的问题我没解决过,一般也很少使用中文做目录名。看看taglist的FAQ吧:
:help taglist-faq
@oldbee
呵呵,和我用的方法一样。
另外,既然本地和远端运行的都是Linux,那么完全可以在RH上起一个gvim,然后把这个gvim显示在你本地Linux上。做法可以参考我的这篇文章使用cygwin X server实现Linux远程桌面 (for windows),虽然是讲cygwin的,不过X serrver的原理都是一样的。
@karl
既然是用ssh登陆运行VIM,那么VIM进程是跑在Server上的,寄存器之类的也是存在Server上,自然没有办法通过VIM寄存器在client上共享剪贴板。
我一般是用terminal的特性,在vim中用shift+鼠标左键拖拽 选定要复制的区域,然后复制(xterm选定后已经自动复制了),到另一个窗口shift+Insert粘贴(vim要在非Normal模式下)。
另外,*和+寄存器只有在图形模式下(gvim)才有。
网上只搜到这哥们的办法:
http://qzone.qq.com/blog/6698756-1218395519
但试了并不好使
虽然运行taglist不报错了,但没有显示函数列表出来
@Easwy
嗯 好
我在UBUNTU下,用SSH登陆上RH AS的主机,使用VIM,没法和系统共享剪贴板,用:reg查看,没有看到*和+寄存器,请问是为什么,应该怎样设才能有*和+两个寄存器?--才能使各个SSH窗口之间通过*和+寄存器进行拷贝?
@karl
脚本其实也很简单的,你:help一下就差不多了
taglist的中文路径问题,好像有人已经解决过了,在网上搜一下吧
vim中不能设置不同大小的字体。
不过我觉得,既然已经选择了vim,要学会适应它的风格,毕竟每个程序都不一样的,不能用一个程序的标准去要求其它的程序,这种先入为主太偏颇了
我更倾向于用这种方法:
还不知脚本怎么写。。。
我看代码关联一般是在si里面看,查找变量在文件中被修改的地方一般在vi中用*#查找。。。
现在有两个问题:
1、windows下的taglist遇到中文路径没法识别
2、上回装了一个srcexpl.vim插件,用着感觉怎么看着就不如SI的关联窗口,后来发现问题所在,在SI中,代码的关联窗口的字体是比代码窗口的字体小一号,而在srcexpl.vim插件中的字体是和主窗口一样大小的。。。有没有办法把字体变小?
@karl
我和Easwy的做法基本一样,在项目根目录下建立一个workspace.vim,然后在.vimrc里面
if filereadable(“workspace.vim”)
source workspace.vim
endif
workspace.vim里放置项目相关配置:path/cscope_db/ctags/lookupfile_tags/DoxygenToolkit_comment/errorformat,以及一些特殊的filetype。
@karl
生成一个绝对路径的tag文件,以及绝对路径的cscope文件,就可以解决你的问题。不过你也许需要在vimrc里设置一下,发现当前目录是项目A的子目录时,使用项目A的tag,否则就用项目B的。
不过我通常都是在项目的根目录下生成整个项目的tag文件/cscope文件,因为使用了lookupfile插件,直接在vim中打开文件已经很方便了,不需要cd到某个目录再打开文件。
在开发过程中我基本上根本不退出vim,在vim里就可以搞定一切,实在不行,就再开一个putty/rxvt终端来做vim里不好做的工作。
是的:)
而且还有一个问题就是:vi要在做tag所在目录为相对目径的情况下,打开源文件,才能用cscope搜定义什么的。。。但我一般都会先切换到下面的子目录去。。。然后再vi xxx.cpp,这样子就会导致没法搜索。不知这个问题有没有解决的办法?
set noautochdir “自动改变当前目录位置autochdir
我用了这个之后,就不会出现你说的那种情况了;但是首次打开vim时最好随便打开一个顶层文件。以初始化当前目录为workdir。
@karl
你是不是想在工程A的目录中时,使用工程A的tag文件,切换到工程B的目录时,使用工程B的tag文件?
你可以试一下vim的project插件
两个不同的工程。。。tag文件如果所有的工程做成一个的话,查找的时候会重复,不准之类的。。。如何在vimrc里针对一个工程的目录配置一个tag文件?
@karl
什么叫不同工程间tag切换?
如果是两个不相关的工程,开两个vim看不就行了
如果是同一个工程,只生成一个大tag文件就可以了
好!
除了这一个问题,还有一个不同工程间tag的切换的问题,vi好像有个tag switch的插件,不过偶还没去看怎么用。。。现在用vi只是用来查找,看代码的关联关系还是在si中方便。。。
@oldbee
是的。
如果再加上cron定时更新tag和cscope的话,应该可以满足大多数人的需求。cron的更新间隔可以根据自己的需要调整。
@Easwy
关于自动更新tag的一点儿想法:
1.cscope是支持增量更新的,cscope.files不变的话,默认参数就是增量。
2.而ctags是不支持增量更新的。但对于支持多tags的编辑器(如VIM),可以考虑分层次的生成多tags,然后根据修改的文件更新(重建)相应的tags即可。可以参考http://ctags.sourceforge.net/faq.html#15
3.最后将文件保存指令和更新tags MAP成一个快捷键。
其实个人对自动更新tags的需求也不是很强,对于一个session,有taglist就行了。做完本地和代码库的同步后,总是会重新建立数据库的,用server也没有觉得慢,而且这点时间可以休息休息眼睛^_^
@alickguo
我似乎也遇到过这样的问题,我记不清是什么原因导致的,好像是因为在vim中切换目录?
遇到这种情况,不必关闭vim,先使用”:cs kill 0″断开和cscope的连接,然后再”:cs add cscope.out”重新连就可以了。
如果总出现这种情况又找不到原因的话,把上面两个命令map成一个快捷键,会使你的困扰小一点。
请教一个Cygwin下vim+cscope的问题.
cscope connecte后过了大概两三小时,再使用cs find 查找时会出现查找失败,vim关闭重开后重新connecte后又恢复了,找了n久没有找到解决方法,错误信息如下:
E262: error reading cscope connection 0
E259: no matches found for cscope query f of ddm_frame.c
vim与cscope的版本信息如下:
$ vim –version
VIM – Vi IMproved 7.2 (2008 Aug 9, compiled Feb 23 2009 13:47:33)
Compiled by alickguo@0kigv8dr4ef5
$ cscope –version
cscope: version 15.6