clinuxmakefile

How to write Makefile for debugging only one header and source in c


The lib folder contains many *.h and *.c files, and all files are in development phrase and they contain many errors including syntax errors. So I want to write the Makefile to debug all libraries one by one.

Here is the project folder structure (All *.c files contain the "main" function for testing purpose):

./Makefile

./src/lib/hello.h
./src/lib/hello.c
./src/lib/world.h
./src/lib/world.c
./src/lib/foo.h
./src/lib/foo.c
./src/lib/bar.h
./src/lib/bar.c

Here is the Makefile_hello for debugging "hello.h" and "hello.c":

CC = gcc
CFLAGS = -Wall -g
# How to include only "hello.h"?
INCLUDES = -Isrc/lilb
# How to write the rest for debugging only "hello.c"?

Here is the Makefile_world for debugging "world.h" and "world.c":

CC = gcc
CFLAGS = -Wall -g
# How to include only "world.h"?
INCLUDES = -Isrc/lilb
# How to write the rest for debugging only "world.c"?

How to write the correct Makefile?


Solution

  • # ==========================================================
    #   Makefile for Modular C Project with Debug Selector
    #   Usage:
    #     make                → build all modules (debug)
    #     make lib=foo        → build only foo.c / foo.h
    #     make mode=release   → build all in release mode
    #     make clean          → remove build artifacts
    # ==========================================================
    
    # Compiler and flags
    CC       := gcc
    MODE     ?= debug
    CFLAGS   := -Wall -std=c17
    INCLUDES := -Isrc/lib
    BUILD    := build
    
    ifeq ($(MODE),debug)
      CFLAGS += -g -O0
    else
      CFLAGS += -O2 -DNDEBUG
    endif
    
    # Source discovery
    SRC_DIR  := src/lib
    SRC_ALL  := $(wildcard $(SRC_DIR)/*.c)
    OBJ_ALL  := $(patsubst $(SRC_DIR)/%.c,$(BUILD)/%.o,$(SRC_ALL))
    EXE      := app
    
    # Optional single library
    LIB      ?=
    
    ifeq ($(LIB),)
      SRC := $(SRC_ALL)
      OBJ := $(OBJ_ALL)
      TARGET := $(EXE)
    else
      SRC := $(SRC_DIR)/$(LIB).c
      OBJ := $(BUILD)/$(LIB).o
      TARGET := $(BUILD)/$(LIB)_test
    endif
    
    # Build rules
    .PHONY: all clean dirs
    
    all: dirs $(TARGET)
    
    dirs:
        @mkdir -p $(BUILD)
    
    $(EXE): $(OBJ)
        $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
    
    $(BUILD)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
        $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
    
    $(BUILD)/%_test: $(BUILD)/%.o
        $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
    
    clean:
        rm -rf $(BUILD) $(EXE)