make 工具 makefile

编译型语言在每次执行之前都要进行编译。这在有人眼里是优势,因此编译过程中可以进行一些语法等信息的检查,避免一些初级的错误。同时编译出来的代码可以有更好的运行速度。但是在有些人眼里这就是灾难。其实不是有时候不是因为别的什么原因,而是因为你输入的编译命令可能长的的需要好几行才能输入完。中间要是修改起来简直就是不可能。

所以,我们有了一个新的工具 make。

1. make 工具

make 工具是用来构建 C 程序而发明的。特别是当需要依赖大量的库文件(尤其是非标准库文件),和需要设置一些特殊的系统变量环境等内容的时候。通常情况下, make 工具都会用在比较大的项目中。但是如果在规模不大的程序中使用会更简单,同时会让你的程序构建变得也更轻松。

要使用 make 工具就需要写一个 makefile,通常情况下这个文件名就是叫 makefile。当然你可以用别的名字替代。不过这个时候你就要在执行 make 命令的时候指定你所要执行的 makefile 文件名。如果写成 makefile 这个名字, make 程序会直接在当前所在的文件夹中寻找这个文件,就不用指定文件名字了。所以,建议大家就用 makefile 这个英文单词的名字。

make 工具其实不仅仅可以应用于 C 语言。它目前也不仅仅只是可以用在 linux 中。它也是可以跨平台的应用。

那么这个 makefile 文件的结构是什么?

其实比较简单。

目标:  依赖1, 依赖2, ……
        编译命令

2. 使用实例

这里我们有一个程序需要构建,而这个程序构建过程中,会依赖另外一个程序。这个时候我们就可以方便的通过 make 工具了。

文件名:test.c

#include <stdio.h>
int add(int d, int e);

int main()
{
     int a = 2, b = 3, c;
     c = add(a, b);
     printf("a add b = %d\n", c);
     return 0;
}

上面是我们的主程序,通过调用外部的程序 add 来实现加法运算。这里需要注意的是我们在程序的开始 int add(int d, int e); 这一行语句是函数的原型声明,因为函数本身是写在另外一个函数里的。这个函数本身是不不知道有这个函数存在的。要想使用 add 这个函数,就要先告知这个 main 函数。

文件名:add.c

int add(int x, int y)
{
    return x + y;
}

上面是我们实现加法运算的子程序。也就是被调用的那个程序。存在于另外一个程序文件中。就是一个简单的求和返回值。

我们首先展示,直接使用命令行是应该如何编译这两个文件的。

gcc test.c add.c -o test

这个看着是不长,但是我遇到过数十个依赖库的情况。你们自己可以自行想象一下24寸显示器屏幕全屏shell窗口一行写不完的景象。

所以这个时候 make 工具就要出场了。

先写一个 makefile 文件,名字就叫 makefile。

test: test.c add.c
		gcc test.c add.c -o test

运行结果:

utopia@DESKTOP:~$ make
gcc test.c add.c -o test
utopia@DESKTOP:~$ make
make: 'test' is up to date.

连续执行两次 make 也会有新的发现,当再次执行 make 时,make 文件会检查原始代码是不是有新的变化。

如果缺失依赖文件会怎样?

如果是直接执行编译命令会有如下提示。

gcc test.c add.c -o test
gcc: error: add.c: No such file or directory
makefile:2: recipe for target 'testbuild' failed
make: *** [testbuild] Error 1

而采用 make 文件会有下面的提示。

utopia@DESKTOP:~$ make
make: *** No rule to make target 'add.c', needed by 'test'.  Stop.

这两者有最大的区别就是 make 文件在进行大规模编译前就会根据你所提供的依赖进行文件检车。如果缺少了依赖的文件就会直接停止下面的编译,节省了大量的时间。不会出现编译到一半找不到文件的尴尬。

3. 小结

make 作为提高构建程序效率的工具,广泛应用在程序的编译构建中。大家如果用一些提供源码编译的工具话一定会使用过 make 工具。

make 工具解决了构建过程依赖的短缺,以及构建命令不容易维护的难题。使得编译程序可以变得不再那么痛苦。毕竟写一次 makefile 文件,每次都要重新输入超长的编译命令来说还是很方便的。更不要说还有可能设置更为负载的系统变量。