如何简化包含多可执行文件与依赖的Makefile?
用户提供了如下Makefile,希望简化它,同时询问如何生成所有文件的目标文件,再为各个可执行文件链接对应的目标文件:
# Program list: # a.cpp, a.h, # b.cpp, b.h, # c.cpp. c.h, # d.cpp, d.h, # commonA.cpp, commonA.h, # commonB.cpp, commonB.h, # mainA.cpp, mainB.cpp, # mainC.cpp, mainD.cpp. CXX=g++ CXXFLAGS = -std=c++11 -g -Wall prog1: mainA.cpp a.cpp $(CXX) $(CXXFLAGS) programOne mainA.cpp a.cpp prog2: mainB.cpp b.cpp $(CXX) $(CXXFLAGS) programTwo mainB.cpp b.cpp prog3: mainC.cpp c.cpp commonA.cpp $(CXX) $(CXXFLAGS) programThree mainC.cpp c.cpp commonA.cpp prog4: mainD.cpp d.cpp commonA.cpp commonB.cpp $(CXX) $(CXXFLAGS) programFour mainD.cpp d.cpp commonA.cpp commonB.cpp # etc...
用户提到查阅了GNU Make文档但觉得晦涩,想要清晰的简化方案。
Hey there! Let's break down how to simplify this Makefile using GNU Make's built-in features and best practices—no need to repeat all that redundant code.
核心思路
The key wins here are:
- Leverage Make's built-in compilation rules to auto-generate
.o(object) files from.cppfiles, so you don't have to write a rule for every single source file. - Use variables to group object files per executable, making the rules cleaner and easier to maintain.
- Use automatic variables to avoid repeating filenames in rule commands.
Step 1: Define Object File Groups
First, create variables that list all the object files each executable depends on. This makes it easy to update dependencies later:
# Define object files for each program PROG1_OBJS = mainA.o a.o PROG2_OBJS = mainB.o b.o PROG3_OBJS = mainC.o c.o commonA.o PROG4_OBJS = mainD.o d.o commonA.o commonB.o
Step 2: Simplify Executable Rules
Instead of writing a full compile/link command for each program, use Make's automatic variables:
$@= the target name (e.g.,prog1)$^= all dependencies (the list of.ofiles)
The link rule for each executable becomes super concise:
prog1: $(PROG1_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog2: $(PROG2_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog3: $(PROG3_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog4: $(PROG4_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^
Wait, but what about compiling the .cpp files to .o? You don't need to write those rules! GNU Make has a built-in rule that automatically runs:
g++ -std=c++11 -g -Wall -c mainA.cpp -o mainA.o
...for every .cpp file when it needs the corresponding .o file.
Step 3: Add a Default Target
Add an all target to build all your programs by default when you run just make:
all: prog1 prog2 prog3 prog4
Step 4: Add a Clean Rule
Add a clean target to delete all generated files (executables and object files) for easy cleanup:
clean: rm -f prog1 prog2 prog3 prog4 *.o
Step 5: (Optional) Auto-Generate Header Dependencies
If you want Make to automatically rebuild files when headers change (e.g., if you edit a.h, it should recompile a.cpp), add these lines to track header dependencies:
# Generate header dependency files CXXFLAGS += -MMD -MP # Include the generated .d files -include *.d
This adds -MMD -MP to your compiler flags, which tells g++ to generate .d files listing header dependencies. The -include line makes Make use those files.
Full Simplified Makefile
Putting it all together, your Makefile looks like this:
# Compiler and flags CXX = g++ CXXFLAGS = -std=c++11 -g -Wall -MMD -MP # -MMD -MP for header dependencies # Object file groups per executable PROG1_OBJS = mainA.o a.o PROG2_OBJS = mainB.o b.o PROG3_OBJS = mainC.o c.o commonA.o PROG4_OBJS = mainD.o d.o commonA.o commonB.o # Default target: build all programs all: prog1 prog2 prog3 prog4 # Executable rules prog1: $(PROG1_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog2: $(PROG2_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog3: $(PROG3_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ prog4: $(PROG4_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ # Clean up generated files clean: rm -f prog1 prog2 prog3 prog4 *.o *.d
Why This Works
- Less repetition: No more writing the same compile command over and over.
- Easier maintenance: If you add a new source file to a program, just update the corresponding
PROGx_OBJSvariable. - Automatic header tracking: The
-MMD -MPflags ensure Make knows when to recompile files if headers change. - Built-in rules: You don't have to manually define how to turn
.cppinto.o—Make handles that for you.
内容的提问来源于stack exchange,提问作者Athena

