cscope, ctags, & vim
cscope, ctags, and Vim are powerful tools for reading a lot of
code. ctags can be used to take you to the definition of a
variable (e.g., a function, variable, or macro). cscope can be
used to take you to the call site of a definition (e.g., all
function calls, all variable uses, all macro uses). These tools
can be used independently of Vim, but having a powerful editor
that can use these tools in an integrated fashion speeds
development.
Theory of cscope, ctags, & vim
Your choice of tool will depend on the language you are developing
in primarily:
-
C: Use cscope + ctags
-
C++ or anything else: Use just ctags. It has the benefit of
knowing about class names, where as cscope does not and will not
know the difference between namespc1::bob and namespc2::bob.
You instruct cscope and ctags to build a database for a directory
tree. These databases are a list of <variable, line_number>
pairs sorted by 'variable'. Vim does a binary search on these
databases to answer your queries (e.g., find definition of
'variable' means searching the database to find the appropriate
variable='variable', then moving the cursor to that line_number).
Vim allows you to specify the order in which it searches its
databases. Typically your list of databases will be ordered as
such:
-
C-kernel: <kernel-cscope>
-
C-user: <ctags-stdlib, cscope-project>
-
C++-user: <ctags-stdlib, ctags-project>
-
other: <ctags-project>
Setting up cscope, ctags, & vim
We first have to build our databases. When you build the database
you want to make sure your repository system ignores the database
files as they are generated and will waste space in your
versioning database (that you won't be able to reclaim). The
running example used here will focus on the Linux kernel using
git.
-
We have two files that we want our repo system (git) to track,
'gentagdb', and 'gentagfiles'. The first script takes a list of
files, and indexes their variables creating the actual ctags and
cscope DBs. The second script generates that list of files.
The second script is important when you have a big project like
the kernel. If you don't exclude redundant files, you will
waste time paging through hundreds of 'write' functions for
strange architectures and irrelevant drivers.
- The first script (gentagfiles). Note when pasting
code into Vim first type ':set paste' so Vim doesn't try
to indent it, then type ':set nopaste' when done.
- #!/bin/bash
- #gentagfiles file list build script
- set -x
- find | grep "\.c$\|\.h$" | grep "\.\/arch\/x86" > cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/fs" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/mm" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/include\/asm-x86" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/include" | grep -v "\.\/include\/asm-" | grep -v "\.\/include\/config\/" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/kernel" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/block" >> cscope.files
- find | grep "\.c$\|\.h$" | grep "\.\/lib" >> cscope.files
- sort cscope.files > cscope.files.sorted
- mv cscope.files.sorted cscope.files
- The second script (gentagdb).
- #!/bin/bash
- #gentagdb database build script
- cscope -b
- ctags -L cscope.files
Now you can build the databases for cscope and ctags. I've
found in practice that running gen* as a make target doesn't
work so well and use it manually. You now have to modify Vim to
support ctags and cscope. Emacs (as far as I know) only
supports ctags, but regardless, I provide only Vim instructions
here. You can use my entire vimrc, or you can just take the
part under "Jeff's cscope settings. My vimrc is the result of
years of Vim tweaking and has some awesome features (pressing
'j' twice equals escape from insert mode).
- Add the desired subset of this
file to your vimrc.
- Make sure 'set csto=0' is included in your vimrc if
you are coding C, and 'set csto=1' is included in your
vimrc if you are coding C++ (see 'Theory' section above
if you want to know why).
Now you are ready to start using it. Simply type ':cs help' to
see the commands right there. Type ':tags' to see where you
currently are in the tag stack. Finally ':tag' will take you to
an arbitrary symbol (and tab-completion works). Try typing
':tag sys_' and the press the Tab key and you should see it try
going through several possible completions. Use Control-\ g to
find the definition of a variable, and Control-\ s to find its
occurrence as a symbol in other code. Use Control-\ c to see
where the symbol is called from. The command 'q:' allows you to
edit the command line history so you can paste large identifier
names into a 'cs find g' command (Ctrl-C exits 'q:' mode).
Conclusions
Good luck. The key to understanding technology is using it. Go
ahead and try to incorporate these scripts into your work process
and you should see a rapid improvement in development speed.
Last updated: Fri Nov 14 15:39:26 EST 2008