Makefile 教程(一)——基础

本文裁剪汇总自Makefile教程和示例指南。

Makefile 意义

Makefile 用于帮助决定大型程序的哪些部分需要重新编译。在绝大多数情况下,都会编译 C 或 C++ 文件。其他语言通常有自己的与 Make 功能类似的工具。Make 也可以在编译之外使用,即当需要根据已更改的文件运行一系列指令时。本教程将重点介绍 C/C++ 编译用例。

下面是可以使用 Make 构建的依赖关系图示例。如果任何文件的依赖项发生更改,则该文件将被重新编译:

one.cpp
one.h
main.cpp
two.cpp
two.h
libm
libc

Make 的替代

流行的 C/C++ 替代构建系统有 SCons、CMake、Bazel 和 Ninja。一些代码编辑器(例如 Microsoft Visual Studio)有自己的内置构建工具。对于 Java,有 Ant、Maven 和 Gradle。其他语言(例如 Go、Rust 和 TypeScript)都有自己的构建工具。

Python、Ruby 和 raw Javascript 等解释性语言不需要与 Makefile 类似的东西。 Makefile 的目标是根据已更改的文件来编译需要编译的任何文件。但是,当解释语言中的文件发生更改时,不需要重新编译任何内容。程序运行时,将使用该文件的最新版本。

Make 的版本和类型

Make 有多种实现,但本指南的大部分内容都适用于任一版本。然而,它是专门为 GNU Make 编写的,GNU Make 是 Linux 和 MacOS 上的标准实现。所有示例都适用于 Make 版本 3 和 4,除了一些深奥的差异之外,它们几乎相同。

Make 基本运行

运行首先需要一个终端,并安装 make。对每一个项目,需包含在一个名为Makefile的文件(无后缀)中,并在同级目录下运行命令make

最简单的 Makefile:

hello:echo "Hello, World"

Makefile 必须使用 TAB 键进行缩进,其中不能有空格。

运行如下:

$ make
echo "Hello, World"
Hello, World

Makefile 语法

Makefile 的主要部分由规则组成,可有多条规则。

一条规则的基本语法:

targets: prerequisitescommandcommand...
  • 目标(target),每条规则可有多个,以空格分隔,但一般只有一个,且为文件名(make将其视为文件名);
  • 命令(command),一系列步骤,一般用于创建目标文件,开始的缩进必须是tab而非空格;
  • 先决条件(prerequisite),又称依赖(dependency),为文件名,可有多个,以空格分隔,在运行命令前需要存在的文件。在执行规则时,prerequisites中的每个prerequisite均需满足以下至少一点:
    • 当前目录下存在同名文件;
    • Makefile中存在以此名为target的规则。

Makefile 精髓

  • 运行时,在终端输入make <target>,然后make会执行该target对应的规则(如果同一目标有多条规则,则会警告,并执行最后一条规则);若在终端输入make,则默认执行第一条规则;

  • 当在终端输入make [<target>]时,make对该target对应规则中的每一个prerequisite进行判断:Makefile中是否存在以其为名的target,若有,则先对对应规则进行递归执行;

    如:

    test1: test2echo "test1" > test1
    test2: echo "test2" > test2 
    

    在该例子中,test1的内容其实与test2无关,所以这个依赖关系只是对make而言的。

    当执行make test1make时,make实质上会先执行make test2

  • 执行规则时,make会先判断是否要执行命令,需满足以下条件的至少一点才会执行:

    1. target为名的文件不存在;
    2. 存在比target更新的prerequisite;(prerequisitetarget更新,即prerequisite文件内容的修改时间晚于target文件make会记录并更新该目录下每个文件被更新的时间戳)

    根据第一点,可以构造一种特殊规则,该规则不会创建以target为名的文件,因而一般情况下在输入make <target>时总是会被执行。常见的有cleanall等。(显然,若该目录下手动创建了对应名称的文件,则该构造就失效了,对应解决方案见后文)

    例如:若Makefile内容如下:

    test1: test2echo "test1"
    test2: test3echo "test2"
    
    1. 若开始时目录下只有该Makefile文件,然后手动依次创建test3test2test1文件(创建文件也是一种手动更新),再执行make,则会显示:

      $ make
      make: 'test1' is up to date.
      

      即没有规则被执行。

      分析如下:

      1. 执行make时,由于未指定target,故默认选择第一个规则,即执行make test1

      2. 执行make test1时,先递归执行其prerequisite,即先执行make test2

      3. make test2,进行判断,发现:

        1. 该目录下存在test2文件;
        2. 其先决条件test3的更新时间早于test2(这是因为创建时间test3 早于test2);

        故不执行对应规则;

      4. 递归回到make test1,进行判断,发现:

        1. 该目录下存在test1文件;
        2. 其先决条件test2的更新时间早于test1(这是因为创建时间test2 早于test1);

        故不执行对应规则;

    2. 换一种情况,若开始时目录下只有该Makefile文件,然后手动依次创建test2test3test1文件(即调换test2test3的创建顺序),再执行make,则会显示:

      $ make
      echo "test2"
      test2
      

      test2对应规则被执行了,test1对应规则未被执行。

