如何写 Makefile 文件
Makefile 文件1. 为什么需要 Makefile 文件2. Makefile 简单示例3. Makefile 编译多个文件4. Makefile 实用技巧4.1 变量4.2 生成多个可执行文件参考文献1. 为什么需要 Makefile 文件在 Linux 系统中, 一般通过 make 工具编译链接源文件。当然,只有 make 是不能完成编译链接过程的。我们还需要一个 Makefile 文件
Makefile 文件
1. 为什么需要 Makefile 文件
在 Linux 系统中, 一般通过 make 工具编译链接源文件。当然,只有 make 是不能完成编译链接过程的。我们还需要一个 Makefile 文件来告诉编译器编译链接的规则。换句话说,就是 make 工具和 Makefile 文件需要配合使用。
此时,有些小伙伴可能会感到疑惑:为啥需要这两个东西来实现编译链接。
可以使用类似 gcc test.c -o test
不就可以了吗?
那么试想一种复杂的情况:有多个源文件需要编译链接,那该怎么办?
有些小伙伴会说,有多少文件就写多少文件呀。比如:gcc tool.c main.c -o main
当然,这样做也不是完全不可以。但这样做,存在两个缺点:
- 源文件数量很多时,手动编写编译链接命令非常容易出错
- 使用上述编译链接命令,编译器需要进行分别编译多个源文件,效率较低
2. Makefile 简单示例
使用 Makefile 文件,可以提高编译器的编译效率,降低错误编译的可能。
下面来看一个简单的例子,来了解 Makefile 的编写规则。
首先给出 test.c 的源代码
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
下面为它编写 Makefile 文件
test: test.c
gcc test.c -o test
非常简单,就两行。第二行和之前手写的编译命令简直是一模一样。
Makefile 的编写规则如下:
target: dependencies
command
command 就是具体的编译命令
target 是要生成的目标(.o 文件 或者 可执行文件)
dependencies 是依赖项,就是生成目标依赖哪些文件
注意:command 前需要有一个 Tab (有些编辑器按下 Tab 键会被转换为 4 个空格,这里必须保证是 Tab)
就这个例子来说,target 就是第二行命令中的目标 test;dependencies 就是第二行命令中的 test.c。
下面来看下编译结果,make 命令执行了 Makefile 中的编译命令。
3. Makefile 编译多个文件
Makefile 主要还是用于编译链接多个源文件。下面给出一个具体的例子来说下:
首先给出源代码 main.c , tool.c, bar.c。
main.c 实现了求给定数组最大、最小值,并打印的功能。
tool.c 中有求取最大值的函数 find_max。
bar.c 中有求取最小值的函数 find_min。
具体代码如下:
main.c
#include "tool.h"
#include "bar.h"
#include <stdio.h>
int main()
{
int arr[5] = {1,9,3,8,0};
int min = find_min(arr, 5);
int max = find_max(arr, 5);
printf("min = %d\n", min);
printf("max = %d\n", max);
return 0;
}
tool.h
int find_max(int arr[], int n);
tool.c
#include "tool.h"
int find_max(int arr[], int n)
{
int m = arr[0];
for(int i = 0; i < n; i++)
{
if(arr[i] > m)
{
m = arr[i];
}
}
return m;
}
bar.h
int find_min(int arr[], int n);
bar.c
#include "bar.h"
int find_min(int arr[], int n)
{
int m = arr[0];
for(int i = 0; i < n; i++)
{
if(arr[i] < m)
{
m = arr[i];
}
}
return m;
}
那么 Makefile 如何对多个文件进行编译呢?
下面来考虑这样一个问题:
如果一个文件发生变化,需要重新编译整个文件吗?
手写编译语句,如 gcc tool.c main.c -o main
,就会编译整个文件。
使用 Makefile 文件的话,就可避免修改部分文件需要编译整个文件的情况。
Makefile 文件如下
main: main.c tool.o bar.o
gcc main.c tool.o bar.o -o main
tool.o: tool.c
gcc -c tool.c
bar.o: bar.c
gcc -c bar.c
clean:
rm *.o main
首先,要从最终生成的可执行文件写起,此处为 main。还是先写 target - main,
dependencies - main.c tool.o bar.o, 换行之后按下 tab 键,再写 command - gcc main.c tool.o bar.o -o main。
然后,开始写依赖项 tool.o 和 bar.o。
依赖中间文件 .o 文件生成最终的可执行文件,可以避免编译整个文件。哪个文件发生了改变,只需编译该文件对应的 .o 文件即可。之后再与其他文件共同生成最终的可执行文件。
最终编译结果如下图所示:
从图中可以看出,terminal 中的执行顺序是与 Makefile 中的书写顺序相反的,将 Makefile 中的内容由下至上执行。
小伙伴们,可能还注意到,Makefile 的最后一行有 clean 项。
这个主要是为了发布源代码用的,如果执行 make clean
命令,clean 项中的内容就会被执行。此处就是删除所有 .o 文件 和 可执行文件 main,只保留源代码。
4. Makefile 实用技巧
4.1 变量
编译源代码时,可以使用 gcc,也可以使用 g++。要是我突然想换个编译器编译源代码该怎么办呢?
一个文件一个文件地手动改吗?把所有的 gcc 改成 g++?
有没有什么好办法呢?当然有了。
可以在 Makefile 中使用变量。话不多说,看个例子。
CC = gcc
CFLAGS = -lm -Wall -g
main: main.c tool.o bar.o
$(CC) $(CFLAGS) main.c tool.o bar.o -o main
tool.o: tool.c
$(CC) $(CFLAGS) -c tool.c
bar.o: bar.c
$(CC) $(CFLAGS) -c bar.c
clean:
rm *.o main
这个 Makefile 文件用变量 CC 保存了 gcc。也可以使用变量保存一些编译选项,如这里的 -lm -Wall -g
。最后的编译结果如下图所示:
4.2 生成多个可执行文件
这里打算分别生成 main_min 和 main_max 文件。两个文件分别输出所给数组的最小值和最大值。下面是源文件:
main_min.c
#include "tool.h"
#include "bar.h"
#include <stdio.h>
int main()
{
int arr[5] = {1,9,3,8,0};
int min = find_min(arr, 5);
printf("min = %d\n", min);
return 0;
}
main_max.c
#include "tool.h"
#include "bar.h"
#include <stdio.h>
int main()
{
int arr[5] = {1,9,3,8,0};
int max = find_max(arr, 5);
printf("max = %d\n", max);
return 0;
}
如果 Makefile 按照上面的方式直接写,那么只会生成第一个文件可执行文件。
Makefile
main_max: main_max.c tool.o bar.o
gcc main_max.c tool.o bar.o -o main_max
main_min: main_min.c tool.o bar.o
gcc main_min.c tool.o bar.o -o main_min
tool.o: tool.c
gcc -c tool.c
bar.o: bar.c
gcc -c bar.c
clean:
rm *.o main_max main_min
执行结果如下所示,只生成了 main_max。
要想生成多个可执行文件,需要加入 all 字段。Makefile 文件如下所示:
all:main_max main_min
main_max: main_max.c tool.o bar.o
gcc main_max.c tool.o bar.o -o main_max
main_min: main_min.c tool.o bar.o
gcc main_min.c tool.o bar.o -o main_min
tool.o: tool.c
gcc -c tool.c
bar.o: bar.c
gcc -c bar.c
clean:
rm *.o main_max main_min
main_max: main_max.c tool.o bar.o
gcc main_max.c tool.o bar.o -o main_max
main_min: main_min.c tool.o bar.o
gcc main_min.c tool.o bar.o -o main_min
tool.o: tool.c
gcc -c tool.c
bar.o: bar.c
gcc -c bar.c
clean:
rm *.o main_max main_min
执行结果如下所示,生成了多个可执行文件:main_max 和 main_min。
参考文献
更多推荐
所有评论(0)