makefile若干知识


前言

  makefile 文件中定义了一系列的规则来指定, 哪些文件需要先编译, 哪些文件需要后编译, 哪些文件需要重新编译, 甚至于进行更复杂的功能操作, 因为 makefile 就像一个 Shell 脚本一样, 其中也可以执行操作系统的命令. makefile 带来的好处就是——“自动化编译”, 一旦写好, 只需要一个 make 命令, 整个工程完全自动编译, 极大的提高了软件开发的效率。

  make 是一个命令工具, 是一个解释 makefile 中指令的命令工具, 一般来说, 大多数的 IDE 都有这个命令, 比如:Visual C++ 的 nmake, Linux 下 GNU 的 make。 可见,makefile 都成为了一种在工程方面的编译方法。

  makefile 文件中会使用 gcc 编译器对源代码进行编译, 最终生成可执行文件或者是库文件。

  makefile文件的命名:makefile 或者 Makefile


提示:以下是本篇文章正文内容,下面案例可供参考

一、makefile的基本规则

makefile由一组规则组成,规则如下:

目标: 依赖
(tab)命令

makefile基本规则三要素:

  • 目标: 要生成的目标文件。

    扫描二维码关注公众号,回复: 14097534 查看本文章
  • 依赖: 目标文件由哪些文件生成。

  • 命令: 通过执行该命令由依赖文件生成目标。

下面以具体的例子来讲解:

如:当前目录下有main.cfun1.cfun2.csum.c, 根据这个基本规则编写一个简单的makefile文件, 生成可执行文件main

方法一:

  • 1、查看一下,该有的文件都有
    在这里插入图片描述
  • 2、创建一个makefile文件
    在这里插入图片描述
  • 3、在makefile文件里面输入下面这两行:

1)第一行
mian:(代表目标,我们给目标起名为mian)
mian.c fun1.c fun2.c sum.c(这些就是目标的依赖的文件)

2)第二行
tab出一个空格(这个空格区域只能用tab键,且tab一次)
后面街上gcc编译命令

在这里插入图片描述

  • 3、make命令生成目标文件

在这里插入图片描述

  • 4、执行
    在这里插入图片描述
    方法二:
main:main.o fun1.o fun2.o sum.o
        gcc -o main main.o fun1.o fun2.o sum.o

mian.o:mian.c
        gcc -c mian.c -I./
fun1.o:fun1.c
        gcc -c fun1.c 
fun2.o:fun2.c
        gcc -c fun2.c 
sum.o:sum.c
        gcc -c sum.c

在这里插入图片描述

二、makefile工作原理

  基本原则:若想生成目标, 检查规则中的所有的依赖文件是否都存在:

  • ① 如果有的依赖文件不存在, 则向下搜索规则, 看是否有生成该依赖文件的规则;
    ② 如果有规则用来生成该依赖文件, 则执行规则中的命令生成依赖文件;
    ③ 如果没有规则用来生成该依赖文件, 则报错。

在这里插入图片描述

  • 如果所有依赖都存在, 检查规则中的目标是否需要更新, 必须先检查它的所有依赖,依赖中有任何一个被更新, 则目标必须更新.(检查的规则是哪个时间大哪个最新)
    若目标的时间 > 依赖的时间, 不更新
    若目标的时间 < 依赖的时间, 则更新

在这里插入图片描述

  • 总结:
    分析各个目标和依赖之间的关系
    根据依赖关系自底向上执行命令
    根据依赖文件的时间和目标文件的时间确定是否需要更新
    如果目标不依赖任何条件, 则执行对应命令, 以示更新(如:伪目标)

三、makefile中的变量

  在makefile中使用变量有点类似于C语言中的宏定义, 使用该变量相当于内容替换, 使用变量可以使makefile易于维护, 修改起来变得简单。

makefile有三种类型的变量:

  • 普通变量

  • 自带变量

  • 自动变量

3.1 普通变量

① 变量定义直接用 =
② 使用变量值用 $(变量名)

如:下面是变量的定义和使用
foo = abc // 定义变量并赋值
bar = $(foo) // 使用变量, $(变量名)

  定义了两个变量: foo、bar, 其中bar的值是foo变量值的引用。

  除了使用用户自定义变量, makefile中也提供了一些变量(变量名大写)供用户直接使用, 我们可以直接对其进行赋值:

CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项 -I
CFLAGS: C编译器的选项 -Wall -g -c
LDFLAGS : 链接器选项 -L -l

3.2 自动变量

$@: 表示规则中的目标
$<: 表示规则中的第一个条件
$^: 表示规则中的所有条件, 组成一个列表, 以空格隔开, 如果这个列表中有重复的项则消除重复项。

Note:自动变量只能在规则的命令中使用.

3.3 模式规则

  至少在规则的目标定义中要包含’%’, ‘%’表示一个或多个, 在依赖条件中同样可以使用’%’, 依赖条件中的’%’的取值取决于其目标:

比如: main.o:main.c fun1.o: fun1.c fun2.o:fun2.c, 说的简单点就是: xxx.o:xxx.c

makefile的第3个版本:

target=main
object=main.o fun1.o fun2.o sum.o
CC=gcc
#makefile提供
CPPFLAGS=-I./  
#C预处理的选项 -I

$(target):$(object)
        $(CC) -o $@ $^ 
#$@是规则中的目标  $<表示规则中的第一个条件  $^表示规则中>的所有条件

%.o:%.c
        $(CC) -o $@ -c $< $(CPPFLAGS)

四、makefile函数

makefile中的函数有很多, 在这里给大家介绍两个最常用的。

1.wildcard – 查找指定目录下的指定类型的文件
src=$(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
2.patsubst – 匹配替换
obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o

在makefile中所有的函数都是有返回值的。
当前目录下有main.c fun1.c fun2.c sum.c
src=$(wildcard *.c)等价于src=main.c fun1.c fun2.c sum.c
obj=$(patsubst %.c,%.o, $(src))等价于obj=main.o fun1.o fun2.o sum.o

makefile的第4个版本::

src=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./

$(target):$(object)
        $(CC) -o $@ $^

%.o:%.c
        $(CC) -o $@ -c $< $(CPPFLAGS)

缺点: 每次重新编译都需要手工清理中间.o文件和最终目标文件

五、makefile的清理操作

用途: 清除编译生成的中间.o文件和最终目标文件

make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令, 解决方案:

  • 伪目标声明:
    .PHONY:clean
    声明目标为伪目标之后, makefile将不会检查该目标是否存在或者该目标是否需要更新

  • clean命令中的特殊符号:
    -”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o
    rm -f: 强制执行, 比如若要删除的文件不存在使用-f不会报错
    @”不显示命令本身, 只显示结果。如:“@echo clean done

  • 其它
    – make 默认执行第一个出现的目标, 可通过make dest指定要执行的目标
    – make -f: -f执行一个makefile文件名称, 使用make执行指定的makefile: make -f mainmak

makefile的第5个版本:

src=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./

$(target):$(object)
        $(CC) -o $@ $^

%.o:%.c
        $(CC) -o $@ -c $< $(CPPFLAGS)

.PHONY:clean
clean:
        -rm -f $(target) $(object)

总结

期待大家和我交流,留言或者私信,一起学习,一起进步!

猜你喜欢

转载自blog.csdn.net/CltCj/article/details/123613421