如何编写一个基本的 Makefile
1. Makefile 的基本结构
一个典型的 Makefile 包含以下部分:
- 变量定义:用于存储编译器、编译选项、源文件等。
- 目标规则:定义如何生成目标文件。
- 伪目标:用于执行非文件生成的任务(如清理)。
2. 示例 Makefile 解析
以下是你提供的 Makefile 的解析和优化:
# 变量定义
bin = httpserver
cc = g++
LD_FLAGS = -std=c++11 -lpthread
src = main.cc
# 目标规则
$(bin): $(src)
$(cc) -o $@ $^ $(LD_FLAGS)
# 伪目标
.PHONY: clean
clean:
rm -rf $(bin)
变量定义
bin = httpserver
:定义目标可执行文件名为httpserver
。cc = g++
:定义编译器为g++
。LD_FLAGS = -std=c++11 -lpthread
:定义链接器标志(包含 C++11 标准和多线程支持)。src = main.cc
:定义源文件为main.cc
。
目标规则
$(bin): $(src)
:定义目标httpserver
依赖于main.cc
。$(cc) -o $@ $^ $(LD_FLAGS)
:使用g++
编译main.cc
,生成httpserver
。$@
:表示目标文件(即httpserver
)。$^
:表示所有依赖文件(即main.cc
)。
伪目标
.PHONY: clean
:声明clean
为伪目标。rm -rf $(bin)
:删除生成的可执行文件httpserver
。
3. 优化后的 Makefile
以下是优化后的 Makefile,增加了一些常用功能和注释:
# 变量定义
CC = g++ # 编译器
CXXFLAGS = -std=c++11 -Wall # 编译选项:C++11 标准,启用所有警告
LDFLAGS = -lpthread # 链接器选项:多线程支持
TARGET = httpserver # 目标可执行文件名
SRC = main.cc # 源文件
OBJ = $(SRC:.cc=.o) # 目标文件(将 .cc 替换为 .o)
# 默认目标
all: $(TARGET)
# 目标规则
$(TARGET): $(OBJ)
$(CC) -o $@ $^ $(LDFLAGS)
# 生成目标文件
%.o: %.cc
$(CC) $(CXXFLAGS) -c $< -o $@
# 清理生成的文件
.PHONY: clean
clean:
rm -rf $(TARGET) $(OBJ)
# 伪目标:重新构建
.PHONY: rebuild
rebuild: clean all
优化点
-
分离编译选项和链接选项:
CXXFLAGS
用于编译选项(如-std=c++11
)。LDFLAGS
用于链接选项(如-lpthread
)。
-
目标文件生成:
- 添加了
OBJ
变量,用于存储目标文件(.o
文件)。 - 使用
%.o: %.cc
规则,将.cc
文件编译为.o
文件。
- 添加了
-
默认目标:
- 添加了
all
目标,作为默认构建目标。
- 添加了
-
伪目标
rebuild
:- 添加了
rebuild
目标,用于先清理再重新构建。
- 添加了
4. 如何使用 Makefile
编译项目
在终端中运行以下命令:
make
这会生成可执行文件 httpserver
。
清理生成的文件
在终端中运行以下命令:
make clean
这会删除生成的可执行文件和目标文件。
重新构建项目
在终端中运行以下命令:
make rebuild
这会先清理,再重新构建项目。
5. Makefile 的常用技巧
变量扩展
$(SRC:.cc=.o)
:将SRC
变量中的所有.cc
替换为.o
。
自动依赖生成
可以使用 g++ -MM
自动生成依赖关系。例如:
DEP = $(SRC:.cc=.d)
%.d: %.cc
$(CC) -MM $< > $@
-include $(DEP)
多目录支持
如果项目有多个目录,可以使用 vpath
指定搜索路径。例如:
vpath %.cc src
vpath %.h include
6. 总结
- Makefile 的核心是目标规则和变量定义。
- 通过优化 Makefile,可以使构建过程更清晰、更高效。
- 使用
make
、make clean
和make rebuild
可以方便地管理项目。