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: