makefile简单梳理总结总结

 

1、使用makefile的原因是因为,当工程很大的时候,有很多文件,这些文件也有可能很分散,若直接用gcc编译则拼写gcc命令很长,很麻烦,很容易出错,所以借助makefile工具将所有编译命令写到文件中帮助gcc编译,避免出错,方便管理。

2、makefile的命名只有两种方式makefile和Makefile

3、规则中的三要素:目标,依赖,命令。

目标依赖文件

           tab键后跟命令

举例子在main函数中依次会调用到add.c min.c mul.c div.c中的函数,我们期待生成一个App,写vi makefile文件中写makefile版本1如下内容

       App:main.c add.c min.c mul.c div.c

            gcc main.c add.c min.c mul.c div.c -o App

保存makefile内容退出后,在终端输入make指令即可编译执行。

4、make指令需要预先安装,安装指令为sudo apt install make

5gcc main.c add.c min.c mul.c div.c -o App这句话的缺点是每个文件都编译了一遍,假如我们只是修改了其中某一个文件的话,其实只用编译这个修改的文件即可。在有几百个文件的系统中,每次只编译更改的文件而不是全部编译这样效率更高。因此修改makefile版本2如下所示,

App:main.o add.o min.o mul.o div.o

    gcc main.o add.o min.o mul.o div.o -o App
 

main.o:main.c

gcc -c main.c

 

add.o:add.c

    gcc -c add.c
 

min.o:min.c

    gcc -c min.c
 

mul.o:mul.c

    gcc -c mul.c
 

div.o:div.c

    gcc -c div.c

以上的makefile中,第一行是终极目标(终极目标一定要写在最前边),当生成终极目标App时候发现没有main.o 然后就会往后边找,后边找到并生成main.o后,发现还缺add.o,继续再往后找,直到终极目标完成。当我们生成App可执行文件后,若发现第二次只修改add.c一个文件时候,此时make就只编译add.c一个文件。

makefile根据终极目标从上至下递归寻找依赖,然后从下至上执行命令直到生成终极目标。

 

6makefile的工作原理:makefile检查文件是否有更新,makefile看目标文件和依赖文件的最后更新时间,若依赖文件的时间更接近现在的时间,那么就证明依赖文件最近被修改过,需要通过执行命令编译新的依赖文件来更新目标文件了。

7makefile中的文件名字出现很多次,可以使用一个变量表示它们并替换它们,方便书写。

这里我们定义变量obj obj=main.o add.o min.o mul.o div.o然后用$符取obj中的值,$符的意思就是取变量中的值。例子如下

obj=main.o add.o min.o mul.o div.o

target=App

$(target):$(obj)

gcc $(obj) -o $(target)

 

main.o:main.c

gcc -c main.c

 

add.o:add.c

    gcc -c add.c
 

min.o:min.c

    gcc -c min.c
 

mul.o:mul.c

    gcc -c mul.c
 

div.o:div.c

    gcc -c div.c

 

8、对于很多行的的操作都一样,如对main.c add.c mul.c等的操作一样,只有名称不一样,我们可以使用模式规则来简化

使用模式规则之前

    main.o:main.c

        gcc -c main.c

使用模式规则之后

    %.o:%.c

        gcc $< -o $@

在这里当生成终极目标App时候需要检查依赖,当发现没有main.o ,就会向下寻找,找到这里就会匹配%.omain.o,由于%的内容一样的所以%c就为mainc,整行就为main.o:main.c。然后再依次查找add.omin.omul.odiv.o并执行相应的匹配。

$<$@$^都是makefile中的自动变量,自动变量就是指它的值是不定的。这三个自动变量只能在规则中使用。

$<表示当前规则中的第一个依赖,这里是指main.c

$@表示当前规则中的目标, 这里是指main.o

$^表示当前规则中所有的依赖,假如是终极目标那一行的所有依赖项这里是指main.oadd.omin.omul.odiv.o

综合以上我们修改makefile版本3如下

    obj=main.o add.o min.o mul.o div.o

    target = App

    $(target):$(obj)

        gcc $(obj) -o App

 

    %.o:%.c

        gcc -c $< -o $@

 

