基于子目录的C项目Makefile编写:生成test并存目标文件至obj
Perfect, I’ve put together a clean, maintainable Makefile tailored to your project structure. Let’s break this down step by step so you understand how it works, and you can tweak it later if needed.
First, let’s confirm your project layout matches what I’m building for:
./include/: Storesa.h,b.h,c.h./src/: Storesmain.c,a.c,b.c,c.c./obj/: Will hold all compiled.otarget files- Final executable:
test
Basic Functional Makefile
Save this as Makefile in your project root directory:
# Define compiler and core flags CC = gcc # Enable warnings + point compiler to your include directory CFLAGS = -Wall -Wextra -Iinclude # Directory paths for organization OBJ_DIR = obj SRC_DIR = src # Auto-detect all .c files in src/ SRCS = $(wildcard $(SRC_DIR)/*.c) # Convert src/*.c paths to obj/*.o (e.g., src/main.c → obj/main.o) OBJS = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRCS)) # Name of your final executable TARGET = test # Default target: run when you just type `make` all: $(TARGET) # Link all object files to build the executable $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@ # Compile individual .c files to .o files in obj/ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ # Create obj/ directory if it doesn't exist (order-only prerequisite) $(OBJ_DIR): mkdir -p $(OBJ_DIR) # Clean up all build artifacts clean: rm -rf $(OBJ_DIR) $(TARGET) # Mark these as "phony" (not actual files, so Make doesn't get confused) .PHONY: all clean
Key Explanations:
- Variables: Using variables makes it easy to update your compiler, flags, or directories later without rewriting the whole file.
$(wildcard)grabs all.cfiles insrc/, and$(patsubst)maps them to the correct.opaths inobj/. - Order-only prerequisite (
| $(OBJ_DIR)): Ensures theobj/directory exists before compiling, but won’t recompile everything if the directory’s timestamp changes. - Automatic variables:
$^: All prerequisites (all.ofiles for the executable)$<: The first prerequisite (the.cfile being compiled)$@: The target file (either the.ofile or the final executable)
clean: Deletes theobj/directory andtestexecutable to start fresh.
Advanced Version (Auto-Detect Header Dependencies)
If you want Make to automatically recompile files when you update a header (e.g., a.h), use this version which adds auto-dependency generation:
# Define compiler and flags (add -MMD -MP for auto-dependencies) CC = gcc CFLAGS = -Wall -Wextra -Iinclude -MMD -MP OBJ_DIR = obj SRC_DIR = src SRCS = $(wildcard $(SRC_DIR)/*.c) OBJS = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRCS)) # Auto-generated dependency files (one per .o file) DEPS = $(OBJS:.o=.d) TARGET = test all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ $(OBJ_DIR): mkdir -p $(OBJ_DIR) # Include auto-generated dependency files -include $(DEPS) clean: rm -rf $(OBJ_DIR) $(TARGET) .PHONY: all clean
What’s New?
-MMD -MP: Tellsgccto generate a.dfile for each.ofile, which lists all header dependencies for that source file.-include $(DEPS): Makes Make read these.dfiles, so it knows to recompile the right source files when you update a header.
How to Use
- Save the Makefile in your project root.
- Run
makein your terminal: it will build thetestexecutable and store all.ofiles inobj/. - Run
make cleanto delete all build files and start over.
内容的提问来源于stack exchange,提问作者Social Programmer
相关产品推荐
相关产品推荐

