The GNU GLOBAL package is highly recommended for using a single tags file, covering all files in all subdirectories, that lives at the base of a source-code tree.
The package comes with gtags.el that integrates it seamlessly into Emacs.
In 2013, GNU ELPA included a package ggtags.el for integrating GNU Global with Emacs, which provides an intuitive UI for navigating between multiple matches along with many other features. Check the project page for full feature list.
The gtags.el package doesn’t cycle through gtags result. Here’s some code for doing it. CyclingGTagsResult
It’s possible to use GNU GLOBAL incremental update feature in after-save-hook in order to keep synchronized the changes you made in source code and gtags database:
(defun gtags-root-dir () "Returns GTAGS root directory or nil if doesn't exist." (with-temp-buffer (if (zerop (call-process "global" nil t nil "-pr")) (buffer-substring (point-min) (1- (point-max))) nil)))
(defun gtags-update () "Make GTAGS incremental update" (call-process "global" nil nil nil "-u"))
(defun gtags-update-hook () (when (gtags-root-dir) (gtags-update)))
(add-hook 'after-save-hook #'gtags-update-hook)
For projects with a huge amount of files, “global -u” can take a very long time to complete. For changes in a single file, we can update the tags with “gtags --single-update” and do it in the background:
(defun gtags-update-single(filename) "Update Gtags database for changes in a single file" (interactive) (start-process "update-gtags" "update-gtags" "bash" "-c" (concat "cd " (gtags-root-dir) " ; gtags --single-update " filename )))
(defun gtags-update-current-file() (interactive) (defvar filename) (setq filename (replace-regexp-in-string (gtags-root-dir) "." (buffer-file-name (current-buffer)))) (gtags-update-single filename) (message "Gtags updated for %s" filename))
(defun gtags-update-hook() "Update GTAGS file incrementally upon saving a file" (when gtags-mode (when (gtags-root-dir) (gtags-update-current-file))))
(add-hook 'after-save-hook 'gtags-update-hook)
If, for whatever reasons, you do not feel comfortable with the interface gtags.el provides, you might try xgtags.el instead. Since its look and feel is more like that of xcscope.el, it differs from gtags.el in several ways:
while using xgtags.el, if you have spaces in the path for sources, you may want to consider to change xgtags--tag-regexp likecedet
(defconst xgtags--file-regexp "\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(.*\\.\\(cpp\\|hpp\\|h\\|c\\|idl\\)\\)[ \t]+\\(.+\\)$" "...")
CEDET (CollectionOfEmacsDevelopmentEnvironmentTools) supports the use of GNU Global as a back-end to some tasks. They include:
GNU Global has a cscope-compatibility utility called “gtags-cscope”. This tool has an identical interface to cscope, so any cscope interface can be used with it. Look at “xcscope.el”, which is on MELPA and in Debian and in Ubuntu. The source is here: https://github.com/dkogan/xcscope.el To use this interface, do (setq cscope-program “gtags-cscope”). This interface has superior support for keeping track of multiple searches, and it’s the best of the bunch, I think.
Comment: would be interesting to see why xcscope.el is the best of the bunch. ggtags.el was created fairly recently out of frustration with all interfaces to gnu global. At the time they usually lacked one thing or another, or difficult to extend. – Leo
Another related package with a most un-original yet very informative name is global-tags.el
Main features are providing an elisp API/library that can be unit tested. Its design is meant to welcome new maintainers through extensibility and maintainability.
For the every day Emacs user, this translates into a package that plugs into Emacs factory-default project (project.el) and tag searching (xref.el) with Tramp support.
It also includes prefetching commonly used queries as “list/search files” and “list/search tag” in the background. This results in a snappier everyday experience.
global-tags.el is currently available in MELPA