Makefile从入门到上手 1

简介: Makefile从入门到上手

前言

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

本文记录了 Makefile 的使用。


一、Makefile 介绍

Makefile 是一个名为 GNU-Make 软件所需要的脚本文件,该脚本文件可以指导 Make 软件控制 arm-gcc 等工具链去编译工程文件最终得到可执行文件,几乎所有的 Linux 发行版都内置了 GNU-Make 软件,VScode 等多种 IDE 也内置了 Make 程序。说白了,Makefile 就是用来管理项目的。

你见到的 xxx.mk 文件或者 Makefile 都统称为 Makefile 脚本文件。命名只能为 makefile 或者是 Makefile,因为只有这两种命名方式才能被 make 命令识别。

Makefile 脚本文件的语法学习可以参考:跟我一起写Makefile 陈皓

二、示例源码

这里放出供下面 Makefile 基础规则中用来测试的源码。

1、hello.c

#include <stdio.h>
#include "head.h"
int main(int argc, char *argv[])
{
    int a = 10; int b = 5;
    printf("%d+%d=%d\n", a, b, add(a, b));
    printf("%d-%d=%d\n", a, b, sub(a, b));
    printf("%d/%d=%d\n", a, b, div(a, b));
    printf("%dx%d=%d\n", a, b, mul(a, b));
  return 0;
}

2、add.c

int add(int a, int b)
{
  return a+b;
}

3、sub.c

int sub(int a, int b)
{
  return a-b;
}

4、mul.c

int mul(int a, int b)
{
  return a*b;
}

5、div.c

int div(int a, int b)
{
  return a/b;
}

6、head.h

#ifndef _HEAD_H_
#define _HEAD_H_
int add(int , int );
int sub(int , int );
int div(int , int );
int mul(int , int );
#endif

三、Makefile 基础规则

想要掌握 makefile,首先需要了解两个概念,⼀个是目标(target),另⼀个就是依赖

(dependency)。目标就是指要干什么,或说运行 make 后生成什么,而依赖是告诉 make 如何去做以实现目标。在 Makefile 中,目标和依赖是通过规则(rule)来表达的。

makefile 的依赖是从上至下的,换句话说就是目标文件是第一句里的目标, 如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。make 会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。

Makefile 三要素:

工作原理:

1、一个规则

1个规则

目标:依赖条件
(一个 tab 缩进)命令

①、目标的时间必须晚于依赖条件的时间,否则,更新目标。

②、依赖条件如果不存在,找寻新的规则去产生依赖条件。

下面来一步一步升级 makefile

利用上述代码实现第一个版本的 Makefile

Makefile 第一版

a.out : hello.c add.c sub.c mul.c div.c
  gcc hello.c add.c sub.c mul.c div.c -o a.out -I ./

执行 make :

此时,修改 add.c 为下面

add.c

int add(int a, int b)
{
  return a+b+1;
}

此时,再使用 make,发现了问题

可以看到,只修改 add.c,但是编译的时候,其他.c 文件也重新编译了,这不太科学。明明只改了一个,全部都重新编译了。

于是将 makefile 改写如下:

Makefile 第二版

a.out : hello.o add.o sub.o mul.o div.o
  gcc hello.o add.o sub.o mul.o div.o -o a.out 
hello.o : hello.c
  gcc -c hello.c -o hello.o -I ./
add.o : add.c
  gcc -c add.c -o add.o
sub.o : sub.c
  gcc -c sub.c -o sub.o
mul.o : mul.c
  gcc -c mul.c -o mul.o
div.o : div.c
  gcc -c div.c -o div.o

执行 make 指令如下:

此时,再将 add.c 改为最开始的代码:

add.c

int add(int a, int b)
{
  return a+b;
}

执行 make 指令如下:

可以看到,只重新编译了修改过的 add.c 和最终目标

makefile 检测原理:修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料的时间,出现这种情况的文件会重新编译。修改 add.c 后, add.o 的时间就早于 add.c , a.out 的时间也早于 add.o 的时间了,于是重新编译这俩文件了。

关于 makefile 指定目标问题,先修改 makefile 如下:

Makefile 第三版

hello.o : hello.c
  gcc -c hello.c -o hello.o -I ./
add.o : add.c
  gcc -c add.c -o add.o
sub.o : sub.c
  gcc -c sub.c -o sub.o
mul.o : mul.c
  gcc -c mul.c -o mul.o
div.o : div.c
  gcc -c div.c -o div.o
a.out : hello.o add.o sub.o mul.o div.o
  gcc hello.o add.o sub.o mul.o div.o -o a.out 

只是将 a.out 放在了文件末尾

执行 make,如下:

这是因为, makefile 默认第一个目标文件为终极目标,生成就跑路,这时候可以用 ALL 来指定终极目标。

ALL:指定 makefile 的终极目标。

指定目标的 makefile 如下:

Makefile 第四版

ALL : a.out
hello.o : hello.c
  gcc -c hello.c -o hello.o -I ./
add.o : add.c
  gcc -c add.c -o add.o
sub.o : sub.c
  gcc -c sub.c -o sub.o
mul.o : mul.c
  gcc -c mul.c -o mul.o
div.o : div.c
  gcc -c div.c -o div.o
a.out : hello.o add.o sub.o mul.o div.o
  gcc hello.o add.o sub.o mul.o div.o -o a.out

执行:

目录
相关文章
|
1月前
|
编译器 Shell Linux
Makefile(3)进阶
Makefile(3)进阶
27 0
|
1月前
|
Linux 编译器 C语言
Linux应用开发基础知识——Makefile 的使用(二)
Linux应用开发基础知识——Makefile 的使用(二)
42 0
Linux应用开发基础知识——Makefile 的使用(二)
|
8月前
|
Java 编译器 Linux
Makefile教程(入门介绍)
Makefile教程(入门介绍)
80 0
|
8月前
|
开发者
Makefile基础教程(伪目标)
Makefile基础教程(伪目标)
55 0
|
1月前
Makefile(1)入门
Makefile(1)入门
24 0
|
1月前
|
Linux 编译器 C语言
快速上手makefile自动化构建工具
快速上手makefile自动化构建工具
|
1月前
|
编译器 Shell C语言
Makefile快速入门
Makefile快速入门
32 0
|
7月前
|
存储 Shell
CMake01快速上手
本文旨在快速上手并且使用cmake,更多深入内容请参考后续的blog。
|
8月前
|
编译器
Makefile基础教程(路径搜索)
Makefile基础教程(路径搜索)
90 0
|
9月前
|
Unix Shell
Makefile从入门到上手 3
Makefile从入门到上手
44 0

热门文章

最新文章