Vim: Using Ctags to View function definitions across files..

Blog Name: Generate Ctags Files for C/C++ Source Files and All of Their Included Header Files

This post is for those people who use Exuberant Ctags. If you are using other versions of ctags, this post may not be useful. HOWEVER, I USE CTAGS-5.8, compiled with wildcards & regex, WITH NO PROBLEM AT ALL! DOWNLOAD SITE is here.

When using ctags to generate the tags file for C/C++ projects, usually we use the following command:

ctags -R .  #Note that the -R means to generate tags recursively.. very nice..

For some users that need more info of the symbols, they may use this command instead:

ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .

No matter which one you use, the generated tags file only contains the symbols in the files in your project source tree, but not any external file, such as standard header files (e.g. stdio.h, stdlib.h), etc. thus editors or IDEs that use tags files, such as Vim, are not able to locate symbols in external header files. There was a solution: generate a tags file for any external header files first, and let the editor or IDE read both the generated tags file and the tags file for the project source tree. For example, the following command will generate a tags file for all your system header files on UNIX/Linux:

ctags -R --c++-kinds=+p --fields=+iaS --extra=+q /usr/include

This command usually takes a very long time to finish, and finally it gives a quite large tags file, which causes the editor or IDE a long time to search this tags file for symbols. To solve this problem, I came up with another idea.

Why must we generate a tags file containing all the symbols in the system header? If we only generate the tags file only for the header files that are related to our projects, would it be faster? That's the point of this idea. We could first search for the header files that are included in our projects, and then we use ctags to generate a tags file for these files and our source files, in this way, a much smaller tags file that containing all the symbols that maybe useful for the project is generated.

To do this, I wrote a shell script ctags_with_dep.sh:

#!/bin/bash

# ./ctags_with_dep.sh file1.c file2.c ... to generate a tags file for these files.

gcc -M $* | sed -e 's/[\\ ]/\n/g' | \
        sed -e '/^$/d' -e '/\.o:[ \t]*$/d' | \
        ctags -L - --c++-kinds=+p --fields=+iaS --extra=+q

This script is also available on github gist. If you only want to use it, download the script and use the following command to generate the tags file:

./ctags_with_dep.sh file1.c file2.c file3.cpp ...

Read on if you want to know what's happening here. This script will first use gcc -M to output the list of header files that are included in our C or C++ source files. However, the output could not be directly used by ctags, thus this script uses sed commands to filter the output. Finally, this script uses a pipe to put the file list to the stdin of the ctags program -- ctags will read the file list from stdin if -L - is passed to it on the command line.

What if you have other directories besides the standard /usr/include that containing the header files you need? You could do a little modification on this script. For example, you have some header files in ~/include, then you could pass -I ~/include to the gcc command. Just like below:

    gcc -M -I ~/include $* | sed -e 's/[\\ ]/\n/g' | \
            sed -e '/^$/d' -e '/\.o:[ \t]*$/d' | \
            ctags -L - --c++-kinds=+p --fields=+iaS --extra=+q

 Whatever, put the generated ctags file with the file. press <c-]> and it will jump to definitions of functions, unless the function is a dynamic-library-function, or function is not defined in a formal style like : __attribute__((..))

 

And try with cscope(cscove) with ctags, might be a good job.

Plugin 'brookhong/cscope'

Plugin 'szw/vim-ctags'

nnoremap <leader>fs,fd(change fg to fd),t,fa

before using 'gf', add to vimrc:

set path+=header path

 

steps: <c-]>,<leader>fd,<leader>fs

 

use ctags to find defs, use cscope to find the refs. perfect!

 

Because ctags is a little hard to use.

here is another instruction..

Actually it is me not knowing the way to use it makes it hard to use..

Generate ctags by passing the real address, and put the generated tags into each folder..

