make工具通过一个称为Makefile的文件来完成并自动维护编译工作。
Makefile文件描述了整个工程的编译、链接等规则。
Target… : DEPENDENCIES…
COMMAND
…
目标:程序产生的文件,如可执行文件和目标文件;目标也可以是可执行的动作,如clean,也称作伪目标。
依赖:是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。
命令:是make执行的动作(命令是shell命令或是可在shell下执行的程序)。注意:每个命令行的起始字符必须为TAB字符!
如果依赖文件列表DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心内容。
例子
假设当前目录下有main.c add.c sub.c add.h sub.h等文件,欲生成main可执行文件,则Makefile可以这么写:
注意命令行起始必须是TAB字符!!!
第一版
main:main.o add.o sub.o
gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
gcc -Wall -g -c sub.c -o sub.o
clean:
rm -rf main main.o add.o sub.o
第一版存在的主要问题在于如果当前目录下有名称为clean的文件,则make clean时就会出现问题。
第二版
第二版就是为了改进第一版存在的问题(显式指定伪目标)
.PHONY:clean
main:main.o add.o sub.o
gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
gcc -Wall -g -c sub.c -o sub.o
clean:
rm -rf main main.o add.o sub.o
如果不想在编译时显示编译命令,则在command前加入@符号
Makefile的自动化变量
- $@:规则的目标文件名
- $<:规则的第一个依赖文件名
- $^:规则的所有依赖文件列表
第三版
第三版主要是为了定义一些变量,让这个Makefile更为通用,少敲一些代码。ps:在Makefile中变量引用使用$(变量)这种方式。
.PHONY:clean
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
gcc -Wall -g $^ -o $@
main.o:main.c
gcc -Wall -g -c $< -o $@
add.o:add.c add.h
gcc -Wall -g -c $< -o $@
sub.o:sub.c sub.h
gcc -Wall -g -c $< -o $@
clean:
rm -rf main $(OBJECTS)
如何在当前目录下生成多个可执行文件
模式规则
%.o:%.c
后缀规则
.c.o:
(当前文件夹下.o文件对应着.c文件)
第一版
.PHONY:clean all
BIN=01test 02test
all:$(BIN)
#%.o:%.c
#gcc -Wall -g -c $< -o $@
.c.o:
gcc -Wall -g -c $< -o $@
01test:01test.o
gcc -Wall -g $^ -o $@
02test:02test.o
gcc -Wall -g $^ -o $@
clean:
rm -rf *.o $(BIN)
生成过程:生成all->生成BIN->生成01test和02test
第二版
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
#$(CC) $(CFLAGS) -c $< -o $@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
$(CC) $(CFLAGS) $^ -o $@
02test:02test.o
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -rf *.o $(BIN)
第三版
增加一个可执行文件03test,其依赖项03test.o abc.o
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test 03test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
#$(CC) $(CFLAGS) -c $< -o $@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
$(CC) $(CFLAGS) $^ -o $@
02test:02test.o
$(CC) $(CFLAGS) $^ -o $@
03test:03test.o abc.o
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -rf *.o $(BIN)
再增加一个可执行文件04test
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test 03test 04test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
#$(CC) $(CFLAGS) -c $< -o $@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
$(CC) $(CFLAGS) $^ -o $@
02test:02test.o
$(CC) $(CFLAGS) $^ -o $@
03test:03test.o pub.o
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -rf *.o $(BIN)>
make常用内嵌函数
函数调用
$(function arguments)
$(Wildcard PATTERN)
当前目录下匹配模式的文件
src=$(wildcard *.c)
$(patsubst PATTREN,REPLACEMENT,TEXT)
模式替换函数
(patsubst
src)/将src里的.c后缀文件替换为.o/
等价于$(src:.c=.o)
shell函数
执行shell命令
$(shell ls -d */)
多级目录的Makefile
所有目录只有一个可执行文件
**以下的Makefile适合当前目录存放main.c,子目录add/和sub/分别存放了main.c里用到的add和sub函数声明及定义add.c add.h sub.c sub.h
这种情况**
CC=gcc
CFLAGS=-Wall -g
CINCLUDES=-I./add -I./sub
BIN=main
SUBDIR=$(shell ls -d */)
ROOTSRC=$(wildcard *.c)
ROOTOBJ=$(ROOTSRC:%.c=%.o)
SUBSRC=$(shell find $(SUBDIR) -name '*.c')
SUBOBJ=$(SUBSRC:%.c=%.o)
$(BIN):$(ROOTOBJ) $(SUBOBJ)
$(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.c.o:
$(CC) $(CFLAGS) $(CINCLUDES) -c $< -o $@
clean:
rm -rf $(BIN) $(ROOTOBJ) $(SUBOBJ)
每个目录都可生成可执行文件
前提是想生成可执行文件的目录下有对应的Makefile
当前目录
SUBDIRS=test1 test2
.PHONY:default all clean $(SUBDIRS)
default:all
all clean:
$(MAKE) $(SUBDIRS) TARGET=$@
$(SUBDIRS):
$(MAKE) -C $@ $(TARGET)
$(MAKE) ==make
子目录
test1子目录下Makefile
CC=gcc
BIN=test1
OBJS=test1.o
.PHONY:all clean print
all:print $(BIN)
print:
@echo "---make all in $(PWD)---"
$(BIN):$(OBJS)
$(CC) $(OBJS) -o $@
.c.o:
$(CC) -c $<
clean:
@echo "---make clean in $(PWD)---"
rm -rf $(BIN) $(OBJS)
test2子目录下Makefile
CC=gcc
BIN=test2
OBJS=test2.o
.PHONY:all clean print
all:print $(BIN)
print:
@echo "---make all in $(PWD)---"
$(BIN):$(OBJS)
$(CC) $(OBJS) -o $@
.c.o:
$(CC) -c $<
clean:
@echo "---make clean in $(PWD)---"
rm -rf $(BIN) $(OBJS)>