Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/fernandodanielmaqueda/gcc-bison-flex-GNUmakefile/llms.txt

Use this file to discover all available pages before exploring further.

The framework is split across a set of .mk files that are included at two distinct moments in a user’s makefile: a header group that runs unconditionally when main.mk is first included, and a footer group that is deferred until the user explicitly expands MKFWK_FOOTER at the bottom of their makefile. This two-part design lets every sub-makefile in a project see the same variable definitions while guaranteeing that the build rules and targets are registered exactly once, at the top level.

Include guard: MKFWK_HEADER_PARSED

main.mk wraps the bulk of its content in an include guard so that the header makefiles are parsed only once, no matter how many sub-makefiles include main.mk:
ifeq ($(MKFWK_HEADER_PARSED),)
MKFWK_HEADER_PARSED=X

# ... all header-level definitions ...

endif
The first time main.mk is included, MKFWK_HEADER_PARSED is empty, so the body executes and immediately sets the variable to X. Every subsequent include main.mk from a nested makefile finds the variable already set and skips the body entirely. This means the directory variables, compiler defaults, and option flags are established exactly once.

Depth stack: MKFWK_DEPTH_STACK

A separate mechanism outside the include guard tracks how deeply nested the current include context is:
MKFWK_DEPTH_STACK+=1
Every time any makefile includes main.mk, a word is appended to MKFWK_DEPTH_STACK. When MKFWK_FOOTER is later expanded, it pops one word:
MKFWK_DEPTH_STACK:=$(wordlist 2,$(words $(MKFWK_DEPTH_STACK)),X $(MKFWK_DEPTH_STACK))
The footer makefiles (which contain all the build rules) are only included when the stack holds exactly one word — meaning we are currently in the top-level makefile, not inside a sub-makefile. This prevents the rules from being registered multiple times and avoids duplicate-target errors.

Relative path variables

Two variables let any .mk file construct correct paths regardless of where it sits on disk:
VariableDefinitionMeaning
MKFWK_LAST_INCLUDED_DIR$(filter-out ./,$(dir $(lastword $(MAKEFILE_LIST))))Directory of the last file GNU Make added to MAKEFILE_LIST — i.e. the file currently being parsed.
MKFWK_LAST_INCLUDING_DIRComputed from the second-to-last entry in MAKEFILE_LISTDirectory of the makefile that issued the include directive — i.e. the caller.
Both variables use immediate (:=) assignment in the places where they matter, because their expansion changes as GNU Make processes each file. The directory variables for the framework’s own subdirectories are derived from MKFWK_LAST_INCLUDED_DIR the moment main.mk is first parsed:
MKFWK_HEADER_DIR:=$(MKFWK_LAST_INCLUDED_DIR)header/
MKFWK_FOOTER_DIR:=$(MKFWK_LAST_INCLUDED_DIR)footer/
MKFWK_LANG_DIR:=$(MKFWK_LAST_INCLUDED_DIR)lang/
MKFWK_CODE_DIR:=en_US/
After the respective include directives consume these values, each variable is cleared to free memory.

Header includes (unconditional)

After the language files are loaded, main.mk includes three header makefiles unconditionally using a plain include directive that fails if any file is missing:
include $(MKFWK_HEADER_DIR)chars.mk $(MKFWK_HEADER_DIR)core.mk $(MKFWK_HEADER_DIR)sysconfig.mk
Defines variables for characters that GNU Make cannot represent directly in certain contexts: MKFWK_SPACE, MKFWK_TAB, MKFWK_HASH, MKFWK_COMMA, MKFWK_PERCENTAGE_SIGN, MKFWK_SEMICOLON, MKFWK_BACKSLASH, and MKFWK_NEWLINE. These are used throughout the other .mk files whenever a literal character would be misinterpreted by the Make parser.
Sets SHELL=/bin/sh and defines pathnames for all core utilities (AWK, CUT, ECHO, FIND, MKDIR, MV, PRINTF, RM, SED, SORT, TOUCH, TR, UNAME, and others). When STARTUP_CHECKS is enabled, it verifies that every required command exists and that $(shell ...) is functional. It also detects incompatible flags like -n/--dry-run.
Detects the host operating system by checking the OS environment variable. On Windows (OS=Windows_NT) it sets EXEEXT=.exe; on every other platform it leaves EXEEXT empty. All program name rules append $(EXEEXT) to executable targets so the same makefile works on both platforms.

Language and locale files

Before the header makefiles, main.mk includes locale-specific message files from $(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR). The default locale directory is lang/en_US/. Which files are loaded depends on active options:
include $(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR)unskippable.mk \
  $(if $(MUST_MAKE),$(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR)must_make.mk, \
    $(if $(VERBOSE),$(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR)verbose.mk)) \
  $(if $(RUNTIME_CHECKS),$(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR)runtime_checks.mk) \
  $(if $(STARTUP_CHECKS),$(MKFWK_LANG_DIR)$(MKFWK_CODE_DIR)startup_checks.mk)
Defines the minimum set of message strings used regardless of which options are active. It cannot be omitted.
Defines messages for the dry-run mode that prints what would be remade instead of actually building.
Defines the extended progress messages printed around each tool invocation (e.g., <<< CC: regenerating... >>>).
Defines error and informational messages used by the runtime command-existence checks in base.mk.
Defines error messages used during the startup validation phase in core.mk and base.mk.
main.mk defines MKFWK_FOOTER as a canned directive (using define). User makefiles must expand it at their very end:
$(eval $(value MKFWK_FOOTER))
$(value MKFWK_FOOTER) retrieves the raw, unexpanded text of the variable. $(eval ...) then feeds that text back to GNU Make as new makefile syntax. This two-step avoids premature expansion of $ references inside the canned directive. When MKFWK_DEPTH_STACK equals 1 (top-level makefile), the expansion includes the six footer makefiles and then clears the key variables. When called from a nested makefile it only pops the stack, doing nothing else.
Defines the all target and the MKFWK_INTERMEDIATE_TARGETS list. When REGENERATE_INTERMEDIATES is set, all depends on every intermediate file as well as the final binaries; otherwise intermediate files are listed under .SECONDARY so they are never automatically deleted but are not rebuilt unless a final binary needs them.
Defines the cleaning target hierarchy: cleandepsmostlycleancleandistcleanrealcleanclobbermaintainer-cleancleandirs. Each level removes a progressively wider set of generated files.
Defines targets for running programs (run-*), debugging with GDB (gdb-*), and analysing with Valgrind (valgrind-<tool>-*).
Contains all the pattern rules that compile .c files through the preprocessing, compilation, assembly, and object phases; rules that invoke YACC/Bison and LEX/Flex; rules for linking programs and building libraries; and the automatic dependency generation rules for .d and .d.timestamp files.
Clears .SUFFIXES to remove all built-in suffix rules, cancels predefined implicit rules that the framework does not use (RCS, SCCS, web, etc.), and clears dozens of unused built-in variables to reduce GNU Make’s memory footprint.

Directory variable summary

VariableDefault valuePurpose
MKFWK_HEADER_DIRmkframework/header/Location of the header .mk files
MKFWK_FOOTER_DIRmkframework/footer/Location of the footer .mk files
MKFWK_LANG_DIRmkframework/lang/Root of the locale directory tree
MKFWK_CODE_DIRen_US/Locale subdirectory to use
BINDIRbin/Output directory for programs and libraries
OBJDIRobj/Output directory for intermediate compiled files
DEPDIR.deps/Output directory for dependency .d files
All four framework directory variables are cleared after their respective include directives to prevent them from interfering with user-defined variables.

Build docs developers (and LLMs) love