静态模式形如:
$(OBJS): $(objdir)/%.o: %(srcdir)/%.c
$(CC) -c $(CFLAGS) $< -o $@
可以非常方便帮我们编译某文件夹下的所有.c (或.c++/.cc/.cpp等)文件,配合命令wildcard 、patsubst 、notdir 命令,可以非常方便指定源目录及中间文件目录等。
首先介绍上文中提到的三个命令(可以自行百度、Google),以下权当作个人记录
SRCS = $(wildcard $(DIR)/*.c) //提取DIR目录下所有.c文件,附带目录
CSRCS = $(notdir $(SRCS)) //提取所有文件,只包含文件名及后缀
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(CSRCS)) //将所有CSRCS中的.c文件后缀改为.o,并增加目录OBJDIR
举个例子:
1. 新建src文件夹,并于该文件夹下建立sr1.c sr2.c sr3.c 三个文件
2. 于src平级文件夹下建立obj文件夹
建立Makefile文件,写入以下语句:
DIR := ./src
OBJDIR := ./obj
SRCS = $(wildcard $(DIR)/*.c)
CSRCS = $(notdir $(SRCS))
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(CSRCS))
all:
@echo $(SRCS)
@echo $(CSRCS)
@echo $(OBJS)
目录结构如下:
|-.
|-obj
|-src
|-sr1.c
|-sr2.c
|-sr3.c
|-Makefile
SRCS 内容为:./src/sr1.c ./src/sr2.c ./src/sr3.c //取出所有.c文件并带着目录信息
CSRCS 内容为:sr1.c sr2.c sr3.c//去除目录信息,为了给将.o文件放入其他目录
OBJS 内容为:./obj/sr1.o ./obj/sr2.o ./obj/sr3.o//为.o文件加上目录信息
至此,在OBJS中保存了需要编译的所有中间文件,但此时文件并未生成,需要gcc编译得到
$(OBJS):$(OBJDIR)/%.o:$(DIR)/%.c
$(CC) -c $(CFLAGS) $< -o $@
使用make执行以上脚本,则可在./obj文件夹下得到sr1.o sr2.o sr3.o三个中间文件
这里简单解释:
1. 在Makefile静态模式中,中间项(两个:之间的项,这里是$(OBJDIR)/%.o)用于匹配首项(这里是$(OBJS))中的内容,由于OBJS中所有文件均类似$(OBJDIR)/filename.o,以$(OBJDIR)/%.o进行匹配,则%代表了filename也即是去除了后缀的文件名,再将此文件名跟上.c后缀并加上$(DIR)文件信息,则可以确定源文件位置
2. OBJS中所有项为$(OBJDIR)/filename.o 是为了保证gcc生成的中间文件全部位于$(OBJDIR)目录下,便于整理以及清理工作。
3. 注意:
a) 就上例而言,若中间项形如$(OBJDIR)/%.o,则%分别代表了sr1 、sr2、sr3
b)若中间项形如%.o,则 % 分别代表了$(OBJDIR)/sr1 、$(OBJDIR)/sr2、$(OBJDIR)/sr3, 这样匹配,将导致第三项$(DIR)/%.c变为 $(DIR)/$(OBJDIR)/sr1.c 、$(DIR)/$(OBJDIR)/sr2.c 、$(DIR)/$(OBJDIR)/sr3.c 最终导致无法找到源文件
c)在命令中,表示源文件的是"$<" 而不是 "$^",后者代表所有源的集合
进行以上操作之后,可将src目录下的所有.c文件生成的中间文件存入obj目录,如果有大量.c文件需要编译,使用该方法能够有效减轻Makefile文件大小,并使其干净、整洁