You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简化包含多可执行文件与依赖的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 .cpp files, 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 .o files)

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_OBJS variable.
  • Automatic header tracking: The -MMD -MP flags ensure Make knows when to recompile files if headers change.
  • Built-in rules: You don't have to manually define how to turn .cpp into .o—Make handles that for you.

内容的提问来源于stack exchange,提问作者Athena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:41:24