Makefile:从零开始入门Makefile

目录

        1.前言

        2.Makefile的简单介绍

        3.Makefile中的指令规则

        4.Makefile的执行流程

        5.Makefile中的变量类型

        6.Makefile中的模式匹配

        7.Makefile中的函数

        8.Makefile补充知识


前言

        在Linux中编译CPP文件,我们能够使用GCC命令进行编译,但当项目文件多且繁杂的时候,使用GCC命令就会十分的麻烦。那么有没有一个脚本文件能直接处理我们编译的过程,按照我们设置好的编译流程进行文件的编译?这就是Makefile解决的问题。而为了执行Makefile文件,我们还需要使用make命令,用于解释Makefile中的指令的命令工具


Makefile的简单介绍

        Makefile是一个文件,通常没有扩展名,包含了一系列的指令和规则,用于指导make工具如何编译和链接程序。在Makefile文件中每个规则可以指定一系列的依赖项和要执行的命令,当你修改了源代码并希望重新编译项目时,make工具会根据Makefile中的规则来决定哪些部分需要重新构建。而Makefile带来的好处是能实现“自动化编译”,一旦写好Makefile,只需要一个make命令,整个项目完全自动编译,极大的提高了软件开发的效率

        Makefile文件有以下两种:

                1.makefile 

                2.Makefile

        在构建项目的时候在哪个目录下执行构建make命令,则这个目录下的makefile文件就会执行,因此在一个项目中可以存在多个makefile文件,分别位于不同的项目目录中


Makefile中的指令规则

        在描述Makefile文件中的规则时,我们先观察下面的图片:

图1.Makefile文件的简单命令

        观察上图,我们知道了一个简单的Makefile文件中的规则是由目标,依赖和命令组成的。这些标识具体意义如下:

                1.目标

                        1.目标和规则中的命令是一一对应的

                        2.通过执行规则中的命令,生成目标文件

                        3.规则中可以有多个命令,因此可以生成多个目标

                        4.伪目标:当执行规则后不生成任何文件

                2.依赖

                        1.在规则的命令中需要使用的依赖

                        2.规则的依赖为空,则代表命令不需要任何依赖

                        3.当前规则中的依赖可以是其他规则中的目标文件

                3.命令

                        1.当前规则的执行语句,一般情况下是一个shell命令
                        2.一个规则的命令可以是多个,每个命令前必须有一个Tab缩进并且独占占一行

        在了解到Makefile文件中的指令规则的具体组成后,我们还需要知道以下几点:

                1.目标与依赖之间以":"为间隔

                2.可以存在多个目标和依赖,具体的目标与依赖之间使用","分割或者空格分割

                3.每一条命令独占一行,以一个TAB键开头,且一个规则存在多条命令

        具体可参考以下Makefile文件示例:

//多个目标文件,多个依赖,多个命令
Demo1 Demo2 : main.cpp fun.cppg++ main.cpp -o Demo1g++ fun.cpp -o Demo2

PS:在Makefile文件中存在自动推导功能,如果依赖没有指明的化,只要当前目录符合编译条件,那么使用make指令都能成功执行Makefile文件


Makefile的执行流程

        当我们编写好Makefile文件时,我们需要使用make命令执行当前目录下的Makefile文件,在我们于终端中输入make指令并回车时,会按照以下步骤进行执行:

                步骤1:在当前目录查找Makefile文件,存在则执行步骤2,不存在则不执行

                步骤2:查看Makefile文件的规则中的依赖文件是否存在,存在则执行命令,不存在则执行步骤3

                步骤3:当规则中的依赖文件不存在时,则会遍历Makefile文件中的其他规则,寻找能生成当前依赖文件的规则,并执行

        通过以上三个步骤,我们了解了Makefile的大致的执行流程,而当我们重复执行make指令时则不会再通过以上步骤进行执行,而是执行以下几个步骤:

                步骤1:查看当前规则的目标文件是否存在,不存在则执行命令,存在则执行步骤2

                步骤2:查看当前规则的目标文件和依赖文件的修改时间,如果目标文件修改时间晚于依赖文件则不执行操作,早于依赖文件则执行步骤3

                步骤3:当目标文件的修改时间早于依赖文件,即依赖文件在生成目标文件后被修改过,则执行命令更新目标文件

        以上便是具体的Makefile的执行流程,当我们执行make指令时,我们还可以指定执行对应的规则,具体示例如下:

