The framework drives the complete transformation from raw source files to runnable programs or linkable libraries. Each stage of the pipeline is handled by a pattern rule defined inDocumentation 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.
making.mk, and each stage can be made the final stopping point by setting an option variable — letting you inspect preprocessed output, assembly code, or object files without changing the recipe logic.
Source file types
The framework recognises three source file extensions:| Extension | Language | Tool |
|---|---|---|
.c | C source | CC (gcc by default) |
.y | Yacc/Bison grammar | YACC (bison by default) |
.l | Lex/Flex scanner | LEX (flex by default) |
<name>_SOURCES variable. The framework infers which pipeline stages to run from the file extensions in that list.
Yacc/Bison pipeline
A.y grammar file is run through YACC before any C compilation happens:
bison produces three files in $(OBJDIR):
%.tab.c— the parser implementation in C%.tab.h— token definitions, included by scanner code and user headers%.output— a human-readable report of the parser states (with--report=state --report=itemset --report=lookaheadby default)
.tab.c file then feeds into the normal C compilation stages below.
Lex/Flex pipeline
A.l scanner file is processed by LEX:
%.lex.yy.c in $(OBJDIR) also feeds into the C compilation stages. When .y files are also present, making.mk arranges for the corresponding .tab.h file to be a prerequisite of the .lex.yy.c compilation step via MKFWK_YDEFS, ensuring the token header exists before the scanner is compiled.
C compilation stages
After code generation, every.c file (including generated .tab.c and .lex.yy.c) passes through up to four sub-stages. Three option variables control where the pipeline stops:
Preprocessing (.c → .i)
Enabled by setting When this is the final stage, dependency information is captured in the same invocation via
GENERATE_PREPROCESSING_OUTPUT=X. The compiler is called with -E to expand macros and #include directives, writing a .i file to $(OBJDIR):-MMD -MF.Compilation (.i or .c → .s)
Enabled by setting
GENERATE_COMPILING_OUTPUT=X. The compiler is called with -S to emit assembly code, writing a .s file to $(OBJDIR):Assembly (.s or .c → .o)
Enabled by default (Dependency tracking happens here too:
GENERATE_ASSEMBLING_OUTPUT=X). The compiler is called with -c to produce an object file in $(OBJDIR):-MMD -MF appended to the same command writes $(DEPDIR)*.d and then $(DEPDIR)*.d.timestamp is touched to record that the .d file is up to date.Linking (.o → program or library)
Object files are linked by a per-target explicit rule generated from Static libraries (Shared libraries (
mkfwk_rule_for_program, mkfwk_rule_for_static_library, or mkfwk_rule_for_shared_library.Programs (BIN_PROGRAMS) land in $(BINDIR) with $(EXEEXT) appended (.exe on Windows, empty elsewhere):BIN_LIBRARIES) are archived with AR into $(BINDIR)libname.a:BIN_SOLIBRARIES) are linked with -shared -Wl,-soname,name into $(BINDIR)libname.so. The -fpic flag is automatically added to all compilation steps for shared library sources.Intermediate file handling
GNU Make normally deletes files it treats as intermediates. The framework prevents unwanted deletion in two ways depending on theREGENERATE_INTERMEDIATES option:
REGENERATE_INTERMEDIATES | Behaviour |
|---|---|
Set (default X) | all explicitly depends on every intermediate file. Make keeps them and rebuilds them if they are removed. |
| Unset | Intermediate files are listed under .SECONDARY. Make never deletes them automatically, but does not rebuild them unless a final binary needs them. |
.DELETE_ON_ERROR special target is always active (set in base.mk), so a partially-written target file is removed if its recipe exits with a non-zero status.
Output directories
All generated files land in three directories, each configurable:| Variable | Default | Contents |
|---|---|---|
BINDIR | bin/ | Programs (.exe on Windows) and libraries (.a, .so) |
OBJDIR | obj/ | Intermediate compiled files (.tab.c, .lex.yy.c, .i, .s, .o) |
DEPDIR | .deps/ | Dependency files (.d, .d.timestamp) |
mkdir before any build step that needs them, using order-only prerequisites (| dir) on every rule.
The all target
all is always the .DEFAULT_GOAL. Its exact dependency list is built dynamically in central.mk:
MKFWK_INTERMEDIATE_TARGETS is computed by a sed script that maps each source path to its expected intermediate outputs (.tab.c/.tab.h/.output for .y, .lex.yy.c for .l, and .i/.s/.o for .c) based on which output options are currently enabled.
Pipeline summary
When
GENERATE_PREPROCESSING_OUTPUT, GENERATE_COMPILING_OUTPUT, and GENERATE_ASSEMBLING_OUTPUT are all unset at once, the framework bypasses the intermediate .i/.s/.o files and passes source files directly to the linker in a single compiler invocation. In practice, the default configuration (GENERATE_ASSEMBLING_OUTPUT=X) always produces .o files.