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

原内容地址链接

1.make

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

1.1 make 命令格式

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

2.Makefile 核心概念‌ ‌

作用‌:
 
自动化编译和链接程序,管理项目依赖关系,避免重复编译未修改的代码。
 
‌基本结构:
 
target: dependencies
    command
 
‌target‌: 生成的目标(如可执行文件、中间文件)
‌dependencies‌: 生成目标所需的文件或目标
‌command‌: 生成目标的命令(必须以 Tab 开头)

2.1创建并运行 Makefile步骤

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

3. Makefile编写

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 命令

将可执行文件main删除,Makefile复制一份,重命名为Makefile1,执行 make -f Makefile1
 
也可以正常执行make命令。执行结果与默认make命令结果相同。
 
 

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 变量概述

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 的任何地方使用
常用变量:
 
定义变量: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系统变量

make 工具会拷贝系统的环境变量并将其设置为 makefile 的变量,在 makefile 中可直接读取或修改拷贝后的变量。
程序:
main.c
 
#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)
 
运行结果:
(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预定义变量

$@       目标名
$<       依赖文件列表中的第一个文件
$^       依赖文件列表中除去重复文件的部分
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编译器与工具

3.3.5.2. 编译选项

3.3.5.3. 文件与目录

3.3.5.4. 隐式规则中的关键变量

Make 根据文件后缀自动推导编译规则,以下变量控制隐式规则行为:
 

3.3.5.5. 常用内置变量

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最基础、自定义变量、预定义变量对应关系。
 
每一行为几种方法相同结果,不同格式的变量表达式。


 

 
 
posted @ 2025-04-10 21:31  浅安的邂逅  阅读(392)  评论(0)    收藏  举报