Makefile

利用make工具可以自动完成编译工作。这些工作包括:如果仅仅修改了某几个文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。这样做的好处就是不必要每次去编译所有文件,可大大的简化工作和节约时间。


make工具通过一个称为Makefile的文件来完成并自动编译工作。Makefile文件描述了整个工程的编译、连接等规则。

Makefile基本规则

Target .. : Dependencies...

    command

    ..

目标(Target)程序产生的文件,如可执行文件和目标文件;目标文件也可以是要执行的动作,如:clean,也称为伪文件

依赖(Dependencies)是用来产生目标的输入文件列表,一个目标文件通常依赖多个文件

命令(command)是make执行的动作;但是需要注意的是:每个命令行的起始字符必须始TAB字符!

如果Dependencies中有一个或多个文件更新的话,command就要执行,这是Makefile最核心的内容

看一个简单的例子

main.c add.c sub.c add.h sub.h
有上面四个文件,下面编写一个最简单的makefile文件

// makefile
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
执行

make 
gcc -Wall -g -c main.c -o main.o
gcc -Wall -g -c add.c -o add.o
gcc -Wall -g -c sub.c -o sub.o
gcc -Wall -g main.o add.o sub.o -o main
就这么的简单;如果我们更新add.h文件,再执行make

gcc -Wall -g -c add.c -o add.o
gcc -Wall -g main.o add.o sub.o -o main
在makefile文件的最后加上

clean:
	rm -r main main.o add.o sub.o
它只是用来删除生成的文件,又称之为伪目标,执行make clean

如果我们只是要编译mai.o,我们只需要 make main.o即可

再修改上面的代码:

.PHONY:clean  #伪目标一般需要在首行加入.PHONY:clean来定义,如果有个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 -r main main.o add.o sub.o

从上面的代码得知,我们最好还是需要有伪目标的时候定义;

在上面的代码中,你一定可以看出有非常多的重复的代码;在makefile中是可以定义变量

选项名作用
  $@规则的目标文件
  $<规则的第一个依赖文件名
  $^规则的所有依赖文件列表
上面的make可以改为

.PHONY:clean  #伪目标一般需要在首行加入.PHONY:clean来定义,如果有个clean就不能执行了
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
	gcc -Wall -g $^ -o $@ // gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
	gcc -Wall -g -c $< -o $@ // gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
	gcc -Wall -g -c $< -o $@ // gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
	gcc -Wall -g -c $< -o $@ // gcc -Wall -g -c sub.c -o sub.o
clean:
        @echo "delete ...."
        rm -r main $(OBJECTS) // rm -r main main.o add.o sub.o
