gtags is a Linux tool that generates a symbol database for source code and then allows searching of those symbols for usage and definition. ggtags is the "plugin" for Emacs that provides an automated frontend to the tool. Some alternatives that have similar functionality to gtags are ctags, etags, and cscope, most of which have their own Emacs plugins.
Notably, many of these tools are not very good at handling large codebases (Linux kernel size and larger) because of the way they store their databases. The Linux kernel for example will generate a 2GB text file when using just gtags, and that file has to be loaded and searched whenever you try to do a symbol lookup. Workarounds exist to resolve this problem (below).
Simple solution
1.Install gtags on your system.
sudo apt-get install global
On a command line you should now be able to run this command and see where it's installed:
which gtags
2.Tell the Emacs ggtags plugin where to find the gtags tool.
Using the path returned by the which gtags
command, add the following line to your ~/.emacs file:
(setq ggtags-executable-directory "/path/to/gtags/parent/dir")
3.Create a gtags database for a code project.
By default ggtags will search upward through the directory tree from the file in which you performed a symbol lookup trying to find a GTAGS file. That GTAGS file (and possibly some associated ones) is your symbol database. If it doesn't find a match for the symbol in the first database file, it will continue searching up the directory tree for additional databases. Matches are prioritized based on file proximity of symbol usage/definition to the file you're doing the lookup in. Generation of this database is called "tagging", and it's usually located at the root of a source tree you want to tag. The gtags tool itself does not do this continuation search since it's passed a path to a specific database, and the native Emacs provided gtags plugin maintains this single-database behavior.
To create a gtags database for a source folder out of Emacs when you're using the ggtags plugin (recommended over the native Emacs gtags plugin), you need to run the command ggtags-create-tags
. The default key-binding for running arbitrary commands in Emacs is M-x, so press that and then type ggtags-create-tags
. It will prompt you for a folder everything should be tagged and the database should be placed, so point it to the top directory of the source folder you want to tag. It will run for a while, possibly quite a while if you have a large source tree, blocking the entire Emacs GUI while it generates the tag database. Once it completes it will get used automatically by ggtags when relevant.
Much better solution
One of the problems with gtags, ctags, etags, and cscope is the size of the databases produced. Since they're tagging where symbols are defined as well as where they're used, you can end up with a database larger than your actual source tree. Very large databases then present the problem of searching them in a reasonable time. Using ggtags with the default Ubuntu gnu-global tool installed produces a very inefficient database format that gets exponentially worse the larger it grows. Mostly this is because Ubuntu is still providing the gnu-global tool from 2008 rather than a modern version, and it's not built to use the much more efficient ctags tools as an underlying framework.
To avoid the problems with gtags and get it to use the more efficient ctags, you need global-6.4 or later, and it needs to be built to point to your ctags installations. The only way I've really found to do this is to build it from source and provide the proper options as well as all the necessary dependent package installations. I ended up writing a shell script to do this installation and setup for me, and I keep it in GitHub with the rest of my emacs configuration and installation scripts. You can get it from https://github.com/mtalexan/emacs-settings/blob/master/global_install.sh.
You'll need to set a few things in your ~/.emacs to make full use of this:
(setq ggtags-use-idutils t)
(setq ggtags-use-project-gtagsconf nil)
This enables the use of the very efficient idutils sub-package, and makes sure gtags calls use your global settings for gtags that you've now compiled in.
How to use gtags/ggtags/helm-gtags
I personally use ggtags and not helm-gtags or gtags. Emacs provides a default gtags "plugin", but it has a much worse interface than ggtags and will only search a single database. I use helm regularly for most things, but I like my ggtags interface separated from my helm interface when I'm parsing matches so I don't use helm-gtags. Also helm-gtags is pretty slow if your gtags database is large.
For ggtags you need to set ggtags-mode for it to be useful. This can be done by adding it to automatically trigger on c-mode by adding something like the following to your .emacs file
(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
(ggtags-mode 1))))
Alternatively you can set it to always be enabled by instead using a line like this:
(setq ggtags-global-mode 1)
Settings I recommend if you're going to be using a large codebase require the following lines in your ~/.emacs file:
; Allow very large database files
(setq ggtags-oversize-limit 104857600)
(setq ggtags-sort-by-nearness t)
When browsing the code, the most common things I do are to follow a symbol underneath my cursor, find all uses of a symbol underneath my cursor, and occasionally to do a symbol lookup unrelated to where my cursor is. These correspond to the commands: ggtags-find-tag-dwim
and ggtags-find-reference
. These commands operate on a point (your Emacs cursor position) but will open a prompt for you to enter a symbol when there is no symbol under your point or when they're called from M-x.
When you run ggtags-find-tag-dwim
it can do a number of things best understood by playing with it, but generally will jump to a match when there's only one match (equivalent that doesn't auto-jump is ggtags-find-tag
) or will open a side windows like ggtags-find-reference
with a list of possible matches that includes the file, line number, and some context for it where each entry is clickable to jump directly there.
Be careful when that window is open, it puts you in a special minor mode that means the up and down keys will switch between matches until you press Enter to officially select a match.
Conveniently when you select a match your tag-mark is left behind. This means you can use the command pop-tag-mark
to jump back to the last place you were at. tag-mark is a stack of tag-marks, so you can repeatedly look up symbols and will always be able to go back to each location prior to following a lookup.
If you want to just do a manual lookup rather than one based on the symbol at the point, there are some ggtags functions that operate like ggtags-find-tag-dwim
, but prompt you for the symbol in the minibuffer. ggtags-find-tag-dwim
will do this as well if there is no symbol under the point.