更新时间 2021-04-21

make 工具是一个有吸引力的仆人,总是在那里与人方便。像许多小说和电影中必不可少的助手一样,make 一开始总是被低估的,你给它扔了一些奇怪的工作,然后它将慢慢地接管整个企业。 当我的主管、最初 O’Reilly 经典《Make 项目管理》的作者 史蒂夫·塔尔伯特(Steve Talbott)注意到我的痴迷并要求我写第二版时。我已经达到了将 make 置于每个我接触项目的中心的不可救药的阶段。对我来说,这是一次关键的成长经历(也是一次疯狂的旅行),也是我进入 O’Reilly 奇妙世界的关键,但是我们并没

编程技巧通常遵循及其简单的流程,编辑源文件、编译源文件到可执行的形式,然后调试编译结果。尽管将源程序转换到可执行程序是常规操作,但是如果操作不当,程序员可能会浪费大量的时间来跟踪问题。大多开发者都经历过修改功能和运行新代码的挫败感,仅仅是发现刚才的改动无法解决某个bug。然后他们发现由于某些流程错误,例如重编译源码失败,链接失败,或重构建 jar 包失败,程序并没有执行他们修改的功能,此外,随着程序复杂度的增加这些简单的任务可能会随着开发不同版本的程序而变得越来越容易出错。也可能其他平台或者其他版本的库等。

在上一章中,我们编写了一些规则来编译和链接我们的单词计数程序。这些规则中的每一个都定义一个目标,即要更新的文件。每个目标文件都依赖于一组文件。当要求更新目标时,如果任何依赖文件比目标修改时间最近,make 将执行规则的命令脚本。由于一个规则的目标可以作为另一条规则的依赖来引用,因此目标和依赖的集合形成了依赖关系链或图。构建并处理此依赖关系图以更新需要的目标是 make 的全部目的。 由于规则在 make 中是如此重要,因此存在许多不同种类的规则。与上一章中的规则一样,显式规则指出了要更新的特定目标,如果该目

我们知道 makefile 变量已经有一段时间了,我们看到了许多在内置规则和用户定义规则中使用它们的例子。但我们看到的例子只是触及了表面。变量和宏会变得更加复杂,并赋予 GNU make 强大的功能。 在我们继续之前,重要的是要理解 make 是两种语言的结合体。第一种语言描述由目标和依赖组成的依赖关系图。(这门语言在第二章中介绍过) 第二语言是执行文本替换的宏语言。您可能熟悉的其他语言的宏,例如,C 预处理器、m4、TEX 和 宏汇编器。与其他宏语言一样,make 允许您为更长的字符序列定义一个简写术语,

GNU make 支持内置函数和自定义函数。函数调用看起来很像变量引用,但是包含用一个或多个用逗号分隔的参数。大多数内置函数扩展为某个值,然后将该值赋给变量或传递给子 shell。自定义的函数存储在变量或宏中,并期望调用者传递一个或多个参数。 自定义函数 将命令序列存储在变量中为广泛的应用打开了大门。例如,这里有一个用来终止进程的宏: 你可能会问:“为什么要在 makefile 中做这个?”,好吧,在 Windows 上,打开一个文件会锁定它,防止其他进程写入。在我写这本书的时候,PDF 文件经常会被 A

我们已经介绍了 make 命令的许多基本元素,但是为了确保我们都在同一页面上,让我们稍微回顾一下。 命令本质上是一行 shell 脚本。实际上,make 抓取命令行行并将其传递给子 shell 执行。事实上,make 可以优化这个(相对)昂贵的fork/exec 算法,如果它能保证省略 shell 不会改变程序的行为。它通过扫描每个命令行来检查 shell 特殊字符,比如通配符和 I/O 重定向。如果没有找到,make 直接执行命令,而不将它传递给子 shell。 默认情况下,shell 使用 /bin/s

什么样的项目才配称为大项目?对我而言,可能需要一个团队的开发者,可能需要在多种体系结构上运行,也可能有多种领域需要维护。当然,不是所有的大项目都满足以上所有要求。单一平台百万行代码级别的 C++ 的预发布版本同样也是大项目。但是软件不会永远停留在预发布版本。如果它是成功的,那么终将有人想让它运行在其他的平台。所以一段时间之后,大多数大型软件系统都十分相似。 大型软件系统通常通过将系统拆分多个主要的组件来简化复杂性。一般包括程序、库,或者二者皆有。这些组件通常保存在它们自己的目录中而且通过它们自己的 make

可移植 makefile 是什么意思?作为一个极端的例子,我们想要一个在任何可运行 GNU make 的系统上都不需要更改的执行 makefile。但由于操作系统的多样性,这实际上是不可能的。更合理的解释是 makefile,它很容易针对运行它的每个新平台进行更改。一个重要的附加约束是,到新系统的移植不会破坏对以前平台的支持。 我们可以使用与传统编程相同的技术来实现 makefile 的这种级别的可移植性:封装和抽象。通过使用变量和自定义函数,我们可以封装应用程序和算法。通过为命令行参数和形参定义变量,我们

第六章中所展示的问题和技术将在本章中增强,并应用于 C 和 C++ 项目。我们将继续在非递归生成文件上构建 mp3 播放器示例。 分离源代码和二进制文件 如果我们想要支持一个带有多个平台的单一源代码树,以及每个平台的多个构建,那么分离源代码树和二进制树是必要的,那么我们该怎么做呢?最初编写 make 程序是为了能够很好地处理单个目录中的文件。尽管从那时起它已经发生了巨大的变化,但它并没有忘记它的初心。当它正在更新的文件位于当前目录(或其子目录)中时,make 最适合用于多个目录。 简单的方法 让 make

首先,我讨厌 Java,其次,这个声明和原书作者无关,然后,我们继续吧。 许多Java开发人员喜欢集成开发环境(IDE),比如 Eclipse。有了诸如 Java IDE 和 Ant 这样知名的替代方案,读者可能会问,为什么要考虑在 Java 项目中使用 make。本章探讨了在这些情况下 make 的价值;特别是,它提供了一个通用的 makefile,它可以被放入任何 Java 项目中,只需进行最小的修改,就可以执行所有标准的重建任务。 在 Java 中使用 make 带来了几个问题,也带来了一些机会。这