原创声明

修改自:https://www.toutiao.com/a6599850731023368707/


概述

当你需要在一些源文件改变后运行或更新一个任务时,通常会用到 make 工具。make 工具需要读取一个名为 Makefile(或 makefile)的文件,该文件中定义了一系列需要执行的任务。你可以使用 make 来将源代码编译为可执行程序。大部分开源项目会使用 make 来实现最终的二进制文件的编译,然后使用 make install 命令来执行安装。

本文将通过一些基础和进阶的示例来展示 make 和 Makefile 的使用方法。在开始前,请确保你的系统中安装了 make。


基础示例

依然从打印 “Hello World” 开始。首先创建一个名字为 myproject 的目录,在目录下新建 Makefile 文件,文件内容为:

在 myproject 目录下执行 make,会有如下输出:

在上面的例子中,“say_hello” 类似于其它编程语言中的函数名,在这里被称为目标(target)。在该目标之后的是预置条件依赖。为了简单起见,我们在这个示例中没有定义预置条件。echo "Hello World" 命令被称为步骤(recipe),它基于预置条件来实现目标。目标、预置条件和步骤共同构成一个规则

总结一下,一个典型的规则的语法为:

预置条件可以是文件,也可以是其它目标:

目标可以是文件,也可以是步骤的名字(称之为伪目标)。

再回到上面的示例中,当 make 被执行时,指令 echo "Hello World" 也被打印出来了,之后才是真正的执行结果。如果不希望指令本身被打印,需要在 echo 前添加 @。

接下来在 Makefile 中添加如下伪目标:generate 和 clean:

随后当我们运行 make 时,只有 say_hello 这个目标被执行。这是因为 Makefile 中的第一个目标是默认目标。我们可以通过 .DEFAULT_GOAL 这个特殊的伪目标来覆盖掉该默认行为。

在 Makefile 文件的开头增加 .DEFAULT_GOAL:

make 会将 generate 作为默认目标:

下面删除掉 .DEFAULT_GOAL,增加 all 目标:

运行之前,我们再增加一些特殊的伪目标。.PHONY 用来定义这些不是文件的目标。make 会调用伪目标下的步骤,而不去检查文件是否存在或文件的最后修改日期。完整的 Makefile 如下:

make 命令会调用 say_hello 和 generate:

clean 不应该被放到 all 中,或者被放到第一个目标中。clean 应当在需要清理时手动调用,调用方法为 make clean:

现在你应该已经对 Makefile 有了基础的了解,接下来我们看一些进阶的示例。


变量

Makefile 中的变量只能是字符串类型。Makefile 中的变量有四种赋值方式:

使用 ${变量名} 和 $(变量名) 都可以对变量进行引用。


模式和函数

下面的 Makefile 使用变量、模式和函数来实现所有 C 代码的编译,我们来逐行分析下:

关于 Makefile 的更多信息, GNU Make 手册提供了更完整的说明和实例。