make clean

clean通常用作删除其他目标的输出的目标,但它在make中并不是一个专有的词。

注:

  • 一般而言,clean不是第一个目标 (默认目标),也不是先决条件。 这意味着除非显式调用make clean,否则它永远不会运行;
  • 如“Makefile 精髓”中所述,clean不是一个文件名。 如果该目录下有一个名为 “clean” 的文件,则此目标将无法运行。 解决方案参阅后续教程。

例:

some_file: touch some_fileclean:rm -f some_file

变量

变量只能是字符串,一般通过:=赋值(使用= 也可以,具体见后续部分)。

使用$()${}引用变量(单字母名称变量也可以不用括号,但不推荐)。

例:

files := file1 file2
some_file: $(files)echo "Look at this variable: " $(files)touch some_filefile1:touch file1
file2:touch file2clean:rm -f file1 file2 some_file

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

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

相关文章

绘制决策树尝试3

目录 代码解读AI 随机状态 种子 定义决策树回归模型 tree的decision regressor fit 还可用来预测 export 效果图 我的X只有一个特征 为何这么多分支 &#xff1f;&#xff1f;&#xff1f; 这是CART回归 CART回归 为什么说代码是CART回归&#xff1f; 不是所有的决…

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…

分布式微服务系统架构第87集:kafka

Kafka 就是为了解决上述问题而设计的一款基于发布与订阅的消息系统。它一般被称为 “分布式提交日志”或者“分布式流平台”。文件系统或数据库提交日志用来提供所有事务 的持久记录&#xff0c;通过重放这些日志可以重建系统的状态。同样地&#xff0c;Kafka 的数据是按照一定…

k均值聚类将数据分成多个簇

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 K-Means 聚类并将数据分成多个簇&#xff0c;可以使用以下方法&#xff1a; 实现思路 随机初始化 K 个聚类中心计算每个点到聚类中心的距离将点分配到最近的簇更新聚类中心重复上述过程直到收敛 完整代码&#x…

使用 Docker 部署 pSQL 服务器 的教程

如何使用 Edu 邮箱申请 Azure 订阅并开通免费 VPS 使用 Edu 邮箱不仅可以申请 Azure 的免费订阅来开通 VPS&#xff0c;还可以免费使用 Adobe 和 Notion 等软件&#xff0c;极大地提高学习和工作的效率。如果您还没有 Edu 邮箱&#xff0c;可以参考在线笔记s3.tebi.io/notes-i…

langchain 实现多智能体多轮对话

这里写目录标题 工具定义模型选择graph节点函数定义graph 运行 工具定义 import random from typing import Annotated, Literalfrom langchain_core.tools import tool from langchain_core.tools.base import InjectedToolCallId from langgraph.prebuilt import InjectedSt…

【Block总结】CPCA,通道优先卷积注意力|即插即用

论文信息 标题: Channel Prior Convolutional Attention for Medical Image Segmentation 论文链接: arxiv.org 代码链接: GitHub 创新点 本文提出了一种新的通道优先卷积注意力&#xff08;CPCA&#xff09;机制&#xff0c;旨在解决医学图像分割中存在的低对比度和显著…

Python从零构建macOS状态栏应用(仿ollama)并集成AI同款流式聊天 API 服务(含打包为独立应用)

在本教程中,我们将一步步构建一个 macOS 状态栏应用程序,并集成一个 Flask 服务器,提供流式响应的 API 服务。 如果你手中正好持有一台 MacBook Pro,又怀揣着搭建 AI 聊天服务的想法,却不知从何处迈出第一步,那么这篇文章绝对是你的及时雨。 最终,我们将实现以下功能: …

