目录
3.1.2.1 使用make -f 命令执行默认make操作
3.1.2.2使用 make [ ‐f file ] [ targets ]命令
3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并执行可执行程序
1.make

1.1 make 命令格式
make [ ‐f file ] [ targets ]
2.Makefile 核心概念
作用:
自动化编译和链接程序,管理项目依赖关系,避免重复编译未修改的代码。
基本结构:
target: dependencies
command
target: 生成的目标(如可执行文件、中间文件)
dependencies: 生成目标所需的文件或目标
command: 生成目标的命令(必须以 Tab 开头)
2.1创建并运行 Makefile步骤
基本步骤:
- 创建文件:在项目根目录创建名为 Makefile 的文件(无后缀)。
- 编写规则:定义目标(如可执行文件)、依赖(如 .c 和 .o 文件)和命令。
- 运行命令:在终端执行 make 或 make <target>。
3. Makefile编写
make 命令格式
make [ ‐f file ] [ targets ]
3.1最基础Makefile
3.1.1使用默认make命令
程序:
main.c
#include <stdio.h>
#include "main.h"
int main(int argc, char const *argv[])
{
printf("main函数开始\n");
printf("ABC = %d abc = %d\n",ABC, abc);
return 0;
}
main.h
#define ABC 123
#define abc 456
makefile
main:main.c main.h
gcc main.c -o main
clean:
rm main
makefile内容解释:
main:main.c main.h //可执行文件main依赖main.c main.h
gcc main.c -o main //由mian.c 生成可执行文件main
clean:
rm main //执行 make clean 命令,删除可执行文件main
运行结果:
3.1.2使用make -f 命令
3.1.2.1 使用make -f 命令执行默认make操作
程序:与3.1.1使用默认make命令一样。
makefile:与3.1.1使用默认make命令一样。仅名称不同。
将可执行文件main删除,Makefile复制一份,重命名为Makefile1,执行 make -f Makefile1
也可以正常执行make命令。执行结果与默认make命令结果相同。
3.1.2.2使用 make [ ‐f file ] [ targets ]命令
程序:与3.1.1使用默认make命令一样。
makefile:
test:main.c main.h
gcc main.c -o main
@echo "=== test ==="
clean:
rm main
@echo "=== clean ==="
test1:
@echo "=== test1 ==="; # @符号注释见下面
#echo前使用 @:在 echo 前添加 @ 符号,可隐藏命令本身的输出,仅显示命令的执行结果
#终端结果: === test1 ===
#未使用 @:命令本身和执行结果都会显示,
#终端结果: echo "=== test1 ==="
# === test1 ===
# 在 Makefile 中直接写 @echo "注释内容" # 注释内容, 注释内容会输出在终端,
# 因为 # 必须出现在行首或通过 ; 分隔
test2:
@echo "=== test2 ==="; # @符号注释见上面
(1)执行 make -f Makefile2 test1 test test2
test1 test test2 为Makefile2中的三个目标文件,执行上述命令,先运行test1里面的运行命令,在运行test运行命令,最后运行test2运行命令。
运行结果:
(2)执行 make -f Makefile2 test1 test2 clean 命令
test1 test2 clean 为Makefile2中的三个目标文件,执行上述命令,先运行test1里面的运行命令,在运行test2运行命令,最后运行clean运行命令。
运行结果:
注意:保证执行 clean命令,确保删除的文件要存在。
删除文件不存在运行结果:
3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并执行可执行程序
程序:与3.1.1使用默认make命令一样。
makefile:
test:main.c main.h
gcc main.c -o main
@echo "=== test ==="
clean:
rm main
@echo "=== clean ==="
test1:
@echo "=== test1 ==="; # @符号注释见下面
#echo前使用 @:在 echo 前添加 @ 符号,可隐藏命令本身的输出,仅显示命令的执行结果
#终端结果: === test1 ===
#未使用 @:命令本身和执行结果都会显示,
#终端结果: echo "=== test1 ==="
# === test1 ===
# 在 Makefile 中直接写 @echo "注释内容" # 注释内容, 注释内容会输出在终端,
# 因为 # 必须出现在行首或通过 ; 分隔
test2:
@echo "=== test2 ==="; # @符号注释见上面
(1)执行 make -f Makefile2 test1 test2 test;./main 命令
执行Makefile命令后,并运行生成的可执行文件
(2)执行 make -f Makefile2 test;./main 命令
执行Makefile命令后,并运行生成的可执行文件
3.1.3 gcc编译常用组合选项
选项 | 作用 | 示例 |
---|---|---|
-o |
指定输出文件名 | gcc -c main.c -o main.o |
-I |
指定头文件搜索路径 | gcc -c main.c -I../include |
-Wall |
启用所有警告信息 | gcc -c main.c -Wall |
-g |
生成调试信息(用于 GDB) | gcc -c main.c -g |
-O2 |
启用优化(级别 2) | gcc -c main.c -O2 |
3.1.4 make 和 make all区别
关键总结
场景 | make 行为 |
make all 行为 |
---|---|---|
all 是默认目标 |
执行 all |
执行 all |
all 不是默认目标 |
执行第一个目标(如 build ) |
执行 all (需存在定义) |
未定义 all |
执行第一个目标 | 报错 |
强制 .DEFAULT_GOAL=all |
执行 all |
执行 all |
3.1.4.1 all 是默认目标
当 all 是默认目标时,make 和 make all 运行顺序,结果相同。
程序:
main.c
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("main x= %d y= %d \n", x, y);
return 0;
}
makefile
# all 是第一个目标(默认目标)
all:target
echo " all开始"
target:main.c
gcc main.c -o main
echo " main开始"
clean:
rm main *.o -rf
运行结果:当 all 是默认目标时,make 和 make all 运行顺序,结果相同。
(1)make all
(2)make
3.1.4.2 all 不是默认目标
all 不是默认目标,执行make all命令,会先执行 all依赖的命令。
程序:
main.c
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("main x= %d y= %d \n", x, y);
return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
# 要使用 make -f Makefile名称,执行make命令
# all 不是第一个目标
target:main.c
gcc main.c -o main
echo " main开始"
all:clean target
echo " all开始"
clean:
rm main *.o -rf
运行结果:
(1) 首次make 编译, 执行默认目标 target,编译 gcc main.c -o main
(2)执行make all命令,会先执行 clean命令 rm main *.o -rf,在编译gcc main.c -o main
3.1.4.3 没有定义 all 命令
main.c
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("main x= %d y= %d \n", x, y);
return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
# 要使用 make -f Makefile名称,执行make命令
target:main.c
gcc main.c -o main
echo " main开始"
clean:
rm main *.o -rf
运行结果:make all运行报错,make正常运行。
3.1.4.3 强制设置 all 为默认目标
main.c
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("main x= %d y= %d \n", x, y);
return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
# 要使用 make -f Makefile名称,执行make命令
# 显式设置 .DEFAULT_GOAL 为 all
.DEFAULT_GOAL = all
target:main.c
gcc main.c -o main
echo " main开始"
all:clean target
echo " all开始"
clean:
rm main *.o -rf
运行结果:强制设置 all 为默认目标,执行make命令,先执行all依赖的语句。
3.2多文件编程Makefile-基础
main.c
#include "head.h"
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("%d + %d = %d\n", x, y, sum(x, y));
printf("%d - %d = %d\n", x, y, sub(x, y));
return 0;
}
sub.c
#include "head.h"
int sub(int a, int b)
{
return a - b;
}
sum.c
#include "head.h"
int sum(int a, int b)
{
return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
int sum(int a, int b);
int sub(int a, int b);
#endif
Makefile
main:main.o sub.o sum.o
gcc main.o sub.o sum.o -o main
main.o:main.c
gcc -c main.c -o main.o
sub.o:sub.c
gcc -c sub.c -o sub.o
sum.o:sum.c
gcc -c sum.c -o sum.o
clean:
rm *.o main a.out -rf
Makefile语句解释:
main:main.o sub.o sum.o //可执行文件main依赖于main.o sub.o sum.o
gcc main.o sub.o sum.o -o main //gcc 编译 main.o sub.o sum.o 生成可执行文件main
main.o:main.c //可执行文件main.o依赖于main.c
gcc -c main.c -o main.o //gcc 编译 main.c 生成可执行文件main.o
sub.o:sub.c //可执行文件sub.o依赖于sub.c
gcc -c sub.c -o sub.o //gcc 编译 sub.c 生成可执行文件sub.o
sum.o:sum.c //可执行文件sum.o依赖于sum.c
gcc -c sum.c -o sum.o //gcc 编译 sum.c 生成可执行文件sum.o
clean:
rm *.o main a.out -rf //执行 make clean删除可执行文件,所有.o文件 main a.out
执行顺序:
可执行文件main依赖于main.o,main.o又依赖于main.c,先执行gcc -c main.c -o main.o,在执行gcc main.o sub.o sum.o -o main
运行结果:
3.3makefile变量
3.3.1 makefile 变量概述
3.3.2 makefile 的变量分类:
3.3.3 自定义变量语法
常用变量:
定义变量:VAR = value
使用变量:$(VAR)
常用内置变量:
CC:C 编译器(默认 cc,通常指向 gcc)。
CFLAGS:C 编译选项(如 -Wall -O2)。
LDFLAGS:链接选项(如 -L 指定库路径)。
LDLIBS:链接库(如 -lm 表示数学库)。
3.3.3.1自定义变量makefile多文件编程
程序:
main.c
#include "head.h"
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("%d + %d = %d\n", x, y, sum(x, y));
printf("%d - %d = %d\n", x, y, sub(x, y));
return 0;
}
sub.c
#include "head.h"
int sub(int a, int b)
{
return a - b;
}
sum.c
#include "head.h"
int sum(int a, int b)
{
return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
int sum(int a, int b);
int sub(int a, int b);
#endif
Makefile
CC=gcc
obj=main
obj1=sub
obj2=sum
OBJS=main.o sub.o sum.o
$(obj):$(OBJS)
$(CC) $(OBJS) -o $(obj)
$(obj).o:$(obj).c
$(CC) -c $(obj).c -o $(obj).o
$(obj1).o:$(obj1).c
$(CC) -c $(obj1).c -o $(obj1).o
$(obj2).o:$(obj2).c
$(CC) -c $(obj2).c -o $(obj2).o
clean:
rm *.o $(obj) a.out -rf
Makefile语句解释:与3.2多文件编程Makefile-基础,一样,只是替换为自定义的变量
main:main.o sub.o sum.o //可执行文件main依赖于main.o sub.o sum.o
gcc main.o sub.o sum.o -o main //gcc 编译 main.o sub.o sum.o 生成可执行文件main
main.o:main.c //可执行文件main.o依赖于main.c
gcc -c main.c -o main.o //gcc 编译 main.c 生成可执行文件main.o
sub.o:sub.c //可执行文件sub.o依赖于sub.c
gcc -c sub.c -o sub.o //gcc 编译 sub.c 生成可执行文件sub.o
sum.o:sum.c //可执行文件sum.o依赖于sum.c
gcc -c sum.c -o sum.o //gcc 编译 sum.c 生成可执行文件sum.o
clean:
rm *.o main a.out -rf //执行 make clean删除可执行文件,所有.o文件 main a.out
执行顺序:
可执行文件main依赖于main.o,main.o又依赖于main.c,先执行gcc -c main.c -o main.o,在执行gcc main.o sub.o sum.o -o main
运行结果:
3.3.4系统变量
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("x = %d y = %d \n", x, y);
return 0;
}
Makefile
main:main.c
gcc main.c -o main
clean:
rm main -rf
echo $(PWD)
echo $(HOME)
echo $(HOSTNAME)
echo $(MY_SHELL_NUM)

