12. Makefile文件
一、什么是Makefile文件
Makefile 文件时一种用于管理和自动化软件编译过程的文本文件。它通常包含了一系列规则,这些规则描述了如何根据源代码文件生成可执行文件或者其它目标文件。Makefile 的核心概念是规则和依赖关系,规则定义了如何生成一个或多个目标文件,而依赖关系则指定了生成目标文件所需要的源文件或其它依赖文件。
在使用 Makefile 文件之前,我们需要先安装 build-essential 工具包 或 CMake 工具。
sudo apt install -y build-essential
或
sudo apt install -y cmake
我们新建一个 hello.h 头文件,它的内容如下:
#ifndef __HELLO_H__
#define __HELLO_H__
#include <stdio.h>
void say_hello(char *name);
#endif // !__HELLO_H__
然后,我们在新建一个 hello.c 源文件,它的内容如下:
#include "hello.h"
void say_hello(char *name)
{
printf("Hello %s, nice to meet you!\n", name);
}
接着,我们在新建一个 main.c 源文件,它的内容如下:
#include "hello.h"
int main(void)
{
say_hello("Sakura");
return 0;
}
然后,我们在新建一个 Makefile
文件,它的内容如下:
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 目标是 main,依赖 hello.h 和 main.o
# 编译的命令是 gcc hello.o main.o -o main
main: hello.o main.o
gcc hello.o main.o -o main
# 目标是 main.o,依赖 main.c 和 hello.h
# 编译的命令是 gcc -c main.c -o main.o
main.o: main.c hello.h
gcc -c main.c -o main.o
# 目标是 hello.o,依赖 hello.c 和 hello.h
# 编译的命令是 gcc -c hello.c -o main.o
hello.o: hello.c hello.h
gcc -c hello.c -o hello.o
Makefile 中每个规则的命名必须以一个制表符(tab)开始,而不能是空格,否则会提示 “缺失分隔符”
接着,我们在 Makefile 所在的目录下输入 make
命令,我们会发现出现 hello.o 和 main.o 中间文件和 main 可执行文件。然后,我们在终端中输入 ./main
运行可执行文件。
make
./main
如果我们要清除中间生成的文件,可以在 Makefile 文件中使用 clean
工具。
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 目标是 main,依赖 hello.h 和 main.o
# 编译的命令是 gcc hello.o main.o -o main
main: hello.o main.o
gcc hello.o main.o -o main
# 目标是 main.o,依赖 main.c 和 hello.h
# 编译的命令是 gcc -c main.c -o main.o
main.o: main.c hello.h
gcc -c main.c -o main.o
# 目标是 hello.o,依赖 hello.c 和 hello.h
# 编译的命令是 gcc -c hello.c -o main.o
hello.o: hello.c hello.h
gcc -c hello.c -o hello.o
# 清除不想要的内容
clean:
rm main.o hello.o
在使用 make 生成可执行文件后,我们需要使用 make clean
删除中间文件。
make clean
二、引入变量
Makefile 文件为了方便,可以引入临时变量,变量定义的语法格式如下:
变量名 := 变量值
在定义完变量之后,我们可以使用 $
来使用变量,它的语法格式如下:
${变量名}
或
$(变量名)
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 定义变量
objects := hello.o \
main.o
# 目标是 main,依赖 hello.h 和 main.o
# 编译的命令是 gcc hello.o main.o -o main
main: ${objects}
gcc $(objects) -o main
# 目标是 main.o,依赖 main.c 和 hello.h
# 编译的命令是 gcc -c main.c -o main.o
main.o: main.c hello.h
gcc -c main.c -o main.o
# 目标是 hello.o,依赖 hello.c 和 hello.h
# 编译的命令是 gcc -c hello.c -o main.o
hello.o: hello.c hello.h
gcc -c hello.c -o hello.o
# 清除不想要的内容
clean:
rm main.o hello.o
三、自动推导
make 可以根据目标自动加入所需的依赖文件和命令。例如 main.o 目标,会默认将 main.c 作为依赖加入,同时也可以推导出编译 main.o 的命令,于是我们可以简化 Makefile 文件,简化后的文件内容如下:
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 目标是 main,依赖 hello.h 和 main.o
# 编译的命令是 gcc hello.o main.o -o main
main: hello.o main.o
gcc hello.o main.o -o main
# 如果不写 hello.h 依赖文件,则监控不到该文件的变化
main.o: hello.h
hello.o: hello.h
# 清除不想要的内容
clean:
rm main.o hello.o
四、伪目标
伪目标并不代表实际的文件名,它们更多的是行为或用户的标识符。伪目标并不生成具体问及爱你,我们可以使用 .PHONY
声明伪目标。
.PHONY 目标
如果当前目录下存在一个 clean 文件,此时执行 make clean
命令删除中间文件时,make 会将 clean 作为普通目标处理,它先检查 clean 的依赖(不存在),然后发现 clean 文件已存在且没有依赖更新(因为不存在,自然不需要更新),因此不会执行规则下的命令。
此时,我们可以在 Makefile 中添加 .PHONY: clean
将 clean 声明为伪目标,然后重新执行 make clean
命令。
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 目标是 main,依赖 hello.h 和 main.o
# 编译的命令是 gcc hello.o main.o -o main
main: hello.o main.o
gcc hello.o main.o -o main
# 如果不写 hello.h 依赖文件,则监控不到该文件的变化
main.o: hello.h
hello.o: hello.h
# 声明伪目标
.PHONY: clean
# 清除不想要的内容
clean:
rm main.o hello.o
五、忽略错误
如果我们执行过一次 make clean
删除中间文件,在执行一次 make clean
删除文件,会报无法删除文件,找不到那个文件或目录错误。此时,我们可以在删除文件命令加上一个 -
忽略错误。
六、Makefile文件模板
# Makefile文件由以下3部分组成
#目标文件:前置依赖
# \t<需要执行的命令>
# 定义变量
CC := gcc
# $@ 是目标文件名,$^ 是依赖文件名
# $(CC) -o $@ $^ 相当于 gcc -o main main.o hello.o
# ./$@ 相当于 ./main
# rm $^ 相当于 rm main.o hello.o
main: main.o hello.o
- $(CC) -o $@ $^
- ./$@
- rm ./$^
# 目标是 main.o,依赖 main.c 和 hello.h,可以自动推导出需要 main.c
# 如果不写 hello.h 依赖文件,则监控不到该文件的变化
main.o: hello.h
# 目标是 hello.o,依赖 hello.c 和 hello.h,可以自动推导出需要 hello.c
hello.o: hello.h
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2024-02-08 02. µCOS-Ⅲ的基本使用