Makefile使用心得总结(实现简单的外部构建)

本篇文章主要是博主日常学习中使用的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;

创作不易,如果对您有所帮助,可以请点赞收藏。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值