//Makefile文件中的内容,存在多条规则
Demo1 : main.cppg++ main.cpp -o Demo1
Demo2 :  fun.cppg++ fun.cpp -o Demo2//执行指定的生成Demo2目标文件的规则
make Demo2

图2.使用make命令执行指定的规则

PS:当规则中存在多个依赖文件时,只要有一个依赖文件被修改,则会执行命令。即如果命令是编译依赖文件生成目标文件的情况,那么执行make命令则会对所有的依赖执行编译,而不是对被修改的依赖文件执行编译,会导致编译时间长


Makefile中的变量类型

        在编写Makefile文件时,常常会遇到规则中的命令过于冗长,且重复语句过多的情况,为了解决这些问题,Makefile提供了变量类型。在Makefile中变量类型分为以下几种:

        1.自定义变量

                在Makefile中使用自定义变量时,需要对变量进行初始化,不能单独声明变量,在使用变量的时候可以使用$来对变量取值(类似于PHP),具体参考以下代码:

#普通写法
Demo : main.cppg++  main.cpp -o Demo#使用自定义变量写法
target = Demo
reliance = main.cpp
$(target) : $(reliance)g++  $(reliance) -o $(target)

        2.预定义变量

                Makefile中的预定义变量是指在Makefile中已经定义的变量,可以直接使用这些变量编写脚本。预定义变量如下表:

预定义变量备注默认值
AR生成静态库库文件的程序ar
AS汇编编译器as
ARFLAGS生成静态库库文件程序无默认值
ASFLAGS汇编语言编译器的编译无默认值
CCC 编译器cc
CPPC 预编译器$(CC) -E
CXXC++编译器g++
CFLAGSC编译器的编译选项
CPPFLAGSC预编译的编译选项
CXXFLAGS C++编译器
FCFORTRAN编译器f77
FFLAGSFORTRAN编译器
RM删除文件程序rm -f

表1.预定义变量表

#普通写法
Demo : main.cppg++ main.cpp -o Demo#使用预定义变量写法
Demo : main.cpp$(CXX)  main.cpp -o Demo 

        3.自动变量

                自动变量在规则执行时自动设置,通常与当前正在处理的目标和依赖项有关,且自动变量只能在规则的命令中使用。以下是几种Makefile中的自动变量:

自动变量备注
$@表示规则中的目标文件名
$<表示规则中的第一个依赖项
$?表示规则中所有比目标新的依赖项
$^表示规则中所有的依赖项,不包括重复的
$+与 $^ 相同,但是会包括重复的依赖项
$|表示规则中所有比目标新的依赖项,不包括目标自身
$*表示不包含后缀的依赖项或目标文件名
$(@D)表示目标文件的目录
$(@F)表示目标文件的文件名

表2.自动变量表

#普通写法
Demo : main.cppg++  main.cpp -o Demo#使用自动变量x写法
Demo : main.cppg++ $^ -o $@

Makefile中的模式匹配

        当Makefile中的规则大多数都只是因为文件不同而添加不同的规则时,我们可以把这些类似的规则写成模板(类似于C++中的模板),以下对Makefile中的模板进行讲解:

        1.在Makefile中使用"%"对字符进行匹配(类似于*通配符) 

        2.以下是一个简单的Makefile文件:

Demo : fun.o  main.og++  fun.o main.o -o Demofun.o : fun.cppg++ fun.cpp -cmain.o : main.cppg++ main.cpp -c

        3.在上述代码中,我们可以发现存在两条规则相似,具体如下如图:

图3.规则相似

        4.此时我们可以使用Makefile中的模式匹配,写一个规则对以上类似的规则进行匹配:

Demo : fun.o  main.og++  fun.o main.o -o Demo#模式匹配
%.o : %.cppg++ $< -c

PS:一个Makefile文件中可以存在多个模板,当依赖文件不存在时,会对模板进行查询生成文件,当多个依赖符合同一个模板时,则该模板会被执行多次


Makefile中的函数

        Makefile中的函数用于在构建过程中执行一些命令,并根据命令执行结果返回相应的值。其中存在两种格式的函数:

                1.内置函数:是由 Make 工具提供的一些预定义函数,如shell函数、subst函数、patsubst函数等

                2.自定义函数:则是用户根据需要自行定义的函数,可以根据具体情况编写不同的函数来实现自己的需求

        具体的在Makefile中使用函数的语法如下:

