Linux Makefile-概述、语句格式、编写规则、多文件编程、Makefile变量分类:自定义变量、预定义变量

目录

1.make

[1.1 make 命令格式](#1.1 make 命令格式)

[2.Makefile 核心概念‌ ‌](#2.Makefile 核心概念‌ ‌)

[2.1创建并运行 Makefile步骤](#2.1创建并运行 Makefile步骤)

[3. Makefile编写](#3. Makefile编写)

3.1最基础Makefile

3.1.1使用默认make命令

[3.1.2使用make -f 命令](#3.1.2使用make -f 命令)

[3.1.2.1 使用make -f 命令执行默认make操作](#3.1.2.1 使用make -f 命令执行默认make操作)

[3.1.2.2使用 make [ ‐f file ] [ targets ]命令](#3.1.2.2使用 make [ ‐f file ] [ targets ]命令)

[3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并执行可执行程序](#3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并执行可执行程序)

[3.1.3 gcc编译常用组合选项](#3.1.3 gcc编译常用组合选项)

[3.1.4 make 和 make all区别](#3.1.4 make 和 make all区别)

[3.1.4.1 all 是默认目标](#3.1.4.1 all 是默认目标)

[3.1.4.2 all 不是默认目标](#3.1.4.2 all 不是默认目标)

[3.1.4.3 没有定义 all 命令](#3.1.4.3 没有定义 all 命令)

[3.1.4.3 强制设置 all 为默认目标](#3.1.4.3 强制设置 all 为默认目标)

3.2多文件编程Makefile-基础

3.3makefile变量

[3.3.1 makefile 变量概述](#3.3.1 makefile 变量概述)

[3.3.2 makefile 的变量分类:](#3.3.2 makefile 的变量分类:)

[3.3.3 自定义变量语法](#3.3.3 自定义变量语法)

3.3.3.1自定义变量makefile多文件编程

3.3.4系统变量

3.3.5预定义变量

3.3.5.1编译器与工具

[3.3.5.2. 编译选项](#3.3.5.2. 编译选项)

[3.3.5.3. 文件与目录](#3.3.5.3. 文件与目录)

[3.3.5.4. 隐式规则中的关键变量](#3.3.5.4. 隐式规则中的关键变量)

[3.3.5.5. 常用内置变量](#3.3.5.5. 常用内置变量)

3.3.5.6.程序验证

4.几种多文件编程Makefile对应关系


1.make

make是个命令,是个可执行程序,用来解析Makefile文件的命令。
终端输入:which make 查看make保存地址,在 /usr/bin/make

1.1 make 命令格式

objectivec 复制代码
make [ ‐f file ] [ targets ]

(1)[ -f file ]:
make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为
makefile输入文件, -f 可以指定以上名字以外的文件作为makefile输入文件
(2)[ targets ]:
若使用make命令时没有指定目标,则make工具默认会实现makefile文件内的第一个目 标 ,然后退出,指定了make工具要实现的目标,目标可以是一个或多个(多个目标间用空 格隔开)。

2.Makefile 核心概念‌ ‌

作用‌:

自动化编译和链接程序,管理项目依赖关系,避免重复编译未修改的代码。

‌基本结构:

objectivec 复制代码
target: dependencies
    command

‌target‌: 生成的目标(如可执行文件、中间文件)
‌dependencies‌: 生成目标所需的文件或目标
‌command‌: 生成目标的命令(必须以 Tab 开头)

2.1创建并运行 Makefile步骤

基本步骤:

  • 创建文件:在项目根目录创建名为 Makefile 的文件(无后缀)。
  • 编写规则:定义目标(如可执行文件)、依赖(如 .c 和 .o 文件)和命令。
  • 运行命令:在终端执行 make 或 make <target>。

3. Makefile编写

make 命令格式

objectivec 复制代码
make [ ‐f file ] [ targets ]

(1)[ -f file ]:
make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为
makefile输入文件, -f 可以指定以上名字以外的文件作为makefile输入文件
(2)[ targets ]:
若使用make命令时没有指定目标,则make工具默认会实现makefile文件内的第一个目 标 ,然后退出,指定了make工具要实现的目标,目标可以是一个或多个(多个目标间用空 格隔开)。

3.1最基础Makefile

3.1.1使用默认make命令

程序:

main.c

objectivec 复制代码
#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

objectivec 复制代码
#define ABC 123
#define abc 456

makefile

objectivec 复制代码
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:

objectivec 复制代码
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:

objectivec 复制代码
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

objectivec 复制代码
#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

objectivec 复制代码
# 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

objectivec 复制代码
#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

objectivec 复制代码
# 若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

objectivec 复制代码
#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

objectivec 复制代码
# 若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

objectivec 复制代码
#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

objectivec 复制代码
# 若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

objectivec 复制代码
#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

objectivec 复制代码
#include "head.h"

int sub(int a, int b)
{

	return a - b;
}

sum.c

objectivec 复制代码
#include "head.h"

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

head.h

objectivec 复制代码
#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>

int sum(int a, int b);
int sub(int a, int b); 

#endif

Makefile

objectivec 复制代码
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****变量概述

makefile 变量类似于 C 语言中的宏,当 makefile 被 make 工具解析时,其中的变量会被展开。
变量的作用:
保存文件名列表
保存文件目录列表
保存编译器名
保存编译参数
保存编译的输出
...

3.3.2 makefile****的变量分类:

1 、自定义变量
在 makefile 文件中定义的变量。
make 工具传给 makefile 的变量。
2 、系统环境变量
make 工具解析 makefile 前,读取系统环境变量并设置为 makefile 的变量。
3 、预定义变量(自动变量)

3.3.3****自定义变量语法

定义变量:
变量名 = 变量值
引用变量:
( 变量名 ) 或 { 变量名 }
makefile 的变量名 :
makefile 变量名可以以数字开头
注意:
1 、变量是大小写敏感的
2 、变量一般都在 makefile 的头部定义
3 、变量几乎可在 makefile 的任何地方使用

常用变量:

objectivec 复制代码
定义变量:VAR = value
使用变量:$(VAR)
常用内置变量:
CC:C 编译器(默认 cc,通常指向 gcc)。
CFLAGS:C 编译选项(如 -Wall -O2)。
LDFLAGS:链接选项(如 -L 指定库路径)。
LDLIBS:链接库(如 -lm 表示数学库)。
3.3.3.1自定义变量makefile多文件编程

程序:

main.c

objectivec 复制代码
#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

objectivec 复制代码
#include "head.h"

int sub(int a, int b)
{

	return a - b;
}

sum.c

objectivec 复制代码
#include "head.h"

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

head.h

objectivec 复制代码
#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>

int sum(int a, int b);
int sub(int a, int b); 

#endif

Makefile

objectivec 复制代码
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系统变量

make 工具会拷贝系统的环境变量并将其设置为 makefile 的变量,在 makefile 中可直接读取或修改拷贝后的变量。
程序:
main.c

objectivec 复制代码
#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

objectivec 复制代码
main:main.c
	gcc main.c -o main 
	
clean:
	rm main -rf
	echo $(PWD)
	echo $(HOME)
	echo $(HOSTNAME)
	echo $(MY_SHELL_NUM)

运行结果:
(1)先在终端执行shell脚本,设置一个预设环境变量,echo 输出一下。
MY_SHELL_NUM=123
export MY_SHELL_NUM
echo $MY_SHELL_NUM
(2)执行 make 命令,在执行 make clean 命令,shell语句的结果输出在终端。
分别输出 PWD ,HOME,HOSTNAME,MY_SHELL_NUM这四个变量的结果

3.3.5预定义变量

objectivec 复制代码
$@ 目标名
$< 依赖文件列表中的第一个文件
$^ 依赖文件列表中除去重复文件的部分
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

objectivec 复制代码
#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

objectivec 复制代码
#include "head.h"

int sub(int a, int b)
{

	return a - b;
}

sum.c

objectivec 复制代码
#include "head.h"

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

head.h

objectivec 复制代码
#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>

int sum(int a, int b);
int sub(int a, int b); 

#endif

Makefile

objectivec 复制代码
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

objectivec 复制代码
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最基础、自定义变量、预定义变量对应关系。

每一行为几种方法相同结果,不同格式的变量表达式。

相关推荐
虾..39 分钟前
Linux 软硬链接和动静态库
linux·运维·服务器
Evan芙1 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
晨晖22 小时前
单链表逆转,c语言
c语言·数据结构·算法
hkhkhkhkh1233 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen4 小时前
Linux字符串处理
linux·string
张童瑶4 小时前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功1234 小时前
什么是SELinux
linux
石小千4 小时前
Linux安装OpenProject
linux·运维
柏木乃一4 小时前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-30904 小时前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu