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 supports building static archives (.a) and shared libraries (.so) alongside programs in the same GNUmakefile. This is useful for extracting reusable logic into a library, sharing code across multiple programs in the same repository, or producing a distributable library as the primary build output.

When to build libraries

Build a static library when you want to link a module directly into your final binary — the library code becomes part of the executable. Build a shared library when multiple programs should share the same compiled code at runtime, or when you are producing a .so for distribution.

Declaring libraries

Static library

Add the library filename (including the lib prefix and .a extension) to BIN_LIBRARIES:
BIN_LIBRARIES += libcalc.a

Shared library

Add the filename to BIN_SOLIBRARIES:
BIN_SOLIBRARIES += libcalc.so
The -fpic flag is added automatically for every shared library declared in BIN_SOLIBRARIES. You do not need to add it yourself to _CFLAGS.
Both BIN_LIBRARIES and BIN_SOLIBRARIES use the same BIN prefix as BIN_PROGRAMS. Output files are placed in BINDIR (default: bin/).

Required declarations per library

Libraries need _SOURCES just like programs do. Static libraries do not use _LDADD — only programs and shared libraries require a linking order. For a shared library, set _LDADD the same way you would for a program.
If STARTUP_CHECKS=X (the default) and _SOURCES is empty, the framework raises an error before any build starts. Always set _SOURCES for every declared library.

How AR and RANLIB work for static libraries

When building a static library, the framework runs:
ar -r -v 'bin/libcalc.a' 'obj/src/calc.o' ...
The ARFLAGS default is -r -v: -r inserts or replaces members, -v prints the member names as they are processed. After ar, the framework checks for ranlib at runtime. ranlib is a dispensable command — if it is not found, the build continues without it. When found, it runs:
ranlib 'bin/libcalc.a'
This regenerates the symbol table index in the archive, which is required by some linkers. You can override the RANLIB variable to point to a different indexer or clear it to skip the check entirely.

.SECONDARY and the -t option

When Make’s -t (touch) option is active, the framework uses a lighter-weight path for static libraries: it touches the archive file and runs ranlib -t (which updates the timestamp without reindexing), suppressing any errors that ranlib -t might produce on non-archive files:
# From making.mk — touch path for static libraries:
+$(TOUCH) '$@'
+$(if $(MKFWK_HAVE_COMMAND-RANLIB),$(RANLIB) -t '$@' 2>/dev/null || $(TRUE))

Linking a library into a program

Static library

Add the library to the program’s _LDADD in the correct link order (the program’s object files before the library):
$(program1)_SOURCES := $($(program1)_FIND_SOURCES)
$(program1)_LDADD   := $($(program1)_SOURCES) bin/libcalc.a
Point _LDFLAGS at the directory containing the library if it is not in a location the linker searches by default. The _FIND_-L_FLAGS mechanism can discover lib*.a and lib*.so files automatically:
$(program1)_LIBDIR := $($(program1)_SRCDIR)
$(call mkfwk_make_check_set_directory_existence,$(program1)_LIBDIR)

$(program1)_FIND_-L_FLAGS := $(sort \
    $(shell $(FIND) \
        $(if $($(program1)_SRCDIR),'$($(program1)_LIBDIR)',.) \
        -type f \( -name 'lib*.a' -o -name 'lib*.so' \) -print \
      | $(SED) -e 's?^\./??' -e 's?[^/]*$$??' -e 's?/$$??' \
               -e "s?^?-L'?" -e "s?$$?'?" \
               -e "s?^-L''$$?-L'.'?" ;))

$(program1)_LDFLAGS += $($(program1)_FIND_-L_FLAGS)
Alternatively, add an explicit -L flag:
$(program1)_LDFLAGS += -L'bin/'
And reference the library by its -l flag in _LDADD:
$(program1)_LDADD := $($(program1)_SOURCES) -lcalc

Shared library

Shared libraries are linked the same way. At runtime the program must be able to find the .so, either via LD_LIBRARY_PATH or by installing it to a standard location. You can also embed a runtime search path with -Wl,-rpath.

Complete example: static library

This example builds libcalc.a from src/calc.c and links it into myprogram. Project layout:
myproject/
├── GNUmakefile
├── mkframework/
├── src/
│   ├── main.c
│   ├── calc.c
│   └── calc.h
├── bin/
│   ├── myprogram
│   └── libcalc.a
└── obj/
    └── src/
        ├── main.o
        └── calc.o
GNUmakefile:
$(if $(MKFWK_MAIN_MAKEFILE),$(eval include $(MKFWK_MAIN_MAKEFILE)),$(eval include mkframework/main.mk))

.PHONY: $(MKFWK_LAST_INCLUDING_DIR)GNUmakefile

# ── Static library ───────────────────────────────────────────────────────────

lib1 := libcalc.a
BIN_LIBRARIES += $(lib1)

$(lib1)_SRCDIR := src/
$(call mkfwk_make_check_set_directory_existence,$(lib1)_SRCDIR)

# Discover only the library's own source files
$(lib1)_SOURCES := src/calc.c

$(lib1)_CPPFLAGS =
$(lib1)_CFLAGS   =
$(lib1)_ASFLAGS  =

# Static libraries do not have _LDADD

# ── Program ──────────────────────────────────────────────────────────────────

program1 := myprogram
BIN_PROGRAMS += $(program1)

$(program1)_ARGS :=
$(program1)_CWD  := $(BINDIR)

$(program1)_SRCDIR := src/
$(call mkfwk_make_check_set_directory_existence,$(program1)_SRCDIR)

$(program1)_SOURCES := src/main.c
$(program1)_LDADD   := src/main.c bin/libcalc.a

$(program1)_CPPFLAGS =
$(program1)_CFLAGS   =
$(program1)_ASFLAGS  =
$(program1)_LDFLAGS  = -L'bin/'

# ── Include path auto-discovery ──────────────────────────────────────────────

$(program1)_INCLUDEDIR := $($(program1)_SRCDIR)
$(call mkfwk_make_check_set_directory_existence,$(program1)_INCLUDEDIR)

$(program1)_FIND_-I_FLAGS := $(sort \
    $(shell $(FIND) \
        $(if $($(program1)_SRCDIR),'$($(program1)_INCLUDEDIR)',.) \
        -type f -name '*.h' -print \
      | $(SED) -e 's?^\./??' -e 's?[^/]*$$??' -e 's?/$$??' \
               -e "s?^?-I'?" -e "s?$$?'?" \
               -e "s?^-I''$$?-I'.'?" ;))

$(program1)_CPPFLAGS += $($(program1)_FIND_-I_FLAGS)

# ── Footer (must be last) ────────────────────────────────────────────────────

$(eval $(value MKFWK_FOOTER))
1

Build the library and the program

make all
The framework builds bin/libcalc.a first (because myprogram depends on it via _LDADD), then links bin/myprogram.
2

Inspect the archive

The -v flag in ARFLAGS prints each member as it is added:
<<< AR: Replacing members in archive: "bin/libcalc.a" >>>
a - obj/src/calc.o
<<< Done >>>
<<< RANLIB: Executing ranlib: "bin/libcalc.a" >>>
<<< Done >>>
3

Run the program

make run-myprogram

Complete example: shared library

$(if $(MKFWK_MAIN_MAKEFILE),$(eval include $(MKFWK_MAIN_MAKEFILE)),$(eval include mkframework/main.mk))

.PHONY: $(MKFWK_LAST_INCLUDING_DIR)GNUmakefile

# ── Shared library ───────────────────────────────────────────────────────────

solib1 := libcalc.so
BIN_SOLIBRARIES += $(solib1)

$(solib1)_SRCDIR := src/
$(call mkfwk_make_check_set_directory_existence,$(solib1)_SRCDIR)

$(solib1)_SOURCES := src/calc.c
$(solib1)_LDADD   := src/calc.c   # required for shared libraries

# -fpic is added automatically by the framework
$(solib1)_CPPFLAGS =
$(solib1)_CFLAGS   =
$(solib1)_ASFLAGS  =
$(solib1)_LDFLAGS  =

# ── Footer (must be last) ────────────────────────────────────────────────────

$(eval $(value MKFWK_FOOTER))
The framework passes -shared -Wl,-soname,'libcalc.so' to the linker automatically when building a shared library declared in BIN_SOLIBRARIES. You do not need to add these flags yourself.

Next steps

Multi-program project

Build multiple programs and libraries in one GNUmakefile.

Programs and libraries reference

Full variable reference for BIN_PROGRAMS, BIN_LIBRARIES, and BIN_SOLIBRARIES.

Build targets

All available make targets for building.

Pure C project

Start with the simplest single-program setup.

Build docs developers (and LLMs) love