《Makefile 光学教程》之面向 Makefile 编程·Erlang工程模板

此教程将计划以两部分内容呈现,目标是从零基础到 GNU make 最本原的原理的掌握,这是第二部分内容,按不同的工程类型分成多个示范项目来展示。零基础可以先看第一部分:Basic Concepts:
1. 🐣 Basic Concepts
2. 🐣 Demo Projects
2.1. 🐣 Scheme R6RS 语言规范文档处理 [LaTeX]
2.2. 🐣 Multi threaded Download [Msys2 Packages]
2.3. 🐣 C/C++ Project Templates [GLib Gobject & ADT]
2.4. 🐣 Erlang Project Templates
2.5. 🐣 Unit Test [CPL]
完整《Makefile 光学教程》以及 GNU M4 教程参考开源文档:https://github.com/Jeangowhy/opendocs/blob/main/Makefile.md
用来测试的 Erlang 脚本如下,只负责打印一条信息:
Makeile 将自动创建多个子目录,并将以上脚本写入 main.erl 文件,然后再进行编译测试。使用 erlc 编译器命令时,-o 可以指定编译生成的 .beam 文件保存目录的路径,可以使用集中目录存放。但是,如果模块重名,如这里演示的所有子目录下的主模块都命名为 main,就需要独立目录保存。
Erlang 模块就是脚本文件,文件名就是模块名,使用 `-module` 指令显式命名也受此约束。
Erlang 处理处理 Code path 搜索路径列表中存在多个同名模块呢?以搜索路径列表顺序作为优先级,使用 -pa 等参数会将路径添加列表前头,所以以下命令可以解释同名的 main 模块只加载到最靠前的 ModuleC 目录下的模块。
在处理多层级 Makefile 脚本时,有两种方式:
1. include 方式:通过直接原样引用外部 Makefile 脚本;
2. submake 方式:通过 make 命令运行子进程去解释更多的 Makefile 脚本;
这两种方式有很多差别,submake 相当于直接运行 make 命令,但是可以通过变量控制来改变默认行为。
使用 include 直接引用的外部脚本会将内容原样拼合到主脚本中,这种方式反而可能更复杂。因为这种引用外部脚本的方式,会因为脚本拼合导致规则更新,而致使 Make 解析器需要重启,`MAKE_RESTARTS` 自动变量会记录当前重启的次数。而且,在执行 clean 这样的清理工作时,也会有可能触发 Makefiles 文件目标规则,如果有定义并且需要更新的话。
另外,还要求理解透 Make 的规则覆盖机制:
1. 单冒号规则的覆盖:命令块被最后的同名 Target 定义替代,但是依赖项叠加;
2. 双冒号规则的独立性,同名的 Target 命令块与依赖独立解析运行,不存在覆盖行为;
除了规则层面上的覆盖,还需要考虑同名变量的处理:
使用 = 递归赋值,变量值由右侧所引用变量最后叠加的值决定;
使用 := 立即赋值,变量值虽然当下是已经绑定,但后缀叠加脚本还可以进行重新赋值;
最后,include 指令还会改变 `MAKEFILE_LIST` 变量的列表,列表中最后一个脚本文件即为上一条 include 指令引用的脚本(也可以是列表)中的最后一个脚本。如果使用 = 递归赋值的变量需要使用此列表,就需要考虑如何正确处理这个值的状态。
如果不希望各种 Makefile 脚本中的变量相互影响,那么就应该使用名称前缀、后缀来解决。
以下是 Makefile 脚本输出内容参考:
以下是 Makefile 脚本内容参考,简要说明如下:
1. 宏函数与变量定义没有本质区别,只是使用上不同,使用 call 调用即为宏函数;
2. 变量的 := 立即绑定方式其值立即固定,= 递归绑定由右则变量的最终值决定;
3. include 引用外部脚本,可能因脚本被更新导致 Make 重启解释过程,MAKE_RESTARTS 变量记录重启次数;
4. 引用脚本可能会因为 Target 同名,导致原有单引号规则的命令块失效,被新规则替换,但是依赖列表叠加;