正如您已经看到的,GNU make 可以做一些非常不可思议的事情,但是我还没有看到太多用 eval 构造真正突破 make 3.80 极限的东西。在这个练习中,我们将看看是否能比平时走的更远。 数据结构 在编写复杂的 makefile 时,make的一个局限性是它缺乏数据结构。在一种非常有限的方式中,您可以通过定义带有内嵌周期(甚至 -> 如果你能忍受的话): file.path = /foo/bar file.type = unix file.host = oscar 如果按下,你甚至可以通过使用计算变
调试 makefile 有点像一门魔法。不幸的是,没有 makefile 调试器这样的东西来检查特定规则是如何计算的或变量是如何展开的。相反,大多数调试都是通过简单的 print 语句和检查 makefile 来执行的。GNU make 通过各种内置函数和命令行选项提供了一些帮助。 调试 makefile 的最佳方法之一是添加调试钩子,并使用防御性编程技术,当事情出错时,您可以使用这些技术。我将介绍一些我认为最有帮助的基本调试技术和防御性编码实践。 make 的调试特性 warning 函数对于调试不规则的
make 在开发过程中起着至关重要的作用。它结合了项目的组件来创建应用程序,同时允许开发人员避免因意外地省略构建步骤而引起的细微错误。但是,如果开发人员因为觉得 makefile 太慢而避免使用 make,那么 make 的所有好处就都失去了。因此,确保尽可能高效地 makefile 是很重要的。 性能问题总是很棘手,但是当考虑到用户的感知和代码的不同路径时,性能问题就更加棘手了。并不是 makefile 的每个目标都值得优化。根据您的环境,即使是激进的优化也可能不值得。例如,将手术时间从 90 分钟减少到
可移植 makefile 是什么意思?作为一个极端的例子,我们想要一个在任何可运行 GNU make 的系统上都不需要更改的执行 makefile。但由于操作系统的多样性,这实际上是不可能的。更合理的解释是 makefile,它很容易针对运行它的每个新平台进行更改。一个重要的附加约束是,到新系统的移植不会破坏对以前平台的支持。 我们可以使用与传统编程相同的技术来实现 makefile 的这种级别的可移植性:封装和抽象。通过使用变量和自定义函数,我们可以封装应用程序和算法。通过为命令行参数和形参定义变量,我们
在本书中显示的 makefile 是工业强度相当适应您的最高级的需求。但是仍然值得看看一些来自现实项目的 makefile,看看人们在提供可交付成果的压力下用 make 做了什么。在这里,我们将详细讨论几个示例 makefile。第一个例子是构建这本书的 makefile。第二个是用于构建 Linux 2.6.7 内核的 makefile。 本书的 Makefile 写一本关于编程的书本身就是构建系统的有趣练习。本书的文本由许多文件组成,每个文件都需要不同的预处理步骤。这些示例是应该运行的真实程序,它们的输
GNU make有一组令人印象深刻的命令行选项。大多数命令行选项包括短格式和长格式。短命令以一个 - 后跟一个字符表示,而长命令以 -- 开头,通常后跟用 - 分隔的整个单词。这些命令的语法如下: -o argument --option-word=argument 以下是最常用的选项。要获得完整的清单,请参阅 GNU make 手册或键入 make --help。 –always-make -B 首先假设每个目标都过期了,然后更新所有目标。 –directory=directory -C direct
第六章中所展示的问题和技术将在本章中增强,并应用于 C 和 C++ 项目。我们将继续在非递归生成文件上构建 mp3 播放器示例。 分离源代码和二进制文件 如果我们想要支持一个带有多个平台的单一源代码树,以及每个平台的多个构建,那么分离源代码树和二进制树是必要的,那么我们该怎么做呢?最初编写 make 程序是为了能够很好地处理单个目录中的文件。尽管从那时起它已经发生了巨大的变化,但它并没有忘记它的初心。当它正在更新的文件位于当前目录(或其子目录)中时,make 最适合用于多个目录。 简单的方法 让 make
我们已经介绍了 make 命令的许多基本元素,但是为了确保我们都在同一页面上,让我们稍微回顾一下。 命令本质上是一行 shell 脚本。实际上,make 抓取命令行行并将其传递给子 shell 执行。事实上,make 可以优化这个(相对)昂贵的fork/exec 算法,如果它能保证省略 shell 不会改变程序的行为。它通过扫描每个命令行来检查 shell 特殊字符,比如通配符和 I/O 重定向。如果没有找到,make 直接执行命令,而不将它传递给子 shell。 默认情况下,shell 使用 /bin/s
GNU make 支持内置函数和自定义函数。函数调用看起来很像变量引用,但是包含用一个或多个用逗号分隔的参数。大多数内置函数扩展为某个值,然后将该值赋给变量或传递给子 shell。自定义的函数存储在变量或宏中,并期望调用者传递一个或多个参数。 自定义函数 将命令序列存储在变量中为广泛的应用打开了大门。例如,这里有一个用来终止进程的宏: 你可能会问:“为什么要在 makefile 中做这个?”,好吧,在 Windows 上,打开一个文件会锁定它,防止其他进程写入。在我写这本书的时候,PDF 文件经常会被 A
我们知道 makefile 变量已经有一段时间了,我们看到了许多在内置规则和用户定义规则中使用它们的例子。但我们看到的例子只是触及了表面。变量和宏会变得更加复杂,并赋予 GNU make 强大的功能。 在我们继续之前,重要的是要理解 make 是两种语言的结合体。第一种语言描述由目标和依赖组成的依赖关系图。(这门语言在第二章中介绍过) 第二语言是执行文本替换的宏语言。您可能熟悉的其他语言的宏,例如,C 预处理器、m4、TEX 和 宏汇编器。与其他宏语言一样,make 允许您为更长的字符序列定义一个简写术语,