一步一步搞懂Makefile

Makefile

Makefile是什么

问题:在linux下开发应用程序的时候,如果项目的源文件有一个或者几个我们可以通过:gcc xxx.c -o xxxx

来进行编译。那么如果有成百上千个的时候,还怎么通过这样的命令去实现?

那么这时候就需要一定的规则去编译链接这些源文件了,Makefile就是定义这些规则的文件,你可以把它理解为一个脚本,make就是执行脚本的工具,就像bash和shell脚本的.sh文件一样。

所以要开发一个大型项目,Makefile就必须写的好。这样编译工作就会很简单,一个make就搞定了。

Makefile的语法
target:requirement
<tab> cmd
...

这就是最基本的语法格式:

  • target就是要生成的目标,比如.o文件或者可执行文件,requirement,就是生成target所需要的源文件
  • 就是tab键,这里只能按tab,不能按空格,如果正确语句就会高亮,然后就是命令,这个命令生成,requirement

比如我们来看一个实例:项目目录下有1.c,2.c,3.c…,那么应该怎么写Makefile

app:1.o 2.o 3.o
	gcc -o app 1.o 2.o 3.o

1.o:1.c 1.h
	gcc -c 1.c
2.o:2.c 2.h
	gcc -c 2.c
3.o:3.c 3.h
	gcc -c 3.c

clean:
	rm -rf *.o

那么有多少个文件都这么写就可以了:

  • 首先要生成app,需要链接这下.o文件
  • 然后make会去找从哪生成这些.o文件就会继续向下执行
  • clean 是执行make clean 的时候就会被执行,否则不执行,因为他现在像是一个标签一样的,帮助make找到后面的动作
Makefile使用变量

上面的makefile虽然已经可以帮助我们做一些编译工作了,但是我们想想,是不是可以让其好看一点呢,我们平时都是使用变量来组织代码的,那么这如何使用变量,使用变量就像shell一样要用$

改进版:

OBJECTS = 1.o 2.o 3.o
app : $(OBJECTS)
	gcc -o app $(OBJECTS)
	
1.o:1.c 1.h
	gcc -c 1.c
2.o:2.c 2.h
	gcc -c 2.c
3.o:3.c 3.h
	gcc -c 3.c
	
clean:
	rm -rf $(OBJECTS)

	

这样的话如果再加入文件就只要修改OBJECTS就可以了,那么这样好像还是不好,因为每次都要写生成.o的操作,重复性太高了

Makefile自动推导

其实make是很强大的,在生成.o的时候,并不需要加上那么复杂的指令,我们可以这样写:

OBJECTS = 1.o 2.o 3.o
app : $(OBJECTS)
	gcc -o app $(OBJECTS)
	
1.o:1.h
2.o:2.h
3.o:3.h

.PHONY : clean
clean:
	rm -rf $(OBJECTS)

这里,要生成.o文件,make会自动的把.c加到依赖里面,然后后面的命令也会被推导出来。

.PHONY表示clean是一个伪依赖文件,在使用make clean的时候,如果目录下有clean,那么clean就不会被执行了,加上这个以后,就可以执行了。

到这里我么再来写一版:

OBJECTS = 1.o 2.o 3.o
app : $(OBJECTS)
	gcc -o app $(OBJECTS)
	
$(OBJECTS) : 1.h

.PHONY : clean
clean:
	rm -rf $(OBJECTS)

这样似乎更简单了,但是这样好像就看不清文件的依赖关系了,虽然我可以肯定的告诉你,make可以自动推导出来。

我们添加新的源码的时候,好像还是每一次都需要来修改OBJECTS,这时候就可以使用make的函数了。

make函数

先上代码:

SOURCE = $(wildcard *.c)
OBJECTS = $(patsubst %.c,%.o,$(SOURCE))
PROGRAM = app
CC = gcc
CFLAGS = -Wall 

$(PROGRAM) : $(OBJECTS)
	$(cc) -o $(PROGRAM) $(OBJECTS) $(CFLAGS)

$(OBJECTS) : $(SOURCE)

.PHONY : clean
clean:
	rm -rf $(OBJECTS) 
  • wildcard 的作用是把符合规则的文件展开成文件名,也就是1.c 2.c 3.c,然后我们这里使用一个变量接一下结果,当然也可以不使用。
  • patsubst,是pattern substitude匹配替换的缩写,它需要三个参数,第一个是需要匹配的式样,第二个是替换成什么样,第三个是一个以空格分开的列表,,我们这里替换完成后就是源文件对应的.o文件

