《C++——makefile》

发布于:2025-08-31 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、Makefile 是什么

Makefile 是一个包含了一系列规则的文件,这些规则告诉 make 工具如何编译和链接程序。make 工具会根据 Makefile 中的规则,判断哪些文件需要重新编译,然后执行相应的命令,最终生成可执行文件或库。

二、基本规则格式

Makefile 的基本规则格式如下:

目标: 依赖
    命令
  • 目标:可以是可执行文件、目标文件,也可以是一个动作如 clean,可以理解为最后要生成的是什么。
  • 依赖:生成目标所需要的文件或其他目标。
  • 命令:生成目标所需要执行的命令(需要以 Tab 键开头)。

例如,我们有一个简单的 hello.cpp 文件,要编译它生成可执行文件 hello,可以写这样的规则:

hello: hello.cpp
    g++ hello.cpp -o hello

在这里插入图片描述

三、变量的使用

在 Makefile 中,我们可以使用变量来简化书写,尤其是当编译选项、文件列表等需要重复使用时。

我们可以自定义变量来表示编译选项、源文件列表等。例如:

# 定义编译器
CXX = g++
# 定义编译选项
CXXFLAGS = -std=c++11 -Wall
# 定义源文件列表
SRCS = hello.cpp world.cpp
# 定义目标文件列表,将源文件的 .cpp 替换为 .o
OBJS = $(SRCS:.cpp=.o)
# 定义可执行文件名
TARGET = my_program

可以理解为给这个文件定义了一个集合别名,就像模板一样

然后在规则中使用这些变量:

$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) $^ -o $@
%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

这里 $^ 表示所有的依赖文件,$< 表示第一个依赖文件,$@ 表示目标文件。

如果不用自定义:

# 最终可执行文件
my_program: hello.o world.o
	g++ -std=c++11 -Wall hello.o world.o -o my_program
	
# 编译hello.o
hello.o: hello.cpp
	g++ -std=c++11 -Wall -c hello.cpp -o hello.o

# 编译world.o
world.o: world.cpp
	g++ -std=c++11 -Wall -c world.cpp -o world.o

怎么比自定义还短?那我用自定义不是多此一举吗?
虽然在极简单的小项目中,直接写命令可能看起来更短,但当项目规模扩大、需求变化时,自定义变量的优势会非常明显,就如c++中的#define,typedef一样,在上千上万行代码里,一个一个去更改变量,不如提前定义好只需要修改定义的部分就行

四、多目标与伪目标

如果我们有多个可执行文件需要编译,可以在 Makefile 中定义多个目标。例如,我们有 server、client 两个可执行文件:

CXX = g++
CXXFLAGS = -std=c++11 -Wall
LDFLAGS = -lpthread

SERVER_SRCS = server.cpp
CLIENT_SRCS = client.cpp

SERVER_OBJS = $(SERVER_SRCS:.cpp=.o)
CLIENT_OBJS = $(CLIENT_SRCS:.cpp=.o)

all: server client

server: $(SERVER_OBJS)
    $(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
client: $(CLIENT_OBJS)
    $(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS)

%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -f server client $(SERVER_OBJS) $(CLIENT_OBJS)

在这里插入图片描述

这里使用了伪目标.PHONY: clean
伪目标不是一个实际的文件,而是一个动作的标识。最常见的伪目标是 clean,用于清理编译生成的文件。我们需要用 .PHONY 来声明伪目标,防止项目中存在同名文件时 make 误判。例如上面的 clean 目标,执行 make clean 会删除生成的可执行文件和目标文件。

五、实战

CFLAG= -std=c++11 -I ../../build/release-install-cpp11/include/
LFLAG= -L../../build/release-install-cpp11/lib  -lmuduo_net -lmuduo_base -pthread
all: server client text
server: server.cpp
	g++  $(CFLAG) $^ -o $@ $(LFLAG)
client: client.cpp
	g++  $(CFLAG) $^ -o $@ $(LFLAG)
text: text.cpp
	g++  $(CFLAG) $^ -o $@ $(LFLAG)

.PHONY:clean
clean:
	rm -f server client
  1. 变量定义:
    CFLAG:编译选项,指定 C++11 标准和第三方库(如 muduo)的头文件路径。
    LFLAG:链接选项,指定库文件路径及需要链接的库(muduo 网络库、基础库和线程库)。
  2. 目标规则:
    默认目标 all 会依次编译 server、client、text 三个可执行文件。
    每个目标对应一个 .cpp 源文件,通过统一的 g++ 命令编译,利用 $^(依赖文件)和 $@(目标文件)简化书写。
  3. 清理操作:
    clean 伪目标用于删除编译生成的可执行文件,但当前缺少对 text 的清理,需补充以避免残留。

通用 Makefile 模板:

# 编译器与选项
CXX = g++
CXXFLAGS = -std=c++11 -Wall -g
LDFLAGS = # 链接库(如需要可添加-lpthread -lm等)

# 项目文件
TARGET = main
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)

# 默认编译
all: $(TARGET)

# 链接
$(TARGET): $(OBJS)
	$(CXX) $^ -o $@ $(LDFLAGS)

# 编译
%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

# 清理
clean:
	rm -f $(OBJS) $(TARGET)

# 伪目标
.PHONY: all clean

一般只需要:

  • 改文件名:修改TARGET的值
  • 加库:在LDFLAGS后添加(如-L/path -lmuduo)
  • 改标准:调整CXXFLAGS中的-std=c++11(如c++17)

如果需要分开执行文件,可以不需要编译,生成多个执行文件


网站公告

今日签到

点亮在社区的每一天
去签到