make详解

2023-05-16

Make

1. 学习make的必要性

在Linux中,有一个用来维护程序模块关系和生成可执行程序的工具-make。他可以根据程序模块的修改情况重新编译链接生成中间代码或最终的可执行程序。执行make 命令,需要一个名为“makefile”或“Makefile”的文本文件,这个文件定义了整个项目的编译规则。它定义了模块间的依赖关系,指定文件的编译顺序,以及编译所使用的命令。有了make命令和Makefile文件,整个项目的源程序文件可以自动编译,极大地提高了软件的开发效率。在这里插入图片描述

2. make的一般使用

目标文件列表 分隔符 依赖文件列表[; 命令]
     [命令] 注意:如果命令换行写,前面加Tab键。
     [命令]

 main.o : main.c defs.h
   		cc -c main.c
  main.o : main.c defs.h;cc -c main.c
  • make如何解释执行

   过时:是指一个文件生成后,用来生成该文件的源文件或头文件被修改了,导致生成该文件所需要的源文件或头文件的修改时间比生成该文件的时间完。

编译顺序:

  1. 如果只输入make命令。那么, make会在当前目录下找名字
    “Makefile”或“makefile”的文件。也可以命名为其他的名字make -f othername
  2. 它会找文件中的第一个目标文件(target)并把这个文件作为最终的目标文件。
  3. 观察目标文件是否过时,如果过时,执行规则后面的命令。否则,不执行。
  4. 从头到尾扫描完一遍Makefile文件后,make回溯一遍。

Makefile告诉make命令如何编译和链接这几个文件

  1. 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
  2. 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序.
  3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

3.Makefile文件的构成

Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。

  1. 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
  2. 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
  3. 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
  4. 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
  5. 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。
显示规则
main.o : main.c defs.h
	 	cc -c main.c
 clean:
 		rm *.o
  1. 在规则中使用通配符
    *通配符代替了你一系列的文件,如*.c表示所有后缀为c的文件
  2. 文件搜寻
    • 如果定义了VPATH变量,make就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。VPATH = src:../headers
    • 另一个设置文件搜索路径的方法是使用make的“vpath”关键字,它可以指定不同的文件在不同的搜索目录中。
      vpath < pattern> < directories>为符合模式< pattern>的文件指定搜索目录。
      vpath < pattern> 清除符合模式< pattern>的文件的搜索目录。
      vpath 清除所有已被设置好了的文件搜索目录。
      注意:vapth使用方法中的< pattern>需要包含%字符。%的意思是匹配零或若干字符,例如,%.h表示所有以.h结尾的文件。
  3. 伪目标
    “伪目标”并不是一个文件,只是一个标签,所以make无法生成它的依赖关系和决定它是否要执行。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。为了避免和文件重名的这种情况,我们可以使用一个特殊的标记.PHONY来显示地指明一个目标是伪目标,向make说明,不管是否有这个文件,这个目标就是伪目标
    于是整个过程可以这样写:
 .PHONY: clean
   clean:          
   	   rm *.o 

在Makefile中,一个伪目标可以有自己的依赖。在一个目录下如果需要生成多个可执行程序,可以在一个makefile中完成。

 all : prog1 prog2 prog3
 .PHONY : all
 prog1 : prog1.o utils.o
     cc -o prog1 prog1.o utils.o
 prog2 : prog2.o
     cc -o prog2 prog2.o
 prog3 : prog3.o sort.o utils.o
     cc -o prog3 prog3.o sort.o utils.o
  1. 多目标
    一个规则中可以有多个目标,规则所定义的命令对所有的目标都有效.

    mod1.o mod2.o mod3.o : commmand.c
    

这个规则同时实现给3个目标文件制定一个依赖文件.由于隐含规则的作用,它等价与下面的规则:

mod1.o : mod1.c  command.c
	gcc -c mod1.c -o mod1.o
mod2.o : mod2.c  command.c
	gcc -c mod2.c -o mod2.o
mod2.o : mod2.c  command.c
	gcc -c mod2.c -o mod2.o
隐含规则

make自动推导

main.o : main.c defs.h
	cc -c main.c
