Skip to content

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.

.mk, .mak, .Makefile · 1 registry id · 8 of 14 relationship types

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 typeConstructed
callsconstructed by this analyzer
extendsruled absent
implementsruled absent
usesconstructed by this analyzer
importsconstructed by this analyzer
exportsconstructed by this analyzer
containsconstructed by this analyzer
referencesconstructed by this analyzer
overridesconstructed by this analyzer
instantiatesruled absent
decoratesruled absent
rendersruled absent
mixes_inruled absent
part_ofconstructed 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 include is 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 references only when this file declares the target, and uses otherwise 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.
  • ifdef and ifeq select 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 … endef publishes 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, configure and Autotools all emit it — so a build tree under build/ 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.

  1. Which targets does this makefile declare, and what does each one depend on?
  2. Which variable does this recipe read, and where is it assigned?
  3. Which files does this makefile include?
  4. Which macro does this recipe call?

What the analyzer sees in code like this

Two variables, a target with a file prerequisite, and an include
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.mk

Symbols 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.