Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
header_consumers Namespace Reference

Functions

 strip_noise (text)
 
 read (path)
 
 symbols_of (path)
 
 resolve (inc, from_dir)
 
 closure (header, seen=None)
 
 walk_sources ()
 
 main ()
 

Variables

 REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 SRC = os.path.join(REPO, "src")
 
 COMMENT_BLOCK = re.compile(r"/\*.*?\*/", re.S)
 
 COMMENT_LINE = re.compile(r"//[^\n]*")
 
 STRING_LIT = re.compile(r'"(?:\\.|[^"\\])*"')
 
 INCLUDE = re.compile(r'^\s*#\s*include\s+"([^"]+)"')
 
list DECLARE_PATTERNS
 
 ENUM_MEMBER = re.compile(r"^\s*(DT_[A-Z0-9_]+)\s*(?:=|,|$)")
 
dict NOISE
 

Detailed Description

Report what each includer of a header actually consumes through it.

`gui/gtk.h` is included by 140 files, but almost none of them want 140 files' worth of
header. Most want two or three symbols; a good number want *nothing it declares* and are
only there for what it drags in transitively (that is how an earlier split attempt broke
`control/control.h`, which was getting `dt_control_t` through this chain and lost it when
the chain was shortened).

Splitting a god-header safely needs that distinction made explicit per file, so this
separates three cases for every includer:

  OWN    - uses a symbol the header itself declares/defines. Needs whichever new header
           that symbol lands in.
  VIA    - uses no own symbol, but uses a symbol from a header this one includes. The
           include is a transitive supply line; the file needs that header from somewhere
           else. Only headers it cannot already reach through its *other* includes are
           reported, so the list is what actually has to be added, not everything it happens
           to touch.
  UNUSED - uses nothing from the header or its transitive closure. The include can go.

Symbols are collected per header (functions, macros, types, enums, struct tags) and matched
against each includer by word-boundary search outside comments and strings. That over-counts
slightly -- a name mentioned in a comment-like context, or a symbol also reachable from a
different header -- so treat VIA as "candidate direct include", not gospel.

Usage:
    tools/header_consumers.py gui/gtk.h [--json] [--only own|via|unused]

Function Documentation

◆ closure()

header_consumers.closure (   header,
  seen = None 
)
Headers reachable from `header`, excluding itself.

Definition at line 157 of file header_consumers.py.

References closure(), L, read(), and resolve().

Referenced by closure(), and main().

◆ main()

header_consumers.main ( void  )

Definition at line 180 of file header_consumers.py.

References closure(), items, L, main(), read(), resolve(), strip_noise(), symbols_of(), and walk_sources().

Referenced by main().

◆ read()

header_consumers.read (   path)

Definition at line 125 of file header_consumers.py.

References L.

Referenced by closure(), main(), and symbols_of().

◆ resolve()

header_consumers.resolve (   inc,
  from_dir 
)
An include is written either relative to src/ or to the including file's directory.

Definition at line 148 of file header_consumers.py.

References L.

Referenced by closure(), and main().

◆ strip_noise()

header_consumers.strip_noise (   text)
Blank comments and string literals, in ONE pass.

Three regexes applied in sequence cannot do this, in either order, because each construct
can contain the others' delimiters. Comments-first blanks from the `//` of a URL to the end
of the line, taking the string's closing quote with it; the surviving opening quote then
pairs with the next quote further down the file and swallows everything between. Measured on
src/gui/actions/help.c: 7550 of 9491 characters gone, and its three dt_control_log() calls
with them -- the file was reported as using NOTHING from control.h while calling it three
times. 129 files in this tree contain `//` inside a string literal.

Strings-first fails symmetrically: a lone `"` inside a comment (`// don't use "foo.h" here`
is fine, an unbalanced one is not) starts a literal that eats real code.

So: scan once, tracking which construct we are inside. Newlines are preserved so line
numbers stay meaningful; everything else becomes a space, and a string literal becomes the
empty pair the callers already expect.

Definition at line 73 of file header_consumers.py.

References L.

Referenced by main(), and symbols_of().

◆ symbols_of()

header_consumers.symbols_of (   path)
Every identifier `path` supplies to whoever includes it.

Definition at line 133 of file header_consumers.py.

References L, read(), and strip_noise().

Referenced by main().

◆ walk_sources()

header_consumers.walk_sources ( )

Definition at line 172 of file header_consumers.py.

References L.

Referenced by main().

Variable Documentation

◆ COMMENT_BLOCK

header_consumers.COMMENT_BLOCK = re.compile(r"/\*.*?\*/", re.S)

Definition at line 40 of file header_consumers.py.

◆ COMMENT_LINE

header_consumers.COMMENT_LINE = re.compile(r"//[^\n]*")

Definition at line 41 of file header_consumers.py.

◆ DECLARE_PATTERNS

list header_consumers.DECLARE_PATTERNS
Initial value:
1= [
2 re.compile(r"^\s*#\s*define\s+([A-Za-z_]\w*)"),
3 re.compile(r"^\s*}[^;]*?\b([A-Za-z_]\w*)\s*;"), # `} name;` and `} ATTR(..) name;`
4 re.compile(r"^\s*typedef\s+.*?\b([A-Za-z_]\w*)\s*;"),
5 re.compile(r"^\s*typedef\s+.*\‍(\s*\*\s*([A-Za-z_]\w*)\s*\‍)\s*\‍("), # function-pointer typedef # typedef one-liner
6 re.compile(r"^\s*(?:struct|union|enum)\s+([A-Za-z_]\w*)\s*[;{]"),
7 # A declaration or definition at file scope: <type stuff> name(
8 re.compile(r"^\s*(?:[A-Za-z_][\w \t*]*?[ \t*])([A-Za-z_]\w*)\s*\‍("),
9]

Definition at line 47 of file header_consumers.py.

◆ ENUM_MEMBER

header_consumers.ENUM_MEMBER = re.compile(r"^\s*(DT_[A-Z0-9_]+)\s*(?:=|,|$)")

Definition at line 58 of file header_consumers.py.

◆ INCLUDE

header_consumers.INCLUDE = re.compile(r'^\s*#\s*include\s+"([^"]+)"')

Definition at line 44 of file header_consumers.py.

◆ NOISE

dict header_consumers.NOISE
Initial value:
1= {
2 "if", "for", "while", "switch", "return", "sizeof", "defined", "else", "do",
3 "static", "inline", "const", "struct", "union", "enum", "typedef", "extern",
4 "void", "int", "char", "float", "double", "long", "short", "unsigned", "signed",
5 "gboolean", "gint", "guint", "gchar", "gpointer", "gdouble", "gfloat", "gsize",
6 "size_t", "ssize_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
7 "int8_t", "int16_t", "int32_t", "int64_t", "va_list", "FILE",
8 "TRUE", "FALSE", "NULL",
9}

Definition at line 62 of file header_consumers.py.

◆ REPO

header_consumers.REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Definition at line 37 of file header_consumers.py.

◆ SRC

header_consumers.SRC = os.path.join(REPO, "src")

Definition at line 38 of file header_consumers.py.

◆ STRING_LIT

header_consumers.STRING_LIT = re.compile(r'"(?:\\.|[^"\\])*"')

Definition at line 42 of file header_consumers.py.