the order is important also.

   ctags在linux下的作用我就不再赘述了,这里是刚刚看到的一篇文章,是一些使用的ctags细节。
      转自:  http://blog.chinaunix.net/uid-20874550-id-2412585.html (此贴也是转载的   peakflys注)

ctags 在使用vim编程和浏览代码是非常有用。可以用CTRL+]和CTRL+t 来回跳转关键字(peakflys注:在有些环境下CTRL+] 快捷键不出现同名跳转列表,而是直接跳转到查找到的第一条记录,此时可以使用g+]代替  ) 。
先生成自己工作目录的tags。最简单粗暴用法:

$cd yourwork $ctags -R *

这样会生成一个tags文件。
不过,这种有个问题,成员变量没有包含在里面。所以自动完成对象的成员时没有提示。
解决办法:

$ctags -R --fields=+iaS --extra=+q *

–fields=[+|-]flags
–fields指定tags的可用扩展域(extension fields),以包含到tags入口。
i:继承信息Inheritance information
a:类成员的访问控制信息 Access (or export) of class members
S: 常规签名信息,如原型或参数表 Signature of routine(e.g. prototype or parameter list)
–extra=[+|-]flags
指定是否包含某种扩展信息到tags入口。
q:包含类成员信息(如c++,java,Eiffel)。
但就算是C 语言的结构,也需要这两个参数设置才能获取成员信息。

这样就能自动完成结构和类的成员了。

但是,对于系统的函数,还是没有跳转。如socket定义,inetaddr_in这样的结构没有自动变量完成。
最简单做法:

$ctags --fields=+iaS --extra=+q -R -f ~/.vim/systags /usr/include /usr/local/include

然后在.vimrc里设置

set tags+=~/.vim/systags

这样虽然基本能跳转到系统函数定义,一个问题是某些系统函数并没有加入到systags里。
如/usr/incluce/socket.h的socket系列函数,memset等很多关键函数都没有到tag里:

extern int listen (int __fd, int __n) __THROW;

这是因为 __THROW的宏定义让ctags不再认为该系列函数是函数。
同理,如memcpy系列函数:
如/usr/include/string.h的

extern int strcmp (__const char *__s1, __const char *__s2)      __THROW __attribute_pure__ __nonnull ((1, 2));

还有attribute_pure ,nonull等属性,都需要忽略。如果需要#if 0里面的定义,可以–if0=yes来忽略 #if 0这样的定义。

$ctags -I __THROW -I __attribute_pure__ -I __nonnull -I __attribute__ --file-scope=yes --langmap=c:+.h --languages=c,c++ --links=yes --c-kinds=+p --c++-kinds=+p --fields=+iaS --extra=+q -R -f ~/.vim/systags /usr/include /usr/local/include

这样.vim/systags里面是全的,但内容过多。一个函数定义的跳转,会有几十个候选。这时我们可以简化一下,将-R去掉,自己指定目录:

$ctags -I __THROW -I __attribute_pure__ -I __nonnull -I __attribute__ --file-scope=yes --langmap=c:+.h --languages=c,c++ --links=yes --c-kinds=+p --c++-kinds=+p --fields=+iaS --extra=+q  -f ~/.vim/systags /usr/include/* /usr/include/sys/* /usr/include/bits/*  /usr/include/netinet/* /usr/include/arpa/* /usr/include/mysql/*

还可以包含一些自己编程需要的路径。注意后面加*号。
这样生成的系统tags就少多了。不会有太多不相干的定义。


(peakflys补充:tags有一个小技巧,在vimrc文件中set tags=tags; (注意有分号),在vi中使用定位快捷键时会先在当前目录中查找tags文件,找不到的话,就会到父目录中找,依次类推,这样 你在编辑一个大工程时,只需要在最上一层建立一个tags文件,之后可以任意切换到工程子目录里去操作!) 这句话有副作用。具体原因不清楚,总之不要偷懒!要把tags文件复制到最底层。

posted on 2016-07-19 11:41  三叁  阅读(247)  评论(0)    收藏  举报

导航