一、Makefile概述

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。Makefile的基本语法规则为:

目标: 依赖
    操作

例如我们要把一个main.c编译成app,这里目标是app,源是main.c,编译的命令为gcc main.c -o app。那么它的Makefile为:

app: main.c
    gcc main.c -o app

一个要注意的地方是 Makefile文件的名字只能是Makefile,编写完成后在同级目录输入make即可完成编译。这里创建两个文件main.cMakefile

> cat main.c 
#include <stdio.h>

int main() {
    printf("HelloWorld\n");

    return 0;
}
> vi Makefile
> cat Makefile 
app: main.c
    gcc main.c -o app

编译:

> make
gcc main.c -o app # 执行编译
> ./app 
HelloWorld

使用Makefile还有一个好处是不会重复编译:如果一个目标的依赖项在上次编译过后没有更改,那么在下次编译时会提示目标已是最新,该项编译自动跳过。这个功能对大型项目来说十分友好,因为可以减去很多重复编译的时间。

> make
make: ''app'' is up to date.

对于Makefile而言,它本身可能包含多个目标,默认情况是编译第一个不包含通配符的目标。此时如果需要编译其他目标需要手动指定,例如这里的目标是app,输入make app即可指定编译app这个目标。

二、依赖项

Makefile在编译过程中会自动解决依赖关系,依赖项中没有生成的选项会自动根据规则生成:

app: main.c abc
    gcc main.c -o app
abc:
    echo "abc" > /dev/null

输入make命令,会默认生成第一个目标app,而app依赖abc所以会先生成abc

> make
echo "abc" > /dev/null
gcc main.c -o app

三、变量

3.1 内置变量

Makefile中定义了一些内置的变量:

  • $@:表示目标
  • $^:表示所有的依赖
  • $<:第一个依赖项

合理运用内置变量能减少很大的工作量,例如上面的Makefile可改成:

app: main.c
    gcc $< -o $@

3.2 自定义变量

四、函数

五、通配符

六、.PHONY

.PHONY用来生成为伪目标,用于解决一种目标已经存在于目录的情形。

> ls # 目录下有两个文件
main.c  Makefile
> cat main.c # 代码文件
#include <stdio.h>

int main() {

    return 0;
}
> cat Makefile # Makefile文件
app: main.c
    gcc main.c -o app

clean:
    rm app

执行make命令编译程序,make clean删除目标程序:

> make # 编译
gcc main.c -o app
> ls
app  main.c  Makefile
> make clean # 清除
rm app
> ls
main.c  Makefile

以上操作能正常完成,但是当目标文件夹下有一个clean文件时,操作就会失败:

> touch clean
> make
gcc main.c -o app
> make clean # 操作失败
make: ''clean'' is up to date.
> ls
app  clean  main.c  Makefile

原因很简单,因为本地有一个clean,Makefile执行时检测到clean文件所以不会生成目标。

此时就需要.PHONY关键字来生成为伪目标,修改Makefile中clean目标为以下内容即可:

.PHONY: clean
clean:
    rm app -f
最后修改:2018 年 05 月 18 日
如果觉得我的文章对你有用,请随意赞赏