makefilemakefile入门


备注

makefile是一个控制make程序操作的文本文件。 make程序通常用于管理从源文件创建程序,但它可以更普遍地用于处理在修改其他文件(或先决条件 )后需要重新生成文件(或目标 )的任何进程。 makefile描述了目标和先决条件之间的关系,还指定了在一个或多个先决条件发生更改时使目标保持最新所需的命令。 make的唯一方法是确定“过时”是通过比较目标文件的修改时间和它们的先决条件。

Makefile在某些方面有点独特,最初可能会令人困惑。

首先,makefile由同一文件中的两种完全不同的编程语言组成。该文件的大部分是写在一个语言make能理解:这提供变量赋值和扩展,一些预处理能力(包括其他文件,该文件的部分条件分析等)以及目标的定义和其先决条件。此外,每个目标都可以有一个与之关联的配方 ,该配方指定应调用哪些命令以使该目标更新。配方被编写为shell脚本(默认情况下为POSIX sh)。 make程序不解析此脚本:它运行shell并将脚本传递给要运行的shell。配方不是由make解析,而是由单独的shell进程处理的事实,这对于理解makefile是至关重要的。

其次,makefile不是像脚本那样的过程语言:因为make解析makefile,它在内部构造一个有向图 ,其中目标是图的节点,先决条件关系是边。只有在所有的makefile已完全解析和图形完成将make选择一个节点(目标),并尝试将对其进行更新。为了确保目标是最新的,它必须首先确保每个目标的先决条件都是最新的,依此类推。

版本

名称也称为初始版本发布日期
POSIX制作 1992年 IEEE Std 1003.1-2008,2016版 2016年9月30日
NetBSD制作 B请 1988年 20160926 2016年9月26日
GNU make 使用gmake 1988年 4.2.1 2016年6月10日
SunPro制作 dmake的 2006年 2015-07-12
MSVS nmake 2003 2015p3 2016年6月27日

基本的Makefile

考虑写一个“你好世界!”程序在c。让我们说我们的源代码在一个名为source.c的文件中,现在为了运行我们需要编译它的程序,通常在Linux上(使用gcc)我们需要键入$> gcc source.c -o output where output是要生成的可执行文件的名称。对于基本程序,这很有效,但随着程序变得越来越复杂,我们的编译命令也会变得更加复杂。这是Makefile的用武之地,makefile允许我们为编译程序编写一组相当复杂的规则,然后通过在命令行输入make来编译它。例如,这里是上面的hello wold示例的可能示例Makefile。

基本的Makefile

让我们创建一个基本的Makefile ,并将它保存到我们的系统中,与我们的源代码Makefile相同 。请注意,此文件需要命名为Makefile,但是capitol M是可选的。这说使用国会大厦M是相对标准的。

output: source.c
    gcc source.c -o output
 

请注意,在第二行的gcc命令之前只有一个选项卡(这在makefile中很重要)。一旦每次用户输入make(与Makefile在同一目录中)时都会写入这个Makefile,make将检查source.c是否已被修改(检查时间戳),如果它已被修改,而不是输出它将运行以下行的编译规则。

Makefile中的变量

根据项目的不同,您可能需要在make文件中引入一些变量。这是一个包含变量的Makefile示例。

CFLAGS = -g -Wall

output: source.c
    gcc $< $(CFLAGS) -o $@
 