$(FUNCTION_NAME arguments)
UNCTION_NAME为函数名,arguments 为函数的参数

        在了解了Makefile中的函数后,我们先学习Makefile中的内置函数:

                1.wildcard函数:用于展开指定的目录

$(wildcard PATH)
PATH代表指定展开的目录

图4.wildcard函数的使用

                2.notdir函数:用于去掉文件路径

$(notdir PATH)
PATH代表去掉路径的文件

图5.notdir函数的使用

                3.patsubst函数:用于替换文件后缀

$(patsubst 更改前的后缀, 更改后的后缀, $(文件)) 

Makefile补充知识

        在第二小节曾说过伪目标,其伪目标是指当执行规则后不生成任何文件。当我们的目标文件为最新的时候,再执行make指令则会提示目标文件为最新,而使用伪目标则可以不提示这警告继续执行make指令。要使用伪目标则需要对目标文件进行伪目标的声明,如下:

.PHONY:Demo     #使用.PHNOY将目标文件声明为伪目标
Demo : main.cppg++  main.cpp -o Demo

        在执行Makefile脚本的时候,可以在规则中指定强制执行命令,如下:

Demo : main.cpp-g++  main.cpp -o Demo
#使用"-"号表示该命令强制执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/26009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不能访问huggingface、与GPU配置

不能访问huggingface解决方法 如果是从 huggingface.co 下载模型&#xff0c;由于国内不能访问&#xff0c;所以建议先配置一下环境变量&#xff0c; 通过访问国内镜像站点 https://hf-mirror.com来下载模型。 &#xff08;1&#xff09;Linux系统设置环境变量&#xff1a; e…

【Android Studio】导入import android.support.v7.app.AppcompatActivity;时报错

一、问题描述 在进行安卓项目开发时使用import android.support.v7.app.AppcompatActivity;报错&#xff1a; 运行后会有乱码出现&#xff1a; 二、解决办法 将import android.support.v7.app.AppcompatActivity;改为import androidx.appcompat.app.AppCompatActivity;基本上…

一篇文章搞定Java数组初始化,从此告别迷惑

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

面试官:Spring如何解析配置类

你好&#xff0c;我是柳岸花开。 大家好&#xff0c;今天我们来深入探讨一下Spring框架中的配置类解析与扫描过程的源码。Spring作为Java开发中最为广泛使用的框架之一&#xff0c;其核心机制一直是开发者关注的焦点。本文将带领大家从源码角度&#xff0c;详细剖析Spring配置类…

红黑树/红黑树迭代器封装(C++)

本篇将会较为全面的讲解有关红黑树的特点&#xff0c;插入操作&#xff0c;然后使用代码模拟实现红黑树&#xff0c;同时还会封装出红黑树的迭代器。 在 STL 库中的 set 和 map 都是使用红黑树封装的&#xff0c;在前文中我们讲解了 AVL树&#xff0c;对于红黑树和 AVL 树来说&…

k8s 1.28 搭建rabbitmq集群

1.环境 1.1 k8s 1.28 1.2 rabbit 3.8 1.3 工作空间default 1.4 注意&#xff0c;内存最好充足一点&#xff0c;因为我就两个节点一个master、一个node&#xff0c;起初我的node是8g&#xff0c;还剩3~4G&#xff0c;集群竟然一直起不来&#xff0c;后来将虚拟机内存扩大&#x…

Word中插入Mathtype右编号,调整公式与编号的位置

当你已经将mathtype内置于word后&#xff0c;可以使用右编号快速插入公式 但是往往会出现公式和编号出现的位置或之间的距离不合适 比如我在双栏下插入公式&#xff0c;会发现插入的公式与编号是适用于单栏的 解决办法&#xff1a; 开始->样式->MTDisplayLquation -&g…

AWT常用组件

AWT中常用组件 前言一、基本组件组件名标签(Label类)Label类的构造方法注意要点 按钮(Button)Button的构造方法注意要点 文本框(TextField)TextField类的构造方法注意要点 文本域&#xff08;TextArea&#xff09;TextArea 的构造方法参数scrollbars的静态常量值 复选框&#x…

排序-读取数据流并实时返回中位数

目录 一、问题描述 二、解题思路 1.顺序表排序法 2.使用大根堆、小根堆 三、代码实现 1.顺序表排序法实现 2.大根堆、小根堆法实现 四、刷题链接 一、问题描述 二、解题思路 1.顺序表排序法 &#xff08;1&#xff09;每次读取一个数就对列表排一次序&#xff0c;对排…