9makefile系统中还有一些系统维护的变量,这些系统变量都是大写的。系统维护的变量有些有默认值,有些没有默认值,无论有无默认值我们都可以修改。

CC的默认值为ccCC=cc(cc功能其实gcc)我么可以改为CC=gcc  CPPFLAGS是预处理时候选项可以设置为-ICPPFLAGS=-I此外还有编译时候参数CFLAGS和链接时候参数-Wall -g -c ,LDFLAGS链接库使用的选项 -L -l

 

10、makefile中所有的函数都有返回值,不使用返回值话,没必要使用makefile中的函数。

 

11当终极目标有很多依赖.o文件的时候,把所有.o文件写出来比较低效,且易出错。我们要生成终极目标需要所有.o文件,我们生成.o文件需要所有的.c,因此我们自下往上执行先找到.c文件,然后生成对应的.o文件,最后生成终极目标。我们可以借助makefilewildcard函数获取指定目录下的.c文件

    src= $(wildcard ./*.c)

  wildcard是函数名,是找到所有的.c文件的意思 ./*.c是函数参数 $(wildcard)是取函数wildcardd的返回值, wildcard函数查找某个目录下某种类型的文件,查到后以字符串形式返回,这里返回的是main.c add.c min.c mul.c div.c

     obj= $(patsubst ./%.c, ./%.o, $(src))

patsubst是函数名, 是匹配替换的意思./%.o, ./%.c, $(src)是指将当前文件下.c文件替换为.o文件, .c文件来源为$(src),然后obj就是main.o add.o min.o mul.o div.o

综合以上我们修改makefile版本4如下

    src= $(wildcard ./*.c)

    obj= $(patsubst ./%.o, ./%.c, $(src))

    target = App

    CC=gcc

    $(target):$(obj)

        $(CC) $(obj) -o App

 

    %.o:%.c

        gcc -c $< -o $@

 

12、有些时候我们每次需要删除.o文件,我们可以将这个操作写入makefile中, 一下clean这个目标没有依赖项,直接执行rm $(obj)操作

    clean:

        rm $(obj) $(target)

makefile中,由于终极目标是App,并且终极目标与clean这个目标无关,所以在终端黑窗口敲make并不会执行clean相关操作。

要想执行clean操作,需要在终端敲make clean指令,不过make clean这个指令只会执行生成目标cleanrm操作,不会执行其他操作如生成终极目标的操作。

有些时候当clean进行rm删除操作的时候,当没有对应文件会告警,我们可以加-f参数要求强制执行,不管文件存不存在这个指令都会执行。

    clean:

        rm $(obj) $(target) -f

 

13、有些时候我们当前文件下已经有一个clean文件,如我们touch clean 后,再然后执行make clean会发现提示当前的clean是最新的,没有执行相关操作。 这是由于makefile的工作原理是当发现目标是最新的时候就不更新或执行相应操作。我们为此可以添加一个伪目标,声明clean为伪目标,就不会再做比较哪个clean更新了,不会和本地磁盘的clean比较了。

.PHONY:clean声明clean为伪目标。

综合以上我们修改makefile版本5如下

    src= $(wildcard ./*.c)

    obj= $(patsubst ./%.c, ./%.o, $(src))

    target = App

    CC=gcc

    $(target):$(obj)

        $(CC) $(obj) -o App

 

    %.o:%.c

        gcc -c $< -o $@

 

    .PHONY:clean

    clean:

        rm $(obj) $(target) -f

14、特别注意有些时候会在指令前边加一个横杠-,表示的是当前命令执行失败的话,忽略错误继续往下执行。

 clean:

        -rm $(obj) $(target) -f

综合以上我们经常写的简单易懂makefile易读版本如下

   App:main.o add.o min.o mul.o div.o

    gcc main.o add.o min.o mul.o div.o -o App

 

    main.o:main.c

        gcc -c main.c

 

    add.o:add.c

        gcc -c add.c

 

   min.o:min.c

        gcc -c min.c

 

    mul.o:mul.c

        gcc -c mul.c

 

    div.o:div.c

        gcc -c div.c

 

    .PHONY:clean

    clean:

        -rm *.o App -f

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值