Improve include dependency script
authorTeemu Murtola <teemu.murtola@gmail.com>
Fri, 13 Dec 2013 18:48:32 +0000 (20:48 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Tue, 7 Jan 2014 05:24:19 +0000 (06:24 +0100)
- Make the depcheck, doccheck, and depgraphs targets work on the whole
  src/gromacs/ directory.  Now it is possible to run these checks on new
  or reorganized code without touching the scripts themselves.
- Fix the script to correctly recognize relative paths in #include
  directives again.
- Fix some issues the script complains about, and suppress some messages
  within the script itself.
- Make the colors in the module dependency graph somewhat more
  intuitive, and show legacy dependencies in gray instead of bright red
  to make it look reasonable.
- The module dependency graph now includes the legacy modules
  (gmxlib etc.) as well, with a gray background.  This makes the graph a
  bit messier, but still readable (in particular since most of the lines
  to and from them are gray, making them fade into the background).

Now, 'make depcheck' doesn't report any issues, and we should keep it
that way.  'make doccheck' (with the current, somewhat relaxed rules)
reports only a few issues that should be relatively easy to fix, but
left those for separate changes.  Other Doxygen documentation checks
(not only about file dependencies) could also perhaps be included in
this same target.

Change-Id: I3f837c69f2608d2a6a25ed4062102d252a85a0cf

13 files changed:
admin/includedeps.cmake
admin/includedeps.py
src/gromacs/fft/fft.h
src/gromacs/gmxana/legacytests/gmx_traj_tests.cpp
src/gromacs/mdlib/groupcoord.h
src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernels.cuh
src/gromacs/selection/centerofmass.h
src/gromacs/selection/selvalue.h
src/gromacs/timing/cyclecounter.h
src/gromacs/trajectoryanalysis/modules.cpp
src/gromacs/trajectoryanalysis/modules.h
src/gromacs/utility/gmxomp.h
src/testutils/integrationtests.h

index 66f289af0ee3efa8c29c9a0663b2e49988a84cd7..97a71290da568f83ab4ad519d343f1a9e61707c5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # the research papers on the package. Check out http://www.gromacs.org.
 
 function (generate_module_file_list SRCDIR OUTFILE MODE)
-    set(_module_list
-        analysisdata commandline fft fileio linearalgebra onlinehelp options
-        selection timing trajectoryanalysis utility)
-    if (MODE STREQUAL "CHECK")
-        list(APPEND _module_list gmxana gmxlib gmxpreprocess legacyheaders mdlib)
-    endif()
-    set(PATH_LIST)
-    foreach (MODULE ${_module_list})
-        list(APPEND PATH_LIST "${SRCDIR}/src/gromacs/${MODULE}/*.cpp")
-        if (MODE STREQUAL "GRAPHS")
-            list(APPEND PATH_LIST "${SRCDIR}/src/gromacs/${MODULE}/*.c")
-        endif()
-        list(APPEND PATH_LIST "${SRCDIR}/src/gromacs/${MODULE}/*.h")
-    endforeach ()
-    list(APPEND PATH_LIST "${SRCDIR}/src/testutils/*.cpp")
-    list(APPEND PATH_LIST "${SRCDIR}/src/testutils/*.h")
-    set(FILE_LIST)
-    foreach (PATH_EXPR ${PATH_LIST})
-        file(GLOB_RECURSE FOUND_FILES ${PATH_EXPR})
-        list(APPEND FILE_LIST ${FOUND_FILES})
-    endforeach ()
-    string(REPLACE ";" "\n" FILE_LIST "${FILE_LIST}")
-    file(WRITE ${OUTFILE} "${FILE_LIST}")
+    set(_file_list)
+    file(GLOB_RECURSE _file_list
+        ${SRCDIR}/src/gromacs/*.cpp
+        ${SRCDIR}/src/gromacs/*.c
+        ${SRCDIR}/src/gromacs/*.cu
+        ${SRCDIR}/src/gromacs/*.h
+        ${SRCDIR}/src/gromacs/*.cuh
+        ${SRCDIR}/src/testutils/*.cpp
+        ${SRCDIR}/src/testutils/*.h
+        )
+    string(REPLACE ";" "\n" _file_list "${_file_list}")
+    file(WRITE ${OUTFILE} "${_file_list}")
 endfunction ()
 
 function (generate_installed_file_list SRCDIR BUILDDIR OUTFILE)
@@ -88,7 +77,8 @@ endif ()
 if (MODE STREQUAL "CHECK")
     set(GRAPHOPTIONS --check)
 elseif (MODE STREQUAL "CHECKDOC")
-    set(GRAPHOPTIONS --check --check-doc --warn-undoc)
+    # TODO: Add --warn-undoc after most code has at least rudimentary comments.
+    set(GRAPHOPTIONS --check --check-doc)
 elseif (MODE STREQUAL "GRAPHS")
     set(GRAPHOPTIONS
         --module-graph module-deps.dot --module-file-graphs
index d7d7704fda67e1c471a79c75aefa80396bcb7650..48734404d32fc6a7344316e257c50d154bcd369c 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-"""Generate include dependency graphs for Gromacs.
+"""Check and generate include dependency graphs for Gromacs.
 
-This script can generate two types of include dependency graphs: per-file or
-per-module (where module is equivalent to a subdirectory).
+This script can do a few things related to include file dependencies:
+ - Check that there are no broken dependencies between installed headers.
+ - Check that documentated usage of a header matches its installation status
+   and usage from other modules.
+ - Generate two types of include dependency graphs: per-file or per-module
+   (where module is equivalent to a subdirectory).
 It is intended to be run on a subset of files under the src/ directory.
-Output format is suitable for processing with 'dot'.
+Output format for the graphs is suitable for processing with 'dot'.
 
 FILE GRAPHS
 
-The legend for per-file graph nodex:
+The legend for per-file graph nodes:
     gray:          source files
     light blue:    public headers
     dark blue:     library headers
@@ -52,15 +56,18 @@ MODULE GRAPHS
 
 Module graph will contain one node for each top-level subdirectory under src/,
 except that the src/gromacs/ directory will be expanded one level further.
+Legacy modules have gray background.
 
 The legend for per-module graph links (a link with a certain color indicates
 that types above it in the list are not present):
-    red:          invalid dependency (e.g., undocumented file)
-    dark blue:    library header depends on the other module
-    light blue:   public header depends on the other module
-    dashed black: source file depends on a library header in the other module
-    solid black:  source file depends on a public header in the other module
-    dotted grey:  test files depend on the other module
+    red:          invalid dependency
+    grey:         legacy dependency (dependency on undocumented file, or to
+                  legacy directories)
+    solid black:  public header depends on the other module
+    solid blue:   library header depends on the other module
+    dashed blue:  source file depends on a library header in the other module
+    dashed black: source file depends on a public header in the other module
+    dashed green: test file depends on the other module
 """
 
 import os.path
@@ -79,90 +86,54 @@ class ErrorReporter(object):
 class Link(object):
 
     """Link between two node objects.
-    
+
     Signifies an include dependency between the two nodes, and manages types
     associated with the dependencies.
     """
 
-    priorities = {
+    _priorities = {
             'undocumented': 1,
-            'intramodule': 2,
-            'library': 3,
+            'legacy': 2,
+            'intramodule': 3,
             'public': 4,
-            'libimpl': 5,
-            'pubimpl': 6,
-            'test': 7}
+            'library': 5,
+            'libimpl': 6,
+            'pubimpl': 7,
+            'test': 8}
 
-    def __init__(self, fromnode, tonode, link_type=None):
+    def __init__(self, fromnode, tonode, link_type):
         self.fromnode = fromnode
         self.tonode = tonode
         self.link_type = link_type
-        if not link_type:
-            self.refresh_type()
-
-    def refresh_type(self):
-        """Initialize type of a link between two file nodes.
-
-        Both endpoints of the link must be file objects when this method is
-        called.
-        """
-        fromfile = self.fromnode.obj
-        tofile = self.tonode.obj
-        intramodule = \
-                (fromfile.module.get_top_level_module() == \
-                 tofile.module.get_top_level_module())
-        if tofile.type != 'publicheader' and tofile.type != 'libheader':
-            if intramodule:
-                link_type = 'intramodule'
-            else:
-                link_type = 'undocumented'
-        elif fromfile.type == 'test':
-            link_type = 'test'
-        elif fromfile.type in ('source', 'header', 'implheader'):
-            if tofile.type == 'publicheader':
-                link_type = 'pubimpl'
-            elif tofile.type == 'libheader':
-                link_type = 'libimpl'
-            else:
-                raise ValueError('Unknown link type between {0} and {1}'
-                        .format(fromfile.path, tofile.path))
-        elif fromfile.type == 'libheader':
-            link_type = 'library'
-        elif fromfile.type == 'publicheader':
-            if tofile.type == 'publicheader' or tofile.doctype == 'public':
-                link_type = 'public'
-            else:
-                link_type = 'undocumented'
-        else:
-            raise ValueError('Unknown link type between {0} and {1}'
-                    .format(fromfile.path, tofile.path))
-        self.link_type = link_type
+        if link_type not in Link._priorities:
+            raise ValueError('Unknown link type {0}'.format(link_type))
 
     def merge_link(self, other):
         """Merge another link into this one and choose an appropriate type.
 
         Updates the type of this link based on the types of the merged links.
         """
-        if Link.priorities[other.link_type] < Link.priorities[self.link_type]:
+        if Link._priorities[other.link_type] < Link._priorities[self.link_type]:
             self.link_type = other.link_type
 
     def format(self):
         """Format this link for 'dot'."""
-        if isinstance(self.fromnode.obj, File) and \
-                isinstance(self.tonode.obj, File):
+        if self.fromnode.is_file_node() and self.tonode.is_file_node():
             properties = ''
         elif self.link_type == 'intramodule':
             properties = ''
         elif self.link_type == 'test':
-            properties = 'color=grey75, style=dotted'
+            properties = 'color=".33 .8 .8", style=dashed'
         elif self.link_type == 'libimpl':
-            properties = 'color=".66 .5 1"'
+            properties = 'color=".66 .8 .8", style=dashed'
         elif self.link_type == 'pubimpl':
-            properties = 'color=".66 .2 1"'
-        elif self.link_type == 'library':
             properties = 'color=black, style=dashed'
+        elif self.link_type == 'library':
+            properties = 'color=".66 .8 .8"'
         elif self.link_type == 'public':
             properties = 'color=black'
+        elif self.link_type == 'legacy':
+            properties = 'color=grey75'
         else: # undocumented
             properties = 'color=red'
         return '{0} -> {1} [{2}]'.format(self.fromnode.nodename,
@@ -170,10 +141,11 @@ class Link(object):
                                          properties)
 
 class Node(object):
-    def __init__(self, obj, nodename, label):
+    def __init__(self, nodename, label, properties, is_file):
         self.nodename = nodename
         self.label = label
-        self.obj = obj
+        self._properties = properties
+        self._is_file = is_file
         self.children = []
         self.root = False
 
@@ -183,9 +155,15 @@ class Node(object):
     def add_child(self, child):
         self.children.append(child)
 
+    def remove_child(self, child):
+        self.children.remove(child)
+
     def clear_children(self):
         self.children = []
 
+    def is_file_node(self):
+        return self._is_file
+
     def get_children(self, recursive=False):
         if recursive:
             result = list(self.children)
@@ -208,8 +186,10 @@ class Node(object):
             if not self.root:
                 result += '    }\n'
         else:
-            result += '    {0} [{1}]\n'.format(
-                    self.nodename, self.obj.node_properties())
+            properties = 'label="{0}"'.format(self.label)
+            if self._properties:
+                properties += ', ' + self._properties
+            result += '    {0} [{1}]\n'.format(self.nodename, properties)
         return result
 
 
@@ -308,9 +288,9 @@ class File(object):
         self.path = path
         self.name = os.path.basename(path)
         self.module = module
-        if module.name == 'tests':
+        if module.name == 'tests' or module.name == 'legacytests':
             self.type = 'test'
-        elif re.search(r'\.c(pp)?$', self.name) != None:
+        elif re.search(r'\.c(pp|u)?$', self.name) != None:
             self.type = 'source'
         else:
             self.type = 'header'
@@ -323,6 +303,9 @@ class File(object):
     def is_documented(self):
         return self.doctype != 'none'
 
+    def is_installed(self):
+        return self.installed
+
     def set_installed(self, reporter):
         if self.type != 'header':
             reporter.input_warning(self.path,
@@ -333,27 +316,6 @@ class File(object):
     def get_included_files(self):
         return self._included
 
-    def node_properties(self):
-        properties = []
-        style = []
-        properties.append('label="{0}"'.format(self.name))
-        properties.append('URL="\\ref {0}"'.format(self.name))
-        if not self.module:
-            style.append('bold')
-            properties.append('color=red')
-        if self.type == 'source':
-            style.append('filled')
-            properties.append('fillcolor=grey75')
-        elif self.type == 'publicheader':
-            style.append('filled')
-            properties.append('fillcolor=".66 .2 1"')
-        elif self.type == 'libheader':
-            style.append('filled')
-            properties.append('fillcolor=".66 .5 1"')
-        if style:
-            properties.append('style="{0}"'.format(','.join(style)))
-        return ', '.join(properties)
-
     def scan_include_file(self, line, allfiles, selfdir, includedirs,
             ignorelist, reporter):
         """Process #include directive during scan().
@@ -375,7 +337,7 @@ class File(object):
             match = re.match(r'#include *"([^"]*)"', line)
             if match:
                 includedpath = match.group(1)
-                fullpath = os.path.join(selfdir, includedpath)
+                fullpath = os.path.abspath(os.path.join(selfdir, includedpath))
                 #if os.path.abspath(fullpath) in ignorelist:
                 #    return
                 if os.path.exists(fullpath):
@@ -383,9 +345,10 @@ class File(object):
                 else:
                     fullpath = find_include_file(includedpath, includedirs)
                     if not fullpath:
-                        reporter.input_warning(self.path,
-                                'included file "{0}" not found'
-                                    .format(includedpath))
+                        if not includedpath in ('corewrap.h', 'tmpi_config.h'):
+                            reporter.input_warning(self.path,
+                                    'included file "{0}" not found'
+                                        .format(includedpath))
         if not includedpath:
             reporter.input_warning(self.path, 'line "{0}" could not be parsed'
                     .format(line))
@@ -460,6 +423,9 @@ class Module(object):
         self.children = dict()
         self.is_top_level = (not parent or parent.name in ('', 'gromacs'))
 
+    def get_parent(self):
+        return self.parent
+
     def is_child(self, module):
         parent = module.parent
         while parent:
@@ -486,11 +452,6 @@ class Module(object):
             newfile = module.add_nested_file(modules[1:], path)
         return newfile
 
-    def node_properties(self):
-        properties = 'label="{0}", shape=ellipse'.format(self.name)
-        properties += ', URL="\\ref module_{0}"'.format(self.name)
-        return properties
-
 
 class Dependencies(object):
     def __init__(self, rootdir, includedirs, installedfiles):
@@ -536,6 +497,14 @@ class Dependencies(object):
         return result
 
 
+def _is_legacy_module(module):
+    if module.name in ('legacyheaders', 'gmxlib', 'mdlib', 'gmxana', 'gmxpreprocess'):
+        return True
+    if module.get_parent():
+        return _is_legacy_module(module.get_parent())
+    return False
+
+
 class IncludeFileChecker(object):
     def __init__(self, deps, options):
         self._deps = deps
@@ -546,7 +515,10 @@ class IncludeFileChecker(object):
             return
         if not checkfile.is_documented():
             if self._options.warn_undoc:
-                reporter.error(checkfile.path, 'file not documented')
+                is_legacy = _is_legacy_module(checkfile.module)
+                is_external = checkfile.module.name in ('gmx_lapack', 'gmx_blas', 'thread_mpi')
+                if not is_legacy and not is_external:
+                    reporter.error(checkfile.path, 'file not documented')
         elif checkfile.doctype == 'implementation' and \
                 checkfile.type in ('publicheader', 'libheader'):
             reporter.error(checkfile.path,
@@ -564,7 +536,8 @@ class IncludeFileChecker(object):
         docmodule = checkfile.docmodule
         if docmodule and \
                 not selfmodfullname.startswith('module_' + docmodule) and \
-                not selfmodfullname.startswith('module_gromacs_' + docmodule):
+                not selfmodfullname.startswith('module_gromacs_' + docmodule) and \
+                not checkfile.name == docmodule + '.h':
             reporter.error(checkfile.path,
                     'file documented in incorrect module "{0}"'
                         .format(docmodule))
@@ -572,15 +545,19 @@ class IncludeFileChecker(object):
     def _check_included_file(self, checkfile, includedfile, reporter):
         otherfile = includedfile._included_file
         if includedfile._is_system:
+            # TODO: This doesn't report errors with files not listed in
+            # the input files, although those could be included.
+            # That would produce a massive amount of errors for <config.h>.
             if otherfile:
                 reporter.error(checkfile.path,
                         'local file included as <{0}>'
                             .format(includedfile._included_path))
         elif not includedfile._is_relative and checkfile.installed:
-            reporter.error(checkfile.path,
-                    'installed header includes "{0}", '
-                    'which is not found using relative path'
-                        .format(includedfile._included_path))
+            if not includedfile._included_path == 'gmx_header_config_gen.h':
+                reporter.error(checkfile.path,
+                        'installed header includes "{0}", '
+                        'which is not found using relative path'
+                            .format(includedfile._included_path))
         if not otherfile:
             return
         if checkfile.installed and not otherfile.installed:
@@ -596,7 +573,7 @@ class IncludeFileChecker(object):
                 (checkfile.module.get_top_level_module() == \
                  otherfile.module.get_top_level_module())
         if otherfile.type not in ('publicheader', 'libheader'):
-            if not intramodule:
+            if not intramodule and not _is_legacy_module(otherfile.module):
                 reporter.error(checkfile.path,
                         'included file "{0}" is missing API definition'
                             .format(otherfile.path))
@@ -607,7 +584,7 @@ class IncludeFileChecker(object):
                             .format(otherfile.path))
 
     def check_all(self, reporter):
-        for checkfile in self._deps.files.itervalues():
+        for checkfile in sorted(self._deps.files.values()):
             self._check_file(checkfile, reporter)
             for includedfile in checkfile.get_included_files():
                 self._check_included_file(checkfile, includedfile, reporter)
@@ -617,26 +594,88 @@ class GraphBuilder(object):
     def __init__(self, deps):
         self._deps = deps
 
-    def create_file_node(self, fileobj, filenodes):
+    def _create_file_node(self, fileobj, filenodes):
         nodename = re.subn(r'[-./]', '_', fileobj.path)[0]
-        node = Node(fileobj, nodename, fileobj.name)
+        properties = []
+        style = []
+        properties.append('URL="\\ref {0}"'.format(fileobj.name))
+        if not fileobj.module:
+            style.append('bold')
+            properties.append('color=red')
+        if fileobj.type == 'source':
+            style.append('filled')
+            properties.append('fillcolor=grey75')
+        elif fileobj.type == 'publicheader':
+            style.append('filled')
+            properties.append('fillcolor=".66 .2 1"')
+        elif fileobj.type == 'libheader':
+            style.append('filled')
+            properties.append('fillcolor=".66 .5 1"')
+        if style:
+            properties.append('style="{0}"'.format(','.join(style)))
+        node = Node(nodename, fileobj.name, ', '.join(properties), is_file=True)
         filenodes[fileobj] = node
         return node
 
-    def create_file_edges(self, fileobj, filenodes):
+    def _create_file_edge(self, fromfile, tofile, filenodes):
+        intramodule = \
+                (fromfile.module.get_top_level_module() == \
+                 tofile.module.get_top_level_module())
+        is_legacy = _is_legacy_module(tofile.module)
+        if tofile.type not in ('publicheader', 'libheader', 'header'):
+            if intramodule:
+                link_type = 'intramodule'
+            elif is_legacy:
+                link_type = 'legacy'
+            else:
+                link_type = 'undocumented'
+        elif fromfile.type == 'test':
+            link_type = 'test'
+        elif fromfile.type in ('source', 'header', 'implheader') and \
+                not fromfile.is_installed():
+            if intramodule:
+                link_type = 'intramodule'
+            elif tofile.type == 'publicheader':
+                link_type = 'pubimpl'
+            elif tofile.type == 'libheader':
+                link_type = 'libimpl'
+            elif is_legacy:
+                link_type = 'legacy'
+            elif not tofile.is_documented():
+                link_type = 'legacy'
+            else:
+                raise ValueError('Unknown link type between {0} and {1}'
+                        .format(fromfile.path, tofile.path))
+        elif fromfile.type == 'libheader':
+            link_type = 'library'
+        elif fromfile.type == 'publicheader' or fromfile.is_installed():
+            if tofile.type == 'publicheader' or tofile.doctype == 'public' or \
+                    (tofile.is_installed() and not tofile.is_documented()):
+                link_type = 'public'
+            else:
+                link_type = 'undocumented'
+        else:
+            raise ValueError('Unknown link type between {0} and {1}'
+                    .format(fromfile.path, tofile.path))
+        return Link(filenodes[fromfile], filenodes[tofile], link_type)
+
+    def _create_file_edges(self, fileobj, filenodes):
         links = []
         if fileobj in filenodes:
             for includedfile in fileobj.get_included_files():
                 otherfile = includedfile._included_file
                 if otherfile and otherfile in filenodes:
-                    link = Link(filenodes[fileobj], filenodes[otherfile])
+                    link = self._create_file_edge(fileobj, otherfile, filenodes)
                     links.append(link)
         return links
 
     def create_module_node(self, module, filenodes):
-        node = Node(module, module.fullname, module.name)
+        properties = 'shape=ellipse, URL="\\ref module_{0}"'.format(module.name)
+        if _is_legacy_module(module):
+            properties += 'style=filled, fillcolor=grey75'
+        node = Node(module.fullname, module.name, properties, is_file=False)
         for childfile in module.files:
-            node.add_child(self.create_file_node(childfile, filenodes))
+            node.add_child(self._create_file_node(childfile, filenodes))
         for childmodule in module.children.itervalues():
             node.add_child(self.create_module_node(childmodule, filenodes))
         return node
@@ -647,7 +686,7 @@ class GraphBuilder(object):
         rootnode.set_root()
         links = []
         for scanfile in self._deps.files.itervalues():
-            links.extend(self.create_file_edges(scanfile, filenodes))
+            links.extend(self._create_file_edges(scanfile, filenodes))
         graph = Graph([rootnode], links)
         return graph
 
@@ -657,15 +696,28 @@ class GraphBuilder(object):
         rootnode.set_root()
         links = []
         for scanfile in self._deps.files.itervalues():
-            links.extend(self.create_file_edges(scanfile, filenodes))
+            links.extend(self._create_file_edges(scanfile, filenodes))
         graph = Graph([rootnode], links)
         for node in rootnode.get_children():
             if node.label == 'gromacs':
+                module_nodes = []
+                header_nodes = []
                 for child in node.get_children():
-                    graph.collapse_node(child)
+                    if child.is_file_node():
+                        header_nodes.append(child)
+                    else:
+                        graph.collapse_node(child)
+                        module_nodes.append(child)
+                for header in header_nodes:
+                    for module in module_nodes:
+                        if header.nodename.startswith(module.nodename[7:]):
+                            # graph.merge_nodes([header], module)
+                            node.remove_child(header)
+                            break
             else:
                 graph.collapse_node(node)
         graph.set_options(concentrate=False)
+        graph.prune_links()
         return graph
 
     def create_module_file_graph(self, module):
@@ -674,7 +726,7 @@ class GraphBuilder(object):
         rootnode.set_root()
         links = []
         for scanfile in self._deps.files.itervalues():
-            links.extend(self.create_file_edges(scanfile, filenodes))
+            links.extend(self._create_file_edges(scanfile, filenodes))
         graph = Graph([rootnode], links)
         graph.prune_links()
         return graph
@@ -802,8 +854,10 @@ def main():
     if options.module_file_graphs:
         options.left_to_right = True
         for module in deps.get_toplevel_modules():
-            filename = 'module_{0}-deps.dot'.format(module.name)
-            with open(os.path.join(options.outdir, filename), 'w') as outfile:
-                print_module_file_graph(outfile, graphbuilder, module, options)
+            if not _is_legacy_module(module):
+                filename = 'module_{0}-deps.dot'.format(module.name)
+                filename = os.path.join(options.outdir, filename)
+                with open(filename, 'w') as outfile:
+                    print_module_file_graph(outfile, graphbuilder, module, options)
 
 main()
index 96c7b89a559fdb8c5f7e21d7a1026a6bc9d8f4c8..f3c9c9c4ce86cee36b7581e0163dd25482a86737 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2003 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -46,6 +46,7 @@
  *  We also provide our own multi-dimensional transform setups even when
  *  the underlying library does not support it directly.
  *
+ * \inpublicapi
  * \ingroup module_fft
  */
 #ifndef GMX_FFT_FFT_H
index 940eb0a9b0afe537f65879312745378b53d21dc0..29e90b6b229d8d0c6a4b87480f03aec38faea74e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -37,7 +37,6 @@
  * Tests for gmx traj
  *
  * \author Mark Abraham <mark.j.abraham@gmail.com>
- * \ingroup module_integration_tests
  */
 
 #include "gromacs/gmxana/gmx_ana.h"
index 373b56c7295f903907a874573249a96359854512..4893ba130bcbd65c2650ac18c9ee72e980191a35 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-
-/*! \file groupcoord.h
- *
- *  @brief Assemble atom positions for comparison with a reference set.
+/*! \libinternal \file groupcoord.h
+ * \brief
+ * Assemble atom positions for comparison with a reference set.
  *
- *  This file contains functions to assemble the positions of a subset of the
- *  atoms and to do operations on it like determining the center of mass, or
- *  doing translations and rotations. These functions are useful when
- *  a subset of the positions needs to be compared to some set of reference
- *  positions, as e.g. done for essential dynamics.
+ * This file contains functions to assemble the positions of a subset of the
+ * atoms and to do operations on it like determining the center of mass, or
+ * doing translations and rotations. These functions are useful when
+ * a subset of the positions needs to be compared to some set of reference
+ * positions, as e.g. done for essential dynamics.
  *
+ * \inlibraryapi
  */
 
 #ifdef HAVE_CONFIG_H
index 147d42c029be020e6006887679e1d6fbc980d758..608f826b77da2699e9820da4d29f430d80ee8b19 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -33,7 +33,7 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-/*! \file
+/*! \internal \file
  *  This header has the sole purpose of generating kernels for the supported
  *  electrostatics types: cut-off, reaction-field, Ewald, and tabulated Ewald.
  *
index 6e0f9e2c478c753c8880676c8e6a73e69f0b5320..7cefe1a02be3bc4be8dc2dbc449c73cd233a3e2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2013, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -32,7 +32,7 @@
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/*! \file
+/*! \internal \file
  * \brief API for calculation of centers of mass/geometry.
  *
  * This header defines a few functions that can be used to calculate
index cf0104d34faed803659ca5840bc0ddc8db37725d..aad846f9c50f3d1a7a579a8286aa09c9c9380fc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -32,7 +32,7 @@
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/*! \file
+/*! \internal \file
  * \brief
  * Declares ::gmx_ana_selvalue_t.
  *
@@ -59,7 +59,8 @@ typedef enum
     GROUP_VALUE         /**< One group of atoms. */
 } e_selvalue_t;
 
-/*! \brief
+/*! \internal
+ * \brief
  * Describes a value of a selection expression or of a selection method
  * parameter.
  *
index 255f55bc7afeb1c67f925fd2d2486234cd15cfcb..b551009476bd69e42cd2bcf785ffe37cb196611e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2006 David van der Spoel, Erik Lindahl, Berk Hess, University of Groningen.
- * Copyright (c) 2013, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/*! \internal \file
+/*! \libinternal \file
  * \brief
  * High-resolution timestamp or CPU clock cycle counters.
  *
  * After reading the current value with gmx_cycles_read() you can add or
  * subtract these numbers as normal integers of type gmx_cycles_t.
+ *
+ * \inlibraryapi
  */
 #ifndef GMX_TIMING_CYCLECOUNTER_H
 #define GMX_TIMING_CYCLECOUNTER_H
index 501806c449a99da42a43d326ffb79349effda407..1e7dd516365d4767d533d84c02b88a37deaebd06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -79,6 +79,7 @@ void registerModule(CommandLineModuleManager *manager,
 
 }   // namespace
 
+//! \cond libapi
 void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager)
 {
     using namespace gmx::analysismodules;
@@ -88,5 +89,6 @@ void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager)
     registerModule<FreeVolumeInfo>(manager, group);
     registerModule<SelectInfo>(manager, group);
 }
