Makefile学习7 - 静态模式规则与动态库编译

一. 前言

        本文以一个动态库编译的Makefile作为实例,讲解make中的静态模式规则的使用,加深对Makefile全方面的学习,达到学以致用的目的。

二. 静态模式规则

1. 语法

TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...
    COMMANDS
    ...

        从上面的语法规则可以看出,静态模式规则包含三部分:TARGETSTARGET-PATTERNPREREQ-PATTERNS

TARGETS:列出此规则的一系列目标文件,可以包含通配符。

TARGET-PATTERN:目标模式。一般会包含"%",其中"%"可以匹配目标文件中的任何部分,匹配的部分称为"茎",此外,目标文件和目标模式的其余部分必须精确的匹配,例如:

目标文件:foo.o

目标模式:%.o

茎:foo      -> 模式符合

目标文件:foo.c

目标模式:%.o

茎:无       -> 模式不符合

PREREQ-PATTERNS:依赖模式。每个目标的依赖文件使用目标模式的"茎"代替依赖模式中的"%"而得到。举例如下:

目标文件:foo.o

目标模式:%.o

目标依赖:%.c

        根据目标文件foo.o和目标依赖%.o,由上面介绍可以得出,"茎"是"foo",所以目标依赖%.c中%可以替换为foo,所以目标依赖就是foo.c了。

2. 举例

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

        根据上面语法的解释可知:该Makefile的目标文件是foo.o bar.o,目标模式是%.o,目标依赖是%.c。根据目标文件和目标模式,得出"茎"是foo和bar,所以目标模式时foo.o和bar.o,目标依赖是foo.c和bar.c。所以,相当于如下规则:

foo.o : foo.c
	$(CC) -c $(CFLAGS) foo.c -o foo.o
	
bar.o : bar.c
	$(CC) -c $(CFLAGS) bar.c -o bar.o

二. 动态库编译举例

1. 代码结构

├── include
│   ├── a.h
│   ├── b.h
│   ├── c.h
│   └── d.h
├── obj
└── src
    ├── a.c
    ├── b.c
    ├── c.c
    └── d.c

2. 目的

        将src中的所有C语言文件,编译成一个libtest.so的动态库,编译出的目标文件文件和库都放在obj目录下。

3. Makefile编写

INCDIR := include
SRCDIR := src
OBJDIR := obj
TARGET := libtest.so

SRCS := $(wildcard $(SRCDIR)/*)
OBJS := $(SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o)

CFLAGS += -Wall -g -I include -fPIC
LDFLAGS += -fPIC -shared

$(OBJDIR)/$(TARGET):$(OBJS)
	gcc $(LDFLAGS) $^ -o $@ 

$(OBJS):$(OBJDIR)/%.o:$(SRCDIR)/%.c
	@mkdir -p $(OBJDIR)
	gcc $(CFLAGS) -c $< -o $@

.PHONY:clean 
clean:
	@rm -rf $(OBJDIR)/*

        上面的例子($(OBJS):$(OBJDIR)/%.o:$(SRCDIR)/%.c)就使用了Makefile的静态模式规则,其中OBJS是目标文件(obj/a.o obj/c.o obj/b.o obj/d.o),而$(OBJDIR)/%.o是目标模式(obj/%.o),所以,"茎"分别为a,b,c和d,目标依赖则为src/a.c,src/b.c,src/c.c和src/d.c。这块代码的作用是分别将各个C语言文件编译成目标文件。

        最后,$(OBJDIR)/$(TARGET):$(OBJS)规则,将所有目标文件编译为最终的动态库。

三. 总结

        本文讲解了Makefile的静态模式规则的使用,并通过一个动态库编译的例子,加深了对静态模式规则的理解。