diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | changes/ticket26447 | 5 | ||||
-rwxr-xr-x | scripts/maint/checkIncludes.py | 26 |
3 files changed, 31 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am index 202197f5f5..3df35ad3f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -203,7 +203,7 @@ doxygen: test: all $(top_builddir)/src/test/test -check-local: check-spaces check-changes +check-local: check-spaces check-changes check-includes need-chutney-path: @if test ! -d "$$CHUTNEY_PATH"; then \ @@ -320,7 +320,7 @@ endif check-includes: if USEPYTHON - $(top_srcdir)/scripts/maint/checkIncludes.py + $(PYTHON) $(top_srcdir)/scripts/maint/checkIncludes.py endif check-docs: all diff --git a/changes/ticket26447 b/changes/ticket26447 new file mode 100644 index 0000000000..757a4022ff --- /dev/null +++ b/changes/ticket26447 @@ -0,0 +1,5 @@ + o Minor features (code correctness, testing): + - Tor's build process now includes a "check-includes" make target + to verify that no module of Tor relies on any headers from a + higher-level module. We hope to use this feature over time to + help refactor our codebase. Closes ticket 26447. diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py index 5cf7ead47e..d13ff565cb 100755 --- a/scripts/maint/checkIncludes.py +++ b/scripts/maint/checkIncludes.py @@ -1,6 +1,21 @@ #!/usr/bin/python3 # Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info. +"""This script looks through all the directories for files matching *.c or + *.h, and checks their #include directives to make sure that only "permitted" + headers are included. + + Any #include directives with angle brackets (like #include <stdio.h>) are + ignored -- only directives with quotes (like #include "foo.h") are + considered. + + To decide what includes are permitted, this script looks at a .may_include + file in each directory. This file contains empty lines, #-prefixed + comments, filenames (like "lib/foo/bar.h") and file globs (like lib/*/*.h) + for files that are permitted. +""" + + from __future__ import print_function import fnmatch @@ -8,20 +23,26 @@ import os import re import sys +# Global: Have there been any errors? trouble = False def err(msg): + """ Declare that an error has happened, and remember that there has + been an error. """ global trouble trouble = True print(msg, file=sys.stderr) def fname_is_c(fname): + """ Return true iff 'fname' is the name of a file that we should + search for possibly disallowed #include directives. """ return fname.endswith(".h") or fname.endswith(".c") INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"') RULES_FNAME = ".may_include" class Rules(object): + """ A 'Rules' object is the parsed version of a .may_include file. """ def __init__(self, dirpath): self.dirpath = dirpath self.patterns = [] @@ -59,6 +80,7 @@ class Rules(object): print("Pattern {} in {} was never used.".format(p, self.dirpath)) def load_include_rules(fname): + """ Read a rules file from 'fname', and return it as a Rules object. """ result = Rules(os.path.split(fname)[0]) with open(fname, 'r') as f: for line in f: @@ -81,6 +103,6 @@ for dirpath, dirnames, fnames in os.walk("src"): if trouble: err( -"""To change which includes are allowed in a C file, edit the {} files in its -enclosing directory.""".format(RULES_FNAME)) +"""To change which includes are allowed in a C file, edit the {} +files in its enclosing directory.""".format(RULES_FNAME)) sys.exit(1) |