+//! \endcond
 
 } // namespace gmx
index 0c6a7db9799c2a8b94cbed0e5924923bebd9d6e6..44ff5409bc87c5a8fe93ff74077ed5c8022404e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/*! \file
+/*! \libinternal \file
  * \brief
  * Generic interface for accessing trajectory analysis modules.
  *
  * \author Teemu Murtola <teemu.murtola@gmail.com>
- * \inpublicapi
+ * \inlibraryapi
  * \ingroup module_trajectoryanalysis
  */
 #ifndef GMX_TRAJECTORYANALYSIS_MODULES_H
@@ -48,6 +48,7 @@ namespace gmx
 
 class CommandLineModuleManager;
 
+//! \cond libapi
 /*! \brief
  * Registers all trajectory analysis command-line modules.
  *
@@ -57,9 +58,10 @@ class CommandLineModuleManager;
  * Registers all trajectory analysis modules declared in the library such that
  * they can be run through \p manager.
  *
- * \inpublicapi
+ * \ingroup module_trajectoryanalysis
  */
 void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager);
+//! \endcond
 
 } // namespace gmx
 
index d65fa5223e636b275247cad6c4e16035a61835e0..15b4c644cc3c2ae90dad2f3417d48a2dc93b5249 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -43,6 +43,7 @@
  * and omp.h should never be directly included.  Instead, this header should be
  * used whenever OpenMP API functions are needed.
  *
+ * \inlibraryapi
  * \ingroup module_utility
  */
 #ifndef GMX_UTILITY_OMP_H
index 6e3991b035822f9e7a1807eaf7471232069c0c88..a610e5c7e4bcd4852ce32d8ebda1eb7e3d7f5089 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/*! \internal \file
+/*! \libinternal \file
  * \brief
  * Declares test fixture for integration tests
  *
  * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inlibraryapi
  * \ingroup module_testutils
  */
 #ifndef GMX_INTEGRATION_TESTS_MODULETEST_H
@@ -57,6 +58,7 @@ namespace test
  *
  * Any method in this class may throw std::bad_alloc if out of memory.
  *
+ * \inlibraryapi
  * \ingroup module_testutils
  */
 class IntegrationTestFixture : public ::testing::Test