There are several tools to create a tags file. The two dominant tools are etags and ExuberantCtags. Etags comes with Emacs and ExuberantCtags is separate but available on most systems. ExuberantCtags is the better choice as it supports more languages and is more robust.

ExuberantCtags is no longer being maintained, but a fork, UniversalCtags is being actively developed.

Using UniversalCtags/ExuberantCtags

To use ctags with emacs, you must supply the ‘-e’ parameter to instruct ctags to generate an emacs tag file. The commands below are often sourced into a Makefile and then run with a CompileCommand.

  cd /path/to/my/project
  ctags -e myfile.cpp

Ctags also has a recursive option, ‘-R’. This is the most common (and simple) usage. To generate tags for all files that ctags recognizes, simply execute this from the terminal:

  cd /path/to/my/project
  ctags -e -R .

You can filter it to specific extensions if needed:

  cd /path/to/my/project
  ctags -e -R *.cpp *.hpp *.h

If you use macports on macOS, universal ctags are installed as uctags.

From within Emacs

Put this in your init file:

  (setq path-to-ctags "/opt/local/bin/ctags") ;; <- your ctags path here
  (defun create-tags (dir-name)
    "Create tags file."
    (interactive "DDirectory: ")
     (format "%s -f TAGS -e -R %s" path-to-ctags (directory-file-name dir-name)))

Then, once it has been evaluated, you can invoke it via ‘m-x create-tags’

Using etags

First, see a list of languages supported by etags by running ‘etags --help’.

To generate tags for certain source files (like *.el files), invoke this:

  cd /path/to/my/project
  etags *.el

To recurse through directories, run something like this:

  cd /path/to/my/project
  find . -type f -iname "*.[ch]" | etags -

FYI: If you want to use ‘xargs’ with ‘etags’, you have to use the --append flag (e.g. find . -type f -iname "*.[ch]" | xargs etags --append). Otherwise, etags will overwrite the tags file for each file it gets from xargs.

From within emacs

Put this in your init file:

  (defun create-tags (dir-name)
     "Create tags file."
     (interactive "DDirectory: ")
      (format "find %s -type f -name \"*.[ch]\" | etags -" dir-name)))

Auto refresh of the tags file

  ;;;  Jonas.Jarnestrom<at> A smarter               
  ;;;  find-tag that automagically reruns etags when it cant find a               
  ;;;  requested item and then makes a new try to locate it.                      
  ;;;  Fri Mar 15 09:52:14 2002    
  (defadvice find-tag (around refresh-etags activate)
   "Rerun etags and reload tags if tag not found and redo find-tag.              
   If buffer is modified, ask about save before running etags."
  (let ((extension (file-name-extension (buffer-file-name))))
    (condition-case err
      (error (and (buffer-modified-p)
          (not (ding))
          (y-or-n-p "Buffer is modified, save it? ")
         (er-refresh-etags extension)
  (defun er-refresh-etags (&optional extension)
  "Run etags on all peer files in current dir and reload them silently."
  (shell-command (format "etags *.%s" (or extension "el")))
  (let ((tags-revert-without-query t))  ; don't query, revert silently          
    (visit-tags-table default-directory nil)))

Other tips

It just works with ExuberantCtags and etags, as both recognize the language based on extension.

If you happen to need to use two separate tags programs (like rtags and ctags) to parse all languages used in a project, just append one to the other.

See also


CategoryExternalUtilities CategoryNavigation