Language record
Make
A makefile is indexed as the flat namespace it is: one module symbol per file owns every target, variable and macro, a prerequisite this file declares is a reference and everything else is a member read with the reason named — so the shape of a build graph is answerable without running Make.
The registry row this page is generated from
Read at render time from the same family row the register reads, so nothing in this block can disagree with it.
- Extensions
- .mk, .mak, .Makefile
- Registry names
make- Recorded symbols
- targets · variables · includes
Relationship types this analyzer constructs
8 of 14 constructed, read from this analyzer's source and re-derived by the languages gate. Each row below is one of the engine's types, in the engine's own order.
| Relationship type | Constructed |
|---|---|
calls | constructed by this analyzer |
extends | ruled absent |
implements | ruled absent |
uses | constructed by this analyzer |
imports | constructed by this analyzer |
exports | constructed by this analyzer |
contains | constructed by this analyzer |
references | constructed by this analyzer |
overrides | constructed by this analyzer |
instantiates | ruled absent |
decorates | ruled absent |
renders | ruled absent |
mixes_in | ruled absent |
part_of | constructed by this analyzer |
8 constructed, 6 not constructed. All 6 absent types are recorded as ruled absent: the written reason and the corpus measurement behind each are in this family's completeness record. The register explains what each label means.
What this analyzer does not resolve
- Targets resolve inside the makefile. An
includeis an import edge, but the included file's targets are not folded into this file's set, so a rule reaching a dependency two files away reads as two files with two targets — and Make has exactly one declaration level, so a makefile is a flat set of declarations joined by references rather than a tree of blocks. - A reference is
referencesonly when this file declares the target, andusesotherwise with the reason attached. A Make prerequisite is usually a file, a Make variable is often set by the command line or the environment, and Make ships builtins no file can declare; over the corpus the unresolved ends divide as 241 file paths, 183 external variables, 160 builtins, 213 automatic variables and 11 shell variables, and not one of them is a true dangler. ifdefandifeqselect between alternatives and are not evaluated, so a variable assigned in two branches becomes one record carrying the last assignment's operator and value. A worse case is a conditional that follows a rule with a recipe: the grammar nests the whole block inside that rule's recipe, so the walk always descends into children — including recipes — to keep the rules it swallowed.
Every line above was written against Make’s own analyzer module and is named against a construct in it, so it can be checked against the source. Nothing here is inherited from a template, or from another language’s page.
Where you meet it in a repository
Recognised by extension — .mk, .mak, .Makefile. Everything below is about where those files actually sit in a working repository.
- A real project splits make across files with
include common.mk; each file is its own module, the include is an import edge, and each target stays in the file that declares it. Both expansion spellings are normalised —${VAR}is Make's second form and appears 68 times across 14 of the corpus's 99 files, and handling only$(published each as two edges, one of them dangling. - A macro is a callable:
define M … endefpublishes a function symbol with parameters, and$(call M, …)publishes a call edge to it. A loop variable bound by$(foreach v,…)is recorded as a local binder rather than as a project variable. - Generated make is everywhere — CMake,
configureand Autotools all emit it — so a build tree underbuild/is a large body of make whose prerequisites are files rather than source symbols, and almost every edge from it points outward to something Make can see and no file declares.
Questions this index answers
Phrased as retrievals, because that is what an index can honestly do: it holds the symbols and the edges between them, and hands them back with the evidence attached.
- Which targets does this makefile declare, and what does each one depend on?
- Which variable does this recipe read, and where is it assigned?
- Which files does this makefile include?
- Which macro does this recipe call?
What the analyzer sees in code like this
CC := gcc # bb records: variable CC
SRC := $(wildcard src/*.c) # bb records: variable SRC
build: $(SRC) # bb records: target build; $(SRC) references SRC
tail -n +2 $< | $(CC) -o app # $< is an automatic variable: a use, not a declaration
include config.mk # bb records: an import -> config.mkSymbols are stored with the file they came from and the bytes they span, so a hit points at a line rather than at a guess. The annotations in the sample are commentary for the reader, not strings the index would store.
Languages that turn up in the same repository
Web, data & config — the count beside each name is how many relationship types that family’s analyzer constructs.
The extensions, registry names, recorded symbols and relationship types above are the parser registry row for Make, read while the page rendered — the same row the register reads, so the two surfaces cannot tell two stories. Every relationship type listed as constructed appears in src/ast/real-*, the analyzer modules bb ships. bb 0.1.0 answers from a local store over 50 languages (53 registry ids, three of them aliases). There is no benchmark on this page: every claim here is one you can go and read in the source.