Python异步爬虫批量下载图片-协程

import aiofiles import aiohttp import asyncio import requests from lxml import etree from aiohttp import TCPConnectorclass Spider:def __init__(self, value):# 起始urlself.start_url value# 下载单个图片staticmethodasync def download_one(url):name url[0].spl…

Redis 5种常用数据类型

目录 Redis简介 1.字符串 string 2.哈希 hash 3.列表 list 4.集合 set 5.有序集合 sorted set / zset Redis简介 Redis&#xff0c;全称Remote Dictionary Server&#xff0c;是一个开源的、内存中的数据结构存储系统。它可以用作数据库、缓存和消息中间件&#xff0c;支…

JavaScript前端技术入门教程

引言 在前端开发的广阔天地中&#xff0c;JavaScript无疑是最耀眼的一颗明星。它赋予了网页动态交互的能力&#xff0c;让网页从静态的文本和图片展示&#xff0c;进化为可以与用户进行实时交互的丰富应用。本文将带您走进JavaScript的世界&#xff0c;为您提供一个入门级的教…

SpringBoot3+Mybatis-Plus+h2数据库,入门Mybatis-Plus

SpringBoot3Mybatis-Plush2数据库&#xff0c;入门Mybatis-Plus mybatis-plus官网地址maven依赖数据库脚本配置文件实体类Mapper入门程序启动程序测试单元测试测试结果 Service层接口service层接口单元测试测试结果 项目结构 mybatis-plus官网地址 https://www.baomidou.com/ …

风能远程管理ARMxy嵌入式系统深度解析

智能技术正以前所未有的速度融入传统能源管理体系&#xff0c;而ARMxy工业计算机作为这一变革中的关键技术载体&#xff0c;正以其独特的性能优势&#xff0c;为能源管理的智能化升级铺设道路。本文将聚焦于智能电表、太阳能电站监控、风力发电站远程管理三大应用场景&#xff…

【2023】LitCTF

LitCTF2023&#xff08;复现&#xff09; Web&#xff1a; 1、我Flag呢&#xff1f; ​ ctrlu 读取源码&#xff0c;在最后发现了flag&#xff1a; <!--flag is here flagNSSCTF{3d5218b9-4e24-4d61-9c15-68f8789e8c48} -->2、PHP是世界上最好的语言&#xff01;&…

SQL159 每个创作者每月的涨粉率及截止当前的总粉丝量

描述 用户-视频互动表tb_user_video_log iduidvideo_idstart_timeend_timeif_followif_likeif_retweetcomment_id110120012021-09-01 10:00:002021-09-01 10:00:20011NULL210520022021-09-10 11:00:002021-09-10 11:00:30101NULL310120012021-10-01 10:00:002021-10-01 10:00…

RAG检索与生成的融合

1、rag定义 检索增强生成 (RAG) 模型代表了检索系统和生成模型两大不同但互补组件完美结合的杰作。通过无缝整合相关信息检索和生成与背景相关的响应&#xff0c;RAG模型在人工智能领域达到了前所未有的复杂程度。 2、rag工作流程 2.1、rag整体框架 query通过llm处理后&…

3.haproxy负载均衡

haproxy负载均衡 一、haproxy介绍1、负载均衡类型 二、haproxy配置文件1、backend2、frontend 三、haproxy实现MySQL负载均衡 —— 4层1、后端两台MySQL配置双主复制2、安装配置haproxy2.1 安装软件2.2 编辑配置2.3 启动haproxy2.4 测试通过haproxy正常连接MySQL 四、haproxy实…

张大哥笔记:从古至今,赚钱最快的路子就一个,从未改变

从古至今&#xff0c;赚钱最快的路子就一个&#xff0c;而且从未改变&#xff0c;那就是信息差&#xff01; 不要误解信息差为某种高端复杂的概念&#xff1b;其本质很简单——它就是"你知道而别人不知道的信息"。 曾经我也认为&#xff0c;随着互联网的发展&#x…

Android.基本用法学习笔记

设置文本的内容 先在strings.xml声明变量 方法1. 方法2. 设置文本的大小 1.单位dp&#xff0c;大家可以去学一下有关的单位换算 2. 设置文本颜色 1. 2. 4.设置文本背景颜色 1. 2. 设置视图的宽高 与上级视图一致&#xff0c;也就是上一级有多宽就有多少 1. 2. 3. 4. 设置视图…