target ... : prerequisites ...
command
prerequisites 中如果有一个以上的文件比 target 文件要新的话, command 所定义的
命令就会被执行。这就是 Makefile 的规则。也就是 Makefile 中最核心的内容。
只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make 找
到一个 whatever.o,那么 whatever.c,就会是 whatever.o 的依赖文件。并且 cc -c
whatever.c 也会被推导出来
例如
kbd.o command.o files.o : command.h
VPATH = src:../headers
上面的的定义指定两个目录,“src”和“…/headers”, make 会按照这个顺序进行搜索。
目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)
我们可以连续地使用 vpath(小写) 语句,以指定不同搜索策略。如果连续的 vpath 语句中出现了
相同的,或是被重复了的,那么, make 会按照 vpath 语句的先后
顺序来执行搜索。如:
vpath %.c foo
vpath % blish
vpath %.c bar
其表示“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录。
变量
$@ 表示目标文件
$^ 表示所有的依赖文件
$< 表示第一个依赖文件
$? 表示比目标还要新的依赖文件列表
%.o:%.c,
%.o 和要找的 test1.o 匹配
得到%=test1。
所以在后面的%.c就表示test1.c了
$(OBJS) : %.o : %.c
gcc -c $< -o $@
这两条命令的功能就是,大目标是OBJS,这个OBJS就是各种.o文件,然后%.o就是具体的解释,而%.c就是对应同样名字的.c文件,而下面的命令,结合了2个自动化变量,$< 表示依赖对象集中的第一个,$@ 则代表了目标集。所以这个功能就是要遍历所有的.c文件,对所有的.c文件进行编译,然后编译生成对应的.o文件。
目标
一个目标(target)就构成一条规则。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 a.txt 。目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。
除了文件名,目标还可以是某个操作的名字,这称为”伪目标”(phony target)。
clean:
rm *.o
上面代码的目标是clean,它不是文件名,而是一个操作的名字,属于”伪目标 “,作用是删除对象文件。
$ make clean
但是,如果当前目录中,正好有一个文件叫做clean,那么这个命令不会执行。因为Make发现clean文件已经存在,就认为没有必要重新构建了,就不会执行指定的rm命令。
为了避免这种情况,可以明确声明clean是”伪目标”,写法如下。
.PHONY: clean
符号
- ?=
PREFIX?=/usr/local 如果已经定义过变量PREFIX就保持不变,否则令其为
/usr/local - @ 运行make的时候不显示该命令
example
CFLAGS=-g -O2 -Wall -rdynamic -Wextra -Isrc -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local
SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/liblcthw.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
all: $(TARGET) $(SO_TARGET) tests
dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
ar rcs $@ $(OBJECTS)
ranlib $@
$(SO_TARGET): $(TARGET) $(OBJECTS)
$(CC) -shared -o $@ $(OBJECTS)
build:
@mkdir -p build
@mkdir -p bin
# The Unit Tests
.PHONY: tests
tests: LDLIBS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
# The Cleaner
clean:
rm -rf build $(OBJECTS) $(TESTS)
rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \;
rm -rf `find . -name "*.dSYM" -print`
# The Install
install: all
install -d $(DESTDIR)/$(PREFIX)/lib/
install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
# The Checker
check:
@echo Files with potentially dangerous functions.
@egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\
|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true
上述Makefile文件中
TEST_SRC=$(wildcard tests/*_tests.c)
负责找到所有测试文件
TESTS=$(patsubst %.c,%,$(TEST_SRC))
负责利用替换操作生成测试文件的目标,
比如test1.c生成test1.
src内的文件通过生成静态库的方式和测试文件链接
CFLAGS += $(TARGET)