到这里已经把makefile写了好几个版本了,好像已经很强大了,其实已经能解决很多项目的需要了,那么大型项目可以了吗?肯定还有更厉害的。

文件搜索

在一些很大型的工程中,源文件肯定是被放在不同的文件夹下的,因为为了分类,在这时候我们可以为文件加上路径,但是这样做太麻烦,可不可以让make帮我们呢,毕竟我们程序员是无所不能的,怎么会委屈了自己。

Makefile中有一个特殊的变量VPATH,如果没有设定这个变量,make就只会在当前路径下去找依赖的文件,现在我们可以这样写:

VPATH = src:../src

这时候就相当于定义了两个目录,一个是当前项目下的src一个是上一级目录下的src,当然了,可以指定更多,用:隔开即可,make会根据顺序去搜索。

还用一种方法就是使用vpath关键字,注意它不是变量是一个关键字,全是小写:

  1. vpath < pattern> < directories> 为符合模式< pattern>的文件指定搜索目录。
  2. vpath < pattern> 清除符合模式< pattern>的文件的搜索目录。
  3. vpath 清除所有已被设置好了的文件搜索目录。

比如:

vpath %.h ../src

这个就去上级目录的的src下搜索所有的.h文件,当然肯定是在当前目录下先找,因为当前目录永远是最先去找的。

好像Makefile到这就差不多了,其实还没有呢。在那些绝对顶级的大项目下,makefile长什么样呢?

超级大项目的Makefile
LIVEMEDIA_DIR = liveMedia
GROUPSOCK_DIR = groupsock
USAGE_ENVIRONMENT_DIR = UsageEnvironment
BASIC_USAGE_ENVIRONMENT_DIR = BasicUsageEnvironment
PULLER_MODULE_DIR = PullerModule
all:
    cd $(LIVEMEDIA_DIR) ; $(MAKE)
    cd $(GROUPSOCK_DIR) ; $(MAKE)
    cd $(USAGE_ENVIRONMENT_DIR) ; $(MAKE)
    cd $(BASIC_USAGE_ENVIRONMENT_DIR) ; $(MAKE)
install:
    mkdir -p $(PULLER_MODULE_DIR)/lib
    cd $(LIVEMEDIA_DIR) ; $(MAKE) install
    cd $(GROUPSOCK_DIR) ; $(MAKE) install
    cd $(USAGE_ENVIRONMENT_DIR) ; $(MAKE) install
    cd $(BASIC_USAGE_ENVIRONMENT_DIR) ; $(MAKE) install
module:
    cd $(PULLER_MODULE_DIR) ; $(MAKE)
    cd $(PULLER_MODULE_DIR) ; $(MAKE) test
clean:
    cd $(LIVEMEDIA_DIR) ; $(MAKE) clean
    cd $(GROUPSOCK_DIR) ; $(MAKE) clean
    cd $(USAGE_ENVIRONMENT_DIR) ; $(MAKE) clean
    cd $(BASIC_USAGE_ENVIRONMENT_DIR) ; $(MAKE) clean
    cd $(PULLER_MODULE_DIR) ; $(MAKE) clean
cleanall:
	cd $(PULLER_MODULE_DIR) ; $(MAKE) cleanall

all:下面有这样的 cd $(LIVEMEDIA_DIR) ; $(MAKE),就是先进入这个目录下,然后执行目录下的make就会按照目录下的Makefile执行了,然后继续这样的操作,把目录下的都执行了,然后剩下的就是install,module这样的伪目标,也是一样的,就是为使用make xxx进行的划分。

还有就是一些操作命令了,其实就是一个脚本的语法:

$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件
后话:

Makefile是大型项目的基本技能,所以还是有必要掌握的,现在比较好用的还有cmake,它可以用来生成linux下的makefile,和windows下的.sln文件,这两个都是项目中文件的依赖关系,还有在linux下有automake和autoconf这样的工具,因为可能写Makefile实在是有点小难啊,这两个工具就是用来管理GNU程序三部曲:”./configure”,”make”,”make instal”的工具,这样就可以更加简单的安装程序到Linux系统中了,有兴趣可以去了解一下。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值