强化学习、深度学习、深度强化学习的区别是什么?

前言 深度强化学习就是 深度学习 和 强化学习 的结合体。它让计算机程序&#xff08;也就是智能体&#xff09;在特定环境中不断尝试&#xff0c;从错误中学习&#xff0c;最终找到最优的行动策略。 深度学习是AlphaGo从棋谱里学习&#xff0c;强化学些Alphazero 学习规则&am…

string类(详解)

为什么学习string类&#xff1f; 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xf…

工业相机如何获得更好的图像色彩

如何获得更好的图像色彩 大部分的工业自动化检测中对物体的色彩信息并不敏感&#xff0c;因此会使用黑白的相机&#xff0c;但是在显微镜成像、颜色分类识别等领域&#xff0c;相机的色彩还原就显得格外重要&#xff0c;在调节相机色彩方面的参数时&#xff0c;有以下几个方面需…

五.简单函数

五.简单函数 函数是什么&#xff1f; 函数是 一种将输入值映射到唯一输出值的对应关系 1。 在数学中&#xff0c;函数通常表示为 $y f&#xff08;x&#xff09;$&#xff0c;其中 $x$ 是自变量&#xff0c;$y$ 是因变量&#xff0c;$f$ 是对应法则2。 c中&#xff0c;函数是…

SQLite Update 语句详解

SQLite Update 语句详解 SQLite 是一款轻量级的数据库管理系统&#xff0c;以其简单、易用和高效的特点在全球范围内得到了广泛的应用。在 SQLite 中&#xff0c;UPDATE 语句是用于修改数据库表中记录的常用命令。本文将详细解析 SQLite 的 UPDATE 语句&#xff0c;包括其语法…

【Redis】set 和 zset 类型的介绍和常用命令

1. set 1.1 介绍 set 类型和 list 不同的是&#xff0c;存储的元素是无序的&#xff0c;并且元素不允许重复&#xff0c;Redis 除了支持集合内的增删查改操作&#xff0c;还支持多个集合取交集&#xff0c;并集&#xff0c;差集 1.2 常用命令 命令 介绍 时间复杂度 sadd …

一些计算机零碎知识随写(25年2月)

今天复习 MySQL 的时候&#xff0c;我突然冒出一个想法&#xff1a;能不能远程连接 MySQL 呢&#xff1f;虽说心里清楚理论上可行&#xff0c;但一直没实际操作过。 于是&#xff0c;起床后我立马打开服务器&#xff0c;准备启动 MySQL。结果&#xff0c;这一启动就发现问题了&…

【Java异步编程】CompletableFuture实现:异步任务的合并执行

文章目录 一. 合并两个异步任务的结果1. thenCombine()&#xff1a;组合两个异步任务的结果2. runAfterBoth()&#xff1a;在两个任务完成后执行无返回值操作3. thenAcceptBoth()&#xff1a;消费两个任务的结果 二. allOf()&#xff1a;等待所有任务完成 如果某个任务同时依赖…

ESP32-c3实现获取土壤湿度(ADC模拟量)

1硬件实物图 2引脚定义 3使用说明 4实例代码 // 定义土壤湿度传感器连接的模拟输入引脚 const int soilMoisturePin 2; // 假设连接到GPIO2void setup() {// 初始化串口通信Serial.begin(115200); }void loop() {// 读取土壤湿度传感器的模拟值int sensorValue analogRead…

Java 大视界 -- Java 大数据在量子通信安全中的应用探索(69)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

86.(2)攻防世界 WEB PHP2

之前做过&#xff0c;回顾一遍&#xff0c;详解见下面这篇博客 29.攻防世界PHP2-CSDN博客 既然是代码审计题目&#xff0c;打开后又不显示代码&#xff0c;肯定在文件里 <?php // 首先检查通过 GET 请求传递的名为 "id" 的参数值是否严格等于字符串 "admi…

PHP根据IP地址获取地理位置城市和经纬度信息

/** 根据IP地址 获取地理位置*/ function getLocationByIP($ip) {$url "http://ip-api.com/json/{$ip}?langzh-CN&fieldsstatus,message,country,countryCode,region,regionName,city,lat,lon,timezone,isp,org,as";$response file_get_contents($url);$data …