1 Source tree checker scripts {#page_dev_gmxtree}
2 ===========================
4 There is a set of Python scripts, currently under `docs/doxygen/`, that check
5 various aspects of the source tree for consistency. The script is based on
6 producing an abstract representation of the source tree from various sources:
7 * List of files in the source tree (for overall layout of the source tree)
8 * List of installed headers (extracted from the generated build system)
9 * git attributes (to limit the scope of some checks)
10 * Doxygen XML documentation:
11 * For tags about public/private nature of documented headers and other
13 * For actual documented constructs, to check them for consistency
14 * Hard-coded knowledge about the \Gromacs source tree layout
16 This representation is then used for various purposes:
17 * Checking Doxygen documentation elements for common mistakes: missing brief
18 descriptions, mismatches in file and class visibility, etc.
19 * Checking for consistent usage and documentation of headers: e.g., a header
20 that is documented as internal to a module should not be used outside that
22 * Checking for module-level cyclic dependencies
23 * Checking for consistent style and order of \#include directives
24 (see \ref page_devstyle_includes)
25 * Actually sorting and reformatting \#include directives to adhere to the
27 * Generating dependency graphs between modules and for files within modules
29 The checks are run as part of a single `check-source` target, but are described
30 in separate sections below. In addition to printing the issues to `stderr`,
31 the script also writes them into `docs/doxygen/check-source.log` for later
32 inspection. Jenkins runs the checks as part of the Documentation job, and the
33 build is marked unstable if any issues are found.
35 For correct functionality, the scripts depend on correct usage of Doxygen
36 annotations described in \ref page_doxygen, in particular the visibility and
37 API definitions in file-level comments.
39 For some false positives from the script, the suppression mechanism described
40 below is the easiest way to silence the script, but otherwise the goal would be
41 to minimize the number of suppressions.
43 The scripts require Python 2.7 (other versions may work, but have not been
46 To understand how the scripts work internally, see comments in the Python
47 source files under `docs/doxygen/`.
52 The `check-source` target currently checks for a few different types of issues.
53 These are listed in detail below, mainly related to documentation and include
54 dependencies. Note in particular that the include dependency checks are much
55 stricter for code in modules/directories that are documented with a
56 \c \\defgroup: all undocumented code is assumed to be internal to such modules.
57 The rationale is that such code has gotten some more attention, and some effort
58 should also have been put into defining what is the external interface of the
59 module and documenting it.
61 * For all Doxygen documentation (currently does not apply for members that do
62 not appear in the documentation):
63 * If a member has documentation, it should have a brief description.
64 * A note is issued for in-body documentation for functions, since this is
65 ignored by our current settings.
66 * If a class has documentation, it should have public documentation only if
67 it appears in an installed header.
68 * If a class and its containing file has documentation, the class
69 documentation should not be visible if the file documentation is not.
73 #include "..." // This should be used for Gromacs headers
77 #include <...> // This should be used for system and external headers
79 * Installed headers must not include non-installed headers.
80 * All source files must include "gmxpre.h" as the first header.
81 * A source/header file should include "config.h" if and only if it uses a
83 * If the file has a git attribute to identify it as a candidate for include
84 sorting, the include sorter described below should not produce any
85 changes (i.e., the file should follow \ref page_devstyle_includes).
86 * For documented files:
87 * Installed headers should have public documentation, and other files should
89 * The API level specified for a file should not be higher than where its
90 documentation is visible. For example, only publicly documented headers
91 should be specified as part of the public API.
92 * If an \c \\ingroup `module_foo` exists, it should match the subdirectory
93 that the file is actually part of in the file system.
94 * If a \c \\defgroup `module_foo` exists for the subdirectory where the file
95 is, the file should contain \c \\ingroup `module_foo`.
96 * Files should not include other files whose documentation visibility is
97 lower (if the included file is not documented, the check is skipped).
98 * For files that are part of documented modules
99 (\c \\defgroup `module_foo` exists for the subdirectory), or are explicitly
100 documented to be internal or in the library API:
101 * Such files should not be included from outside their module if they are
102 undocumented (for documented modules) or are not specified as part of
103 library or public API.
105 * There should not be cyclic include dependencies between modules.
107 As a side effect, the XML extraction makes Doxygen parse all comments in the
108 code, even if they do not appear in the documentation. This can reveal latent
109 issues in the comments, like invalid Doxygen syntax. The messages from the XML
110 parsing are stored in `docs/doxygen/doxygen-xml.log` in the build tree, similar to
116 The script is not currently perfect (either because of unfinished
117 implementation, or because Doxygen bugs or incompleteness of the Doxygen XML
118 output), and the current code also contains issues that the script detects, but
119 the authors have not fixed. To allow the script to still be used,
120 `doxygen/suppressions.txt` contains a list of issues that are filtered out from
121 the report. The syntax is simple:
125 where `<file>` is a path to the file that reports the message, and `<text>` is
126 the text reported. Both support `*` as a wildcard. If `<file>` is empty, the
127 suppression matches only messages that do not have an associated file.
128 `<file>` is matched against the trailing portion of the file name to make it
129 work even though the script reports absolute paths.
130 Empty lines and lines starting with `#` are ignored.
132 To add a suppression for an issue, the line that reports the issue can be
133 copied into `suppressions.txt`, and the line number (if any) removed. If the
134 issue does not have a file name (or a pseudo-file) associated, a leading `:`
135 must be added. To cover many similar issues, parts of the line can then be
136 replaced with wildcards.
138 A separate suppression mechanism is in place for cyclic dependencies: to
139 suppress a cycle between moduleA and moduleB, add a line with format
143 into `doxygen/cycle-suppressions.txt`. This suppresses all cycles that contain
144 the mentioned edge. Since a cycle contains multiple edges, the suppression
145 should be made for the edge that is determined to be an incorrect dependency.
146 This also affects the layout of the include dependency graphs (see below): the
147 suppressed edge is not considered when determining the dependency order, and is
148 shown as invalid in the graph.
150 Include order sorting {#section_dev_includesorter}
151 =====================
153 The script checks include ordering according to \ref page_devstyle_includes.
154 If it is not obvious how the includes should be changed to make the script
155 happy, or bulk changes are needed in multiple files, e.g., because of a header
156 rename or making a previously public header private, it is possible to run a
157 Python script that does the sorting:
159 docs/doxygen/includesorter.py -S . -B ../build <files>
161 The script needs to know the location of the source tree (given with `-S`) and
162 the build tree (given with `-B`), and sorts the given files. To sort the whole
163 source tree, one can also use:
165 admin/reformat_all.sh includesort -B=../build
167 For the sorter to work correctly, the build tree should contain up-to-date list
168 of installed files and Doxygen XML documentation. The former is created
169 automatically when `cmake` is run, and the latter can be built using the
170 `doxygen-xml` target.
172 Note that currently, the sorter script does not change between angle brackets
173 and quotes in include statements.
175 Include dependency graphs
176 =========================
178 The same set of Python scripts can also produce include dependency graphs with
179 some additional annotations compared to what, e.g., Doxygen produces for a
180 directory dependency graph. Currently, a module-level graph is automatically
181 built when the Doxygen documentation is built and embedded in the documentation
182 (not in the public API documentation). The graph, together with a legend, is
183 on a separate page: \ref page_modulegraph.
185 The Python script produces the graphs in a format suitable for `dot` (from the
186 `graphviz` package) to lay them out. The build system also provides a
187 `dep-graphs` target that generates PNG files from the intermediate `dot` files.
188 In addition to the module-level graph, a file-level graph is produced for
189 each module, showing the include dependencies within that module.
190 The file-level graphs can only be viewed as the PNG files, with some
191 explanation of the notation below. Currently, these are mostly for eye candy,
192 but they can also be used for analyzing problematic dependencies to clean up
195 Both the intermediate `.dot` files and the final PNG files are put under
196 `docs/doxygen/depgraphs/` in the build tree.
201 The graphs are written to <em>module_name</em>`-deps.dot.png`.
206 <dd>public API (installed) headers</dd>
208 <dd>library API headers</dd>
210 <dd>source files</dd>
217 Each edge signifies an include dependency; there is no additional information