3.3.5预定义变量
$@ 目标名
$< 依赖文件列表中的第一个文件
$^ 依赖文件列表中除去重复文件的部分
AR 归档维护程序的程序名,默认值为 ar
ARFLAGS 归档维护程序的选项
AS 汇编程序的名称,默认值为 as
ASFLAGS 汇编程序的选项
CC C 编译器的名称,默认值为 cc
CFLAGS C 编译器的选项
CPP C 预编译器的名称,默认值为$(CC) -E
CPPFLAGS C 预编译的选项
CXX C++编译器的名称,默认值为 g++
CXXFLAGS C++编译器的选项
3.3.5.1编译器与工具
变量名 | 默认值 | 描述 | 示例用法 |
---|---|---|---|
CC |
cc |
C 编译器 | CC = gcc |
CXX |
g++ |
C++ 编译器 | CXX = clang++ |
AR |
ar |
静态库打包工具 | AR = ar rcs |
AS |
as |
汇编器 | AS = nasm |
LD |
ld |
链接器 | LD = lld |
3.3.5.2. 编译选项
变量名 | 描述 | 默认值 | 示例用法 |
---|---|---|---|
CFLAGS |
C 编译选项 | 空 | CFLAGS = -O2 -Wall |
CXXFLAGS |
C++ 编译选项 | 空 | CXXFLAGS = -std=c++17 |
CPPFLAGS |
预处理选项(C/C++通用) | 空 | CPPFLAGS = -Iinclude |
LDFLAGS |
链接器选项(如库路径) | 空 | LDFLAGS = -Llib |
LDLIBS |
链接的库(如 -lm ) |
空 | LDLIBS = -lpthread |
3.3.5.3. 文件与目录
变量名 | 描述 | 默认值 | 示例用法 |
---|---|---|---|
MAKEFILE_LIST |
当前 Makefile 文件名列表 | 自动生成 | 用于条件判断 |
VPATH |
搜索源文件的目录列表 | 空 | VPATH = src:lib |
SRC |
自定义源文件变量 | 无 | SRC = main.c utils.c |
OBJ |
自定义目标文件变量 | 无 | OBJ = $(SRC:.c=.o) |
3.3.5.4. 隐式规则中的关键变量
Make 根据文件后缀自动推导编译规则,以下变量控制隐式规则行为:
变量名 | 描述 | 默认命令 | 示例覆盖 |
---|---|---|---|
COMPILE.c |
C 文件编译命令 | $(CC) $(CFLAGS) $(CPPFLAGS) -c |
COMPILE.c = $(CC) -O3 |
LINK.c |
C 程序链接命令 | $(CC) $(CFLAGS) $(LDFLAGS) |
LINK.c = $(CC) -flto |
3.3.5.5. 常用内置变量
变量名 | 描述 | 示例值 |
---|---|---|
MAKE |
当前 Make 命令路径 | /usr/bin/make |
MAKECMDGOALS |
用户指定的目标列表 | all clean |
CURDIR |
当前工作目录 | /home/user/project |
3.3.5.6.程序验证
程序:
main.c
#include "head.h"
int main(int argc, const char *argv[])
{
int x = 60;
int y = 20;
printf("%d + %d = %d\n", x, y, sum(x, y));
printf("%d - %d = %d\n", x, y, sub(x, y));
return 0;
}
sub.c
#include "head.h"
int sub(int a, int b)
{
return a - b;
}
sum.c
#include "head.h"
int sum(int a, int b)
{
return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
int sum(int a, int b);
int sub(int a, int b);
#endif
Makefile
CC=gcc
obj=main
obj1=sub
obj2=sum
OBJ=main.o sub.o sum.o
CFLAGS=-Wall -O2
# -Wall警告相关, -O2:优化选项,兼顾编译速度和性能
$(obj):$(OBJ)
$(CC) $^ -o $@
$(obj).o:$(obj).c
$(CC) $(CFLAGS) -c $< -o $@
$(obj1).o:$(obj1).c
$(CC) $(CFLAGS) -c $< -o $@
$(obj2).o:$(obj2).c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm *.o $(obj) a.out -rf
Makefile语句解释:
与3.3.3 自定义变量语法,一样,只是替换为预定义的变量。表达式的区别见4.几种多文件编程Makefile对应关系。
运行结果:
注:Makefile更精简表达式
Makefile1
CC=gcc
obj=main
OBJ=main.o sub.o sum.o
CFLAGS=-Wall -g
$(obj):$(OBJ)
$(CC) $^ -o $@
%*.o:%*.c #使用通配符匹配,所有.c文件都去执行下面的命令
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm *.o $(obj) a.out -rf
运行结果:与上述Makefile运行结果相同
(1)先在终端执行 make clean (2)终端执行 make -f Makefile1
4.几种多文件编程Makefile对应关系
多文件编程Makefile最基础、自定义变量、预定义变量对应关系。
每一行为几种方法相同结果,不同格式的变量表达式。