再次运行make是可以执行的。(一般,makefile命名为Makefile, 可以指定文件为makefile;  make -f fileName

如果你不想打印,就在前面加@


Makefile编译多个可执行文件

模式规则:%.o; %.c  后缀规则.c .o

有两个文件,test1.c 和test2.c

test1.c
int main(void)
{
	return 0;
}
test2.c
int main(void)
{
	return 0;
}
它们都有main函数,看Makefile文件

.PHONY:clean all
BIN=testt test2 //BIN变量依赖test1.c和test2.c的文件
all:$(BIN) // all是伪目标;它需要生成test1和test2文件,编译器会自动的推导去生成文件名相同的执行文件
// 如果不需要推导,需要加上完整的代码
test1:test1.o
      gcc -Wall -g -c $^ -o $@
test2:test2.o
      gcc -Wall -g -c $^ -o $@
clean:
      rf -f $(BIN)
它生成了 test1 和test2可执行文件,显示生成.o文件所有的
.PHONY:clean all
BIN=test1 test2
all:$(BIN)
#将所有的.c文件生成.o文件
 %.o:%.c // .c.o:一样的效果
	gcc -Wall -g -c $< -o $@
test1:test1.o
	gcc -Wall -g $^ -o $@
test2:test2.o
	gcc -Wall -g $^ -o $@
clean:
	rm -f *.o $(BIN)

更加专业,修改上面的代码

.PHONY:clean all
CC=gc
CFLAGS=-Wall -g
BIN=test1 test2
all:$(BIN)
#将所有的.c文件生成.o文件
#%.o:%.c
.c.o:
	$(CC) $(CFLAGS) -c $< -o $@
test1:test1.o
	$(CC) $(CFLAGS) $^ -o $@
test2:test2.o
	$(CC) $(CFLAGS) $^ -o $@
clean:
	rm -f *.o $(BIN)

如果我们需要再加入test3.c,里面也包含main文件,但是它需要一个pub.c和pub.h文件,看下面代码

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=test1 test2 test3
all:$(BIN)
#将所有的.c文件生成.o文件
#%.o:%.c
.c.o:
	$(CC) $(CFLAGS) -c $< -o $@
test1:test1.o
	$(CC) $(CFLAGS) $^ -o $@
test2:test2.o
	$(CC) $(CFLAGS) $^ -o $@
test3:test3.o pub.o
	$(CC) $(CFLAGS) $^ -o $@
clean:
	rm -f *.o $(BIN)

Makefile的函数调用

$(function arguments)

下面是常见的Makefile函数

    $(wildcard PATTERN) 当前目录下匹配模式的文件;如src = $(wildcard *.c)

    $(patsubst PATTERN, REPLACENT, TEXT) 模式替换函数,例如($patsubst %.c, %.o, $src)<==>$(src:.c=.o)

    shell函数,执行shell命令 $(shell ls -d */)

看下面的列子,下面是包含2级目录的

.PHONY:clean
CC		= gcc
CFLAGS	= -Wall -g
BIN		= main #要生成的执行文件
SUBDIR  = $(shell ls -d */) #将当前文件下的所有文件都列出来,匹配/线
ROOTSRC = $(wildcard *.c) #当前下所有.c文件
ROOTOBJ = $(ROOTSRC:%.c=%.o) #将所有.c替换为o
SUBSRC	= $(shell find $(SUBDIR) -name '*.c') #列出所有.c文件
SUBOBJ	= $(SUBSRC:%.c=%.o) #所有.c文件替换为.o文件

$(BIN):$(ROOTOBJ) $(SUBOBJ)
	$(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.c.o:
	$(CC) $(CFLAGS) -c $< -o $@
clean:
	rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

我们如果仔细查看mysql或者php的源码,你可以发现,它其实是一次行 编译多个可执行文件,我们看个实验

一个目录结构

Makefile1   ---文件

--test1 ---目录

----main.c---主文件

----Makefile2---主文件

--test2 ---目录

----main.c---主文件

----Makefile3---主文件

SUBDIRS = test1 test2 (Makefile1)
.PHONY:default all clean $(SUBDIRS)
default:all

all clean:
	$(MAKE) $(SUBDIRS) TARGET=$@
$(SUBDIRS):
	$(MAKE) -C $@ $(TARGET)
CC = gcc (Makefile2)
BIN = main
OBJ = main.o
.PHONY: all clean print
all:print $(BIN)
print:
	@echo "------ make all in $(PWD) ----"
$(BIN):$(OBJ)
	$(CC) $(OBJ) -o $@
%.o:%.c
	$(CC) -c $<
clean:
	@echo "----- make clean in $(PWD) ----"
	rm -f $(BIN) $(OBJ)
CC = gcc (Makefile3)
BIN = main
OBJ = main.o
.PHONY: all clean print
all:print $(BIN)
print:
	@echo "------ make all in $(PWD) ----"
$(BIN):$(OBJ)
	$(CC) $(OBJ) -o $@
%.o:%.c
	$(CC) -c $<
clean:
	@echo "----- make clean in $(PWD) ----"
	rm -f $(BIN) $(OBJ)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值