本篇文章主要是博主日常学习中使用的Makefile的经验总结,内容跨度比较大,不建议没有接触过Maekfile的博友们食用,如果有疑问可以评论留言;
一、简单的比较通用的Makefile模板
适用于目标只有一个且源文件和.h文件在同一目录下的情况,大体如下:
.
├── Makefile
├── friend.cpp
├── friend.h
├── main.cpp
├── mystring.cpp
└── mystring.h
Makefile编写如下(以上述文件举例)
/* 目标名 */
TARGET = main
/* 文件类型 */
EXTENSION = cpp
/* 要加的选项,此处文-O2级别的优化 */
#CXXFLAGS += -O2
/* 禁止优化 */
#CXXFLAGS += -fno-elide-constructors
/* 如果要链接动态库的话可以加一下变量 */
#LIBS =
#INCLUDE =
/* 当前路径下的所有源文件(.cpp)集合 */
SRC = $(wildcard *.$(EXTENSION))
/* 把SRC下所有.cpp文件名字替换为.o */
OBJS = $(patsubst %.$(EXTENSION), %.o, $(SRC))
/* 指定编译器 */
CC = g++
/* 把.o文件存放在指定的文件夹下,防止源文件和生成文件杂乱 */
BUILDDIR = build
OBJSDIR = $(BUILDDIR)/objs
/* 根据依赖关系来生成目标文件 */
$(TARGET) : $(BUILDDIR) $(OBJSDIR) $(OBJS)
$(CC) $(OBJSDIR)/*.o -o $@ $(CXXFLAGS)
/* 生成.o文件 */
$(OBJS): %.o:%.$(EXTENSION)
$(CC) -c $< -o $(OBJSDIR)/$@ $(CXXFLAGS)
/* 创建文件夹 */
$(BUILDDIR):
mkdir -p $(BUILDDIR)
$(OBJSDIR):
mkdir -p $(OBJSDIR)
/* 删除命令 */
.PHONY:clean
clean:
$(RM) $(OBJSDIR)/*.o $(TARGET) -r
make后效果如下:
.
├── Makefile
├── build
│ └── objs
│ ├── friend.o
│ ├── main.o
│ └── mystring.o
├── friend.cpp
├── friend.h
├── main
├── main.cpp
├── mystring.cpp
└── mystring.h
二、实现简单的外部构建(多目录下)
没有了解过的博友慎入,因为时间原因,下面的Makefile不再详细解释说明,希望可以给你带来一些帮助。
文件tree如下:
.
├── Makefile
├── include
│ ├── proto.h
│ └── site_type.h
├── medialib
│
└── src
├── client
│ ├── Makefile
│ ├── client.c
│ └── client.h
└── server
├── Makefile
├── medialib.c
├── medialib.h
├── mytbf.c
├── mytbf.h
├── server.c
├── server_conf.h
├── thr_channel.c
├── thr_channel.h
├── thr_list.c
└── thr_list.h
主要使用了两种方案:
1.server目录下和client目录下都写一个Makefile,通过主目录下的总控Makefile实现递归调用Make
2.主目录下编写一个Makefile通过伪目标同时生成两个可执行文件
第一种:
主控Makefile
CC = gcc
/* 库文件路径 */
CFLAGS += -I../../include
/* 当前目录路径 */
TOP_DIR := $(PWD)
/* .o文件生成路径 */
OBJSDIR = $(PWD)/build
/* 可执行文件生成路径 */
BINDIR = $(OBJSDIR)/bin
CLIENT_DIR := $(PWD)/src/client/
SERVER_DIR := $(PWD)/src/server/
/* 传递变量给子目录下的Makefile */
export CC CFLAGS OBJSDIR BINDIR
/* 嵌套调用子目录下的Makefile */
.PHONY:all clean
all:$(OBJSDIR) $(BINDIR)
$(MAKE) -C $(CLIENT_DIR)
$(MAKE) -C $(SERVER_DIR)
clean:
$(MAKE) -C $(CLIENT_DIR) clean
$(MAKE) -C $(SERVER_DIR) clean
$(RM) $(BINDIR)/* -r
$(OBJSDIR):
mkdir -p $(OBJSDIR)
$(BINDIR):
mkdir -p $(BINDIR)
server端Makefile
TARGET = server
CFLAGS += -pthread
OBJDIR = $(OBJSDIR)/server
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRC))
$(TARGET):$(OBJDIR) $(OBJS)
$(CC) -o $(BINDIR)/$(TARGET) $(OBJDIR)/*.o $(CFLAGS)
$(OBJS):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $(OBJDIR)/$@
$(OBJDIR):
mkdir -p $(OBJDIR)
.PHONY:clean
clean:
$(RM) $(OBJDIR)/*.o -r
client端Makefile
TARGET = client
OBJDIR = $(OBJSDIR)/client
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRC))
$(TARGET):$(OBJDIR) $(OBJS)
$(CC) -o $(BINDIR)/$(TARGET) $(OBJDIR)/*.o $(CFLAGS)
$(OBJS):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $(OBJDIR)/$@
$(OBJDIR):
mkdir -p $(OBJDIR)
.PHONY:clean
clean:
$(RM) $(OBJDIR)/*.o -r
第二种
TARGET1 = server
TARGET2 = client
CC = gcc
CFLAGS += -pthread
CFLAGS += -I../../include
CLIENTPATH := ./src/client
SERVERPATH := ./src/server
BUILD = build
OBJS = $(BUILD)/objs
BIN = $(BUILD)/bin
/* 分别找到两个路径下的.c生成对应的.o */
SERVERSRC = $(foreach dir, $(SERVERPATH), $(wildcard $(dir)/*.c))
CLIENTSRC = $(foreach dir, $(CLIENTPATH), $(wildcard $(dir)/*.c))
SERVEROBJS = $(patsubst %.c, $(OBJS)/%.o, $(notdir $(SERVERSRC)))
CLIENTOBJS = $(patsubst %.c, $(OBJS)/%.o, $(notdir $(CLIENTSRC)))
/* 添加搜索路径 */
VPATH = $(CLIENTPATH) : $(SERVERPATH)
all: $(BUILD) $(OBJS) $(BIN) $(TARGET1) $(TARGET2)
.PHONY : all clean install
$(TARGET1) : $(SERVEROBJS)
$(CC) $^ -o $@ $(CFLAGS)
$(TARGET2) : $(CLIENTOBJS)
$(CC) $^ -o $@ $(CFLAGS)
$(OBJS)/%.o : $(SERVERPATH)/%.c
$(CC) -c $< -o $@ $(CFLAGS)
$(OBJS)/%.o : $(CLIENTPATH)/%.c
$(CC) -c $< -o $@ $(CFLAGS)
$(BUILD):
mkdir -p $(BUILD)
$(OBJS):
mkdir -p $(OBJS)
$(BIN):
mkdir -p $(BIN)
clean:
$(RM) $(OBJS)/*.o server client -r
/* 把可执行文件下载到bin目录下 */
install:
mv $(TARGET1) $(TARGET2) ./build/bin
执行效果
小彩蛋:
关于Makefile和makefile这两种文件的创建,当同一目录下存在两个时,优先调用小写makefile,但平时我们程序员一般使用大写的Makefile,让客户或者同行拥有主动权,如果其需要对makefile有修改时,可以编写小写的makefile;
创作不易,如果对您有所帮助,可以请点赞收藏。