现在让我们来探讨这里发生的事在第一行中,我们声明了一个名为CFLAGS的变量,该变量包含您可能希望传递给编译器的几个常见标志,请注意您可以在此变量中存储任意数量的标志。然后我们使用与之前相同的行来告诉make检查source.c以查看它是否比输出更新,如果是,它运行编译规则。我们的编译规则与以前大致相同,但是通过使用变量缩短了它, $< 变量内置于make中(称为自动变量,请参阅https://www.gnu.org/software/make/manual/ html_node / Automatic-Variables.html )它总是代表源代码,所以在这种情况下是source.c$(CFLAGS) 是我们之前定义的变量,但请注意,我们必须将变量放在括号中,前面加$,如$(someVariable) 。这是告诉Make将变量扩展为您之前键入的语法的语法。最后我们有$ @符号,这又是一个内置于make的变量,它只是代表编译步骤的目标,所以在这种情况下它代表输出

清洁

Make clean是了解make文件的另一个有用概念。让我们从上面修改Makefile

CFLAGS = -g -Wall
TARGETS = output

output: source.c
    gcc $< $(CFLAGS) -o $@

clean:
    rm $(TARGETS)
 

正如您所看到的,我们只是在Makefile中添加了一个规则,以及一个包含所有目标的附加变量。这在makefile中有一个常见的规则,因为它允许您通过键入$> make clean 快速删除您生成的所有二进制文件。通过键入make clean,您可以告诉make程序运行clean规则,然后make将运行rm命令来删除所有目标。

我希望这个使用make的简要概述可以帮助您加快工作流程, Makefile可能会变得非常复杂,但是有了这些想法,您应该能够开始使用make并更好地了解其他程序员Makefiles正在发生的事情。有关使用make一个优秀资源的更多信息, 请访问https://www.gnu.org/software/make/manual/

定义规则

快速开始

规则描述了何时以及如何创建某些文件(规则的目标 )。如果目标文件的创建所需的任何文件(目标的先决条件 )比目标文件更新,它也可以用于更新目标文件。

规则遵循以下语法:(请注意,遵循规则的命令选项卡缩进)

targets: prerequisites
        <commands>
 

其中目标先决条件是文件名或特殊保留名称和命令 (如果存在)由shell执行以构建/重建过时的目标

要执行规则,只需在Makefile所在的同一目录中在终端中运行make 命令即可。 make 不指定目标的情况下运行make 将执行Makefile中定义的第一个规则。按照惯例, Makefile中的第一个规则通常称为alldefault ,通常将所有有效的构建目标列为先决条件。

如果目标已过期,则make 仅执行规则,这意味着它不存在或其修改时间早于其任何先决条件。如果先决条件列表为空,则只有在首次调用规则以构建目标时才会执行该规则。但是,当规则不创建文件且目标是虚拟变量时,将始终执行规则。

GNU make

模式规则

模式规则用于指定多个目标并从目标名称构造先决条件名称。与普通规则相比,它们更通用,更强大,因为每个目标都有自己的先决条件。在模式规则中,目标和先决条件之间的关系是基于前缀(包括路径名和后缀或两者)构建的。

试想一下,我们要构建的目标foo.obar.o ,通过编译C脚本, foo.cbar.c ,分别。这可以通过使用以下普通规则来完成:

foo.o: foo.c
    cc -c $< -o $@

bar.o: bar.c
    cc -c $< -o $@

 

其中自动变量 $< 是第一个先决条件的名称, $@ 是目标的名称(可在此处找到自动变量的完整列表)。

但是,由于目标共享相同的后缀,现在可以使用以下模式规则替换上述两个规则:

%.o: %.c
    cc -c $< -o $@
 

隐含规则

隐式规则告诉make 如何使用常规的方法来构建某些类型的目标文件,这是经常使用的。 make 使用目标文件名来确定要调用的隐式规则。

我们在上一节中看到的模式规则示例实际上并不需要在Makefile中声明,因为make 具有C编译的隐式规则。因此,在以下规则中,在构建foo 之前,将使用C编译的隐式规则构建先决条件foo.obar.o

foo : foo.o bar.o
    cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
 

可以在此处找到隐式规则的目录及其使用的变量。

gzip文件的通用规则

如果目录包含2个文件:

$ ls
makefile
example.txt
 

makefile 包含以下文本

%.gz: %
    gzip $<
 

然后你可以通过在shell中输入来获得example.txt.gz

$ make -f makefile example.txt.gz
 

makefile文件只包含一个指示做出如何,如果有名称相同,但后缀名为.gz文件创建一个名称最终以.gz文件规则的。

makefile Hello World

C:\生成文件:

helloWorld :
[TAB]echo hello world
 

运行结果:

C:\>make
echo hello world
hello world
 

注意: [TAB]应替换为实际选项卡,stackoverflow用空格替换选项卡,并且空格不与makefile中的选项卡相同。