• linux入门到精通-第七章-Makefile使用


    参考

    视频教程

    简介

    一个工程中的源文件不计其数,其按类型、功能、模块分别放在若千个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。
    Makefile带来的好处就是一”自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如: Delphi的make, Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

    make主要解决两个问题

    • 1)大量代码的关系维护
      大项目中源代码比较多,手工维护、编译时间长而且编译命令复杂,难以记忆及维护,把代码维护命令及编译命令写在makefile文件中,然后再用make工具解析此文件自动执行相应命令,可实现代码的合理编译
    • 2) 减少重复编译时间
      n 在改动其中一个文件的时候,能判断哪些文件被修改过,可以只对该文件进行重新编译,然后重新链接所有的目标文件,节省编译时间

    Makefile文件命名规则

    makefile和Makefile都可以,推荐使用Makefile
    make工具的安装

    sudo apt install make
    
    • 1

    Makefile语法规则

    一条规则:

    目标:依赖文件列表
    <Tab>命令列表
    
    • 1
    • 2

    Makefile基本规则三要素

      1. 目标:
        通常是要产生的文件名称,目标可以是可执行文件或其它obj文件,也可是一个动作的名称.
      1. 依赖文件:
        用来输入从而产生目标的文件
        一个目标通常有几个依赖文件 (可以没有)
      1. 命令:
        make执行的动作,一个规则可以含几个命令 (可以没有)
        有多个命令时,每个命令占一行

    测试demo,新建test.mk

    all: test1 test2
    	echo " all finished"
    test1: 
    	echo " test1 finished"
    test2: 
    	echo " test2 finished"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行

    root@sony-HP-Notebook:/usr/local/cpp_demo/makefile# make -f test.mk 
    echo " test1 finished"
     test1 finished
    echo " test2 finished"
     test2 finished
    echo " all finished"
     all finished
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    make命令格式

    make是一个命令工具,它解释Makefile 中的指令 (应该说是规则)。
    make命令格式

    make [ -f file ][ options ][ targets ]
    
    • 1

    1.[ -f file ]:

    • make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为makefile输入文件。-f可以指定以上名字以外的文件作为makefile输入文件

    2.[ options ]

    • -v: 显示make工具的版本信息
    • -w: 在处理makefile之前和之后显示工作路径
    • -C dir: 读取makefile之前改变工作路径至dir目录
    • -n: 只打印要执行的命令但不执行
    • -s: 执行但不显示执行的命令

    3.[ targets ]:

    • 若使用make命令时没有指定目标,则make工具默认会实现makefile文件内的第一个目标,然后退出指定了make工具要实现的目标,目标可以是一个或多个 (多个目标间用空格隔开)。

    例如:指定执行test1目标

    root@sony-HP-Notebook:/usr/local/cpp_demo/makefile# make test1 -f test.mk
    echo " test1 finished"
     test1 finished
    
    • 1
    • 2
    • 3

    Makefile的工作原理

    1)、若想生成目标,检查规则中的依赖是否存在,如不存在,则寻找是否有规则用于生成该依赖文件

    在这里插入图片描述

    2)、检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则目标必须更新
    在这里插入图片描述

    总结:

    • 分析各个目标和依赖之间的关系
    • 依靠依赖关系自底向上执行命令
    • 根据修改时间比目标新,确定更新
    • 如果目标不依赖任何条件,则执行对应命令,以示更新

    Makefile中的变量

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

    自定义变量

    1)定义变量方法:

    • 变量名=变量值

    2)引用变量:

    • $(变量名)或 ${变量名}

    3) makefile的变量名:

    • makefile变量名可以以数字开头
    • 变量是大小写敏感的
    • 变量一般都在makefile的头部定义
    • 变量几乎可在makefile的任何地方使用

    示例:

    #变量
    OBJS=add.o sub.o test.o
    TARGET=test
    $(TARGET):$(OBJS)
    	gcc $(OBJS) -o $(TARGET)
    add.o:add.c
    	gcc -c add.c -o add.o
    sub.o:sub.c
    	gcc -c sub.c -o sub.o
    test.o:test.c
    	gcc -c test.c -o test.o
    clean:
    	rm -rf $(OBJS) $(TARGET)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    执行

    # 编译
    make
    # 执行
    ./test
    
    • 1
    • 2
    • 3
    • 4

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

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

    Makefile自动变量

    • $@:表示规则中的目标
    • $<:表示规则中的第一个条件,即第一个依赖
    • $^:表示规则中的鄋条件,组成一个列表,以空格隔开,所有的依赖

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

    示例,新建rule.mk

    OBJS=add.o sub.o test.o
    TARGET=test
    CC=gcc
    # $@: 表示目标
    # $<: 表示第一个依赖
    # $^: 表示所有的依赖
    $(TARGET):$(OBJS)
    	# gcc $(OBJS) -o $(TARGET)
    	gcc $^ -o $@
    	echo $@
    	echo $<
    	echo $^
    add.o:add.c
    	# gcc -c add.c -o add.o
    	$(CC) -c $< -o $@
    sub.o:sub.c
    	# gcc -c sub.c -o sub.o
    	$(CC) -c $< -o $@
    test.o:test.c
    	# gcc -c test.c -o test.o
    	$(CC) -c $< -o $@
    clean:
    	rm -rf test
    	rm -rf *.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行

    # 清理
    make clean -f rule.mk 
    # 编译
    make -f rule.mk 
    # 执行
    ./test
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Makefile模式规则

    模式规则示例:

    %.o:%.c
    $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -0 $@
    
    • 1
    • 2

    Makefile第三个版本 model_rule.mk

    OBJS=add.o sub.o test.o
    TARGET=test
    CC=gcc
    # $@: 表示目标
    # $<: 表示第一个依赖
    # $^: 表示所有的依赖
    $(TARGET):$(OBJS)
    	# gcc $(OBJS) -o $(TARGET)
    	gcc $^ -o $@
    	echo $@
    	echo $<
    	echo $^
    # 模式匹配,所有的.o都依赖对应的.c
    # 将所有的.c生成对应的.o
    %.o:%.c
    	$(CC) -c $< -o $@
    clean:
    	rm -rf test
    	rm -rf *.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Makefile中的函数

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

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

    在makefile中所有的函数都是有返回值的
    Makefile第四个版本 fun_rule.mk

    SRC=$(wildcard *.c)
    OBJS=$(patsubst %.c, %.o, $(SRC)) 
    TARGET=test
    CC=gcc
    # $@: 表示目标
    # $<: 表示第一个依赖
    # $^: 表示所有的依赖
    $(TARGET):$(OBJS)
    	# gcc $(OBJS) -o $(TARGET)
    	gcc $^ -o $@
    	echo $@
    	echo $<
    	echo $^
    # 模式匹配,所有的.o都依赖对应的.c
    # 将所有的.c生成对应的.o
    %.o:%.c
    	$(CC) -c $< -o $@
    clean:
    	rm -rf $(OBJS) $(TARGET)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行

    # 清理
    make clean -f fun_rule.mk 
    # 编译
    make -f fun_rule.mk 
    # 执行
    ./test
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Makefile中的伪目标

    clean用途: 清除编译生成的中间.o文件和最终目标文件
    make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令,解决方案:
    伪目标声明:.PHONY:clean
    声明目标为伪目标之后makefile将不会该判断目标是否存在或者该目标是否需要更新

    clean命令中的特殊符号:

    • “-” 此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
    • “@” 不显示命令本身,只显示结果。如:”@echo clean done”

    第五个版本phony_rule.mk

    SRC=$(wildcard *.c)
    OBJS=$(patsubst %.c, %.o, $(SRC)) 
    TARGET=test
    CC=gcc
    # $@: 表示目标
    # $<: 表示第一个依赖
    # $^: 表示所有的依赖
    $(TARGET):$(OBJS)
    	# gcc $(OBJS) -o $(TARGET)
    	gcc $^ -o $@
    # 模式匹配,所有的.o都依赖对应的.c
    # 将所有的.c生成对应的.o
    %.o:%.c
    	@$(CC) -c $< -o $@
    # 声明clean为伪目标,伪目标不去判断目标文件是否存在,或者是否已经更新
    # 无条件执行命令
    .PHONY:clean
    clean:
    	-rm -rf $(OBJS) $(TARGET)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    【超好懂的比赛题解】2022CCPC四川省赛 个人题解
    PlacementAlias
    [计算机网络]认识“协议”
    湖北2022农民丰收节 国稻种芯:麻城启动王忠林宣布活动
    Webpack最简单的流程理解
    Linux内核读取spi-nor flash sn
    物联网开发的流程是怎么样的
    设计模式-13-职责链(责任链)模式
    C++--vector的使用和模拟实现
    python--列表list切分(超详细)
  • 原文地址:https://blog.csdn.net/Blueeyedboy521/article/details/131060155