main.o : defs.h
使用变量
  1. 引用变量
    变量的引用方式是:$(变量)或者 ${变量},如果要使用字符$,要用$$来表示.

  2. 定义变量
    1.递归展开变量=

    foo = $(bar)
    bar = $(ugh)
    ugh = Huh?
    all:
    echo $(foo)
    执行“make all”将会打出变量$(foo)的值是“Huh?”
    

    2.立即展开变量:=

    x := foo
    y := $(x) bar
    x := later
    其等价于:
    y := foo bar
    x := later
    
  3. 预定义变量
    常用的自动变量:
    $@:表示一个规则中的目标文件
    $%:当规则的目标文件是一个静态库文件时,代表静态库的一个成员库.
    $<:规则中的第一个依赖文件名
    $>:规则中的第一个依赖文件名,它的值是库名.
    $?:所有比目标文件新的依赖文件列表,以空格分隔.
    $^:规则的所有依赖文件,使用空格分隔.
    $+:保留了依赖文件中重复出现的文件.主要用在程序链接时库的交叉引用场合.
    $*:他的值是目标场合去掉后缀后的名称.
    在这里插入图片描述

使用库

在大型软件开发中,通常把编译好的模块按照功能不同放在不同的库中.在Linux中,最后链接生成可执行文件时,如果链接的是一般.o文件,是把整个.o文件的内容插入到可执行文件中.而如果链接的是库,则只从库中找出程序需要的变量和函数,把它们装入到可执行文件中.使用库可以大大节省空间,所以系统提供的标准函数一般都是以库的形式提供.
库中的文件一般都是库的成员,成员的表示形式为:库员(成员名) mylib.a(file.o)
通常使用ar命令对它进行维护和管理
ar -ruv 库名 目标文件名

使用条件语句

ifeq表示条件语句的开始,并指定了一个比较条件(相等),还可以使用关键字ifneq,如果两个参数不相等.
else当条件不满足时要执行的部分
endif表示一个条件语句的结束,任何一个条件表达式都必须要以它结束

libs_for_gcc=-lgnu
normal_liba= 
foo:foo.c
ifeq($(CC),gcc)
	$(CC) -o foo foo.c $(libs_for_gcc)
else
	$(CC) -o foo foo.c $(normal_liba)
endif

ifdef用来判断一个变量是否已经定义,ifndef用来判断一个变量是否没有被定义.

bar=
foo=$(bar)
ifdef foo
frobozz=yes
else
frobozz=no
endif
make参数
  • -C dir 或者 --directory=DIR
    在读取Makefile文件之前,先切换到dir目录下.
  • -d
    make执行时打印出所有的调试信息.
  • -e
    不允许在Makefile中对系统环境变量进行重新赋值.
  • -f filename
    使用指定文件作为Makefile文件
  • -i
    忽略执行是产生的错误,不退出make
    在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

make详解 的相关文章

随机推荐

  • 【Docker】报错:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/

    报错原因 在VMWARE中安装的centos中查看容器Docker所安装的镜像命令时即执行 docker images 时虚拟机报错 xff0c 该用户没有此类权限 错误 xff1a Got permission denied while
  • linux ubuntu 彻底卸载包,清理linux软件卸载残留

    使用以下命令清理残留配置 xff0c 其实就是删除残留的 rc文件 dpkg span class token parameter variable l span span class token operator span span cl
  • list和array 访问不连续index

    python中内置数据类型list与numpy array都是常会用到的两种数据结构 二者在访问变量中不连续index时处理方式有所不同 array array访问不连续index的方式非常简单 xff0c 只需要用定义好的索引直接截取ar
  • TVM Windows conda 安装

    TVM Windows 安装 简介 本篇博客主要目的是帮助大家在windows平台上安装好tvm xff0c 并且可以顺利使用 因为有项目需要使用tvm xff0c 同时自己需要用windows做一些测试 xff0c 因此想要在window
  • 探讨ros下的cmakelists文件的编写

    文章目录 cmakelists文件整体架构分块讲解1 CMake版本2 软件包名称3 查找相关的CMake包4 消息 服务 动作生成器 cmakelists文件整体架构 所需CMake版本 xff08 cmake minimum requi
  • git 克隆指定分支

    git clone b 分支名 仓库地址
  • 【NVIDIA】Jetson Xavier NX镜像烧录

    设备信息 我的设备是Jetson Xavier NX xff1b 准备工作 鼠标 键盘 显示器SD卡 32GB至少 网线 xff08 也可以wifi xff09 官方教程 xff1a https developer nvidia com e
  • Android GPS学习 (二) :GPS 服务启动以及初始化流程

    扫码关注 xff0c 一起学习 1 GPS 服务启动 SystemServer java的startOtherServices方法中添加LocationManagerService方法的代码如下 frameworks base servic
  • docker运行ubuntu22.04出现异常(转载)

    原文链接 xff1a https xyz uscwifi xyz post PRTc2ZYZx 参考 xff1a docker Why I cannot run 96 apt update 96 inside a fresh ubuntu
  • 为什么执行同一个程序每次输出的变量地址是不一样的

    首先看一下下面的代码 include lt stdio h gt int main int a 61 1 printf 34 p n 34 amp a return 0 然后我就很疑惑 xff0c 为什么每次的地址都是不一样的 为什么会有这
  • 中断的基本概念

    异常和中断 概念 xff1a 程序执行过程中CPU会遇到一些特殊情况 xff0c 是正在执行的程序被 中断 xff0c cpu中止原来正在执行的程序 xff0c 转到处理异常情况或特殊事件的程序去执行 xff0c 结束后再返回到原被中止的程
  • 8086CPU结构与功能

    微处理器的外部结构 微处理器的外部结构如下图所示 8086CPU片有40个管脚 微处理器通过这些引脚与外部的逻辑部件连接 完成信息的交换 CPU的这些引脚称为微处理器级的总线 功能 与存储器之间交换信息 指令及数据 与I O设备之间交换信息
  • 8086微处理器的寄存器组织

    8086CPU内部有14个16位的寄存器 按功能可以分为8个通用寄存器 4个段寄存器和两个控制寄存器 通用寄存器 通用寄存器可以分为两类 数据寄存器 AX BX CX DX 和地址寄存器 变址寄存器 SI DI SP BP 8086CPU有
  • python dict setdefault()方法

    描述 Python 字典 setdefault 函数和 get 方法 类似 如果键不存在于字典中 xff0c 将会添加键并将值设为默认值
  • CPU原生支持的任务切换方式

    CPU 厂商原本计划的一种任务切换方法 xff0c 并不是操作系统实例中任务切换的方法 未采用的原因是此方法效率不高 xff0c 现代操作系统很少用这种方法切换任务 为了支持多任务 xff0c CPU 厂商提供了 LDT TSS 这两种原生
  • linux内核2.6.16版本启动分析(1)

    电脑的启动流程详见这篇博文电脑开机过程 简述一下就是按下电源键后 cs ip置位到0xffff0的位置 而这个位置是固化的 上面都刻录好了BIOS程序 BIOS执行基本的硬件自检以及建立中断向量表 初始化BIOS中断等 接下来会把第一块磁盘
  • linux内核目录分析

    最近准备开始研读linux的内核了 今天在deepin内核版本为4 8 15上编译安装了内核4 19 6 本来是先装2 6 16版本的 但2 6 16版本的内核版本要求gcc的版本为4 6之下 装4 6版本的gcc的时候出了点问题 还没解决
  • AT&T语法

    在linux内核编写中 为了维持与gcc输出汇编程序的兼容性 as汇编器使用AT amp T系统的V的汇编语法 下面简称为AT amp T语法 这种语法与Intel汇编程序使用的语法 简称Intel语法 很不一样 他们之间的主要区别有以下几
  • eBPF入门

    BPF和eBPF是什么 简单来说 BPF提供了一种在和各种内核和应用程序事件发生时运行一段小程序的机制 BPF是一项灵活而高效的技术 由指令集 存储对象和辅助函数等几部分组成 由于它采用了虚拟指令集规范 因此也可将它视作一种虚拟机的实现 这
  • make详解

    Make 1 学习make的必要性 在Linux中 有一个用来维护程序模块关系和生成可执行程序的工具 xff0d make 他可以根据程序模块的修改情况重新编译链接生成中间代码或最终的可执行程序 执行make 命令 xff0c 需要一个名为