make工具

1、什么是make?

make是个命令,是个可执行程序,是个工具,用来解析Makefile文件的命令,这个命令存放在/usr/bin/目录下

-rwxr-xr-x 1 root root 250K  2月 15  2022 make
-rwxr-xr-x 1 root root 4.8K  2月 15  2022 make-first-existing-target        //Perl脚本编写的程序会由make命令触发执行,用来检测文件是否被修改,没有修改跳过编译

Debian系安装make工具:sudo apt install make

2、什么是makefile?

Makefile是个文件,这个文件中描述了咱们程序的编译规则,咱们执行make命令的时候,make命令会在当前目录下寻找Makefile文件,根据Makefile文件里的规则,编译咱们的程序。

        注意Makefile文件是咱们程序员根据自己的程序,编写的编译规则文件。

3、make的主要好处

一、大量代码的关系维护,大项目中源代码比较多,手工维护、编译时间比较长而且编译命令比较复杂,难以记忆和维护,把代码维护命令和编译命令写在Makefile文件中,然后再用make工具解析编好规则的Makefile文件,自动执行相应命令,可实现代码的合理编译。

二、减少重复编译时间,在改动其中一个文件的时候,能判断哪些文件被修改过,可以只对该文件进行重新编译,然后重新链接所有的目标文件,节省编译时间。

4、一张图解释:make和:Makefile关系

5、Makefile的编写语法规则

 目标:依赖文件列表

        命令列表

1、目标:通常是要产生的文件名称,目标可以是可执行文件或其他object文件,也可是一个动作的名称

2、依赖文件列表:由多个依赖文件组成,每个依赖文件是用来输入而产生目标的文件,一个目标通常有几个依赖文件(也可以没有)

3、命令列表:由多个命令组成(也可以没有),代表make执行的动作,注意一个规则可以包含多个命令,存在多个命令时,每个命令占一行

举例:将gcc -o hello main.c hello.c hi.c good.c编写成Makefile内容

Makefile文件内容:

main:main.c hello.c hi.c good.c

        gcc -o main main.c hello.c hi.c good.c

clean:

        rm main

5.1、Makefile变量
5.1.1、Makefile变量

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

Makefile变量分为三种:系统环境变量、自定义变量、预定义变量

系统环境变量:make工具解析Makefile前,读取系统环境变量并设置为Makefile的变量

自定义变量:在Makefile文件中定义的变量,make工具传给Makefile的变量都是自定义变量

预定义变量:自动变量,都是设置好的变量(可以理解为规则)

5.1.2、Makefile变量编写规则

变量名=变量值        引用变量:${变量名}       

注意:

        1、注意Makefile的变量名字允许以数字开头

        2、变量区分大小写

        3、变量通常在Makefile文件的头部定义

        4、变量可在Makefile的任何地方使用

5.1.3、预定义变量

Makefile中我们通常只需要定义自定义变量和重新定义系统环境变量,而不需要定义预定义变量。

预定义变量通常是通用的,像正则表达式的元字符,具有特殊的含义。

$@        # 目标名

$<        # 依赖文件列表的第一个文件

$^        # 依赖文件列表中去除重复文件的部分

%        # 通配符

AR        # 归档维护程序的程序名,默认值为ar

ARFLAGS        # 归档维护程序的选项

AS        # 汇编程序的程序名,默认值为as

ASFLAGS        # 汇编程序的选项

CC        # C编译器的名称,默认为cc

CFLAGS        # C编译器的选项

CPP        # C预编译器的名称,默认值为$(CC) -E

CPPFLAGS        # C预编译器的选项

CXX        # C++编译器的名称,默认为g++

CXXFLAGS        # c++编译器的选项

6、make命令格式

make [-f file] [targets] [target] ...

1、通常我们把Makefile文件编写好规则,直接敲make,make默认从工作目录中寻找名为GNUmakefile或makefile或Makefile的文件内容的第一个目标(也有人称规则)进行解析编译。而 -f选项可以指定以上名字以外的文件作为Makefile输入文件。

2、[target]:若使用make命令时没有指定目标,则make工具默认会实现Makefile文件内的第一个目标,然后退出。若指定了目标,目标可以是一个或多个,多个目标之间默认用空格隔开。

7、makefile案例

源代码目录结构

.
├── main.c
├── Makefile
├── myfunc.c
└── myfunc.h

0 directories, 4 files

其中除Makefile以外的文件,我写在上一章csdn博文,参考gcc的编译C语言的过程-CSDN博客

7.1、简单级别

touch创建Makefile文件,写入如下内容

Makefile

my_execfile:main.o myfunc.o
        gcc -o my_execfile main.o myfunc.o
main.o:main.s
        gcc -c main.s -o main.o
my_func.o:myfunc.s
        gcc -c myfunc.s -o myfunc.o
main.s:main.i
        gcc -S main.i -o main.s
my_func.s:myfunc.i
        gcc -S myfunc.i -o myfunc.s
main.i:main.c
        gcc -E main.c -o main.i
myfunc.i:myfunc.c
        gcc -E myfunc.c -o myfunc.i
clean:
        rm my_execfile *.i *.s *.o

这里我把上一章的预处理、编译、汇编、链接的产物和过程集中写在Makefile文件中,并使用clean命令规则清理临时产物包括最终的可执行文件my_execfile。通过简单的把以上步骤汇总在Makefile文件中,只需要敲make就可以输出所有临时产物包括可执行文件,敲make clean可以清理所有中间产物和可执行文件,这对于代码维护很方便,不仅简洁美观,编译也省时。

效果

输出所有中间产物:*.i *.s *.o和可执行文件my_execfile

清理所有产物

7.2、普通级别

 Makefile

  1 #自定义变量
  2 EXEC=my_execfile        #我们的最终想要的可执行文件
  3 CC=gcc  #这里对gcc编译器也定义变量,是因为Makefile可以处理多种编译器的规则
  4 OBJ=main.o myfunc.o     #我们的目标文件
  5 OBJ1=main.o
  6 OBJ2=myfunc.o
  7 OBJ3=main.s
  8 OBJ4=myfunc.s
  9 OBJ5=main.i
 10 OBJ6=myfunc.i
 11 SOUR=main.c
 12 SOUR1=myfunc.c
 13 FLAGS=-Wall     # 这里输出gcc编译的所有warning和error
 14
 15 $(EXEC):$(OBJ)
 16         $(CC) -o $(EXEC) $(OBJ)
 17 $(OBJ1):$(OBJ3)
 18         $(CC) -c $(OBJ3) -o $(OBJ1) $(FLAGS)
 19 $(OBJ2):$(OBJ4)
 20         $(CC) -c $(OBJ4) -o $(OBJ2) $(FLAGS)
 21 $(OBJ3):$(OBJ5)
 22         $(CC) -S $(OBJ5) -o $(OBJ3) $(FLAGS)
 23 $(OBJ4):$(OBJ6)
 24         $(CC) -S $(OBJ6) -o $(OBJ4) $(FLAGS)
 25 $(OBJ5):$(SOUR)
 26         $(CC) -E $(SOUR) -o $(OBJ5) $(FLAGS)
 27 $(OBJ6):$(SOUR1)
 28         $(CC) -E $(SOUR1) -o $(OBJ6) $(FLAGS)
 29 clean:
 30         rm $(EXEC) $(OBJ5) $(OBJ6) $(OBJ3) $(OBJ4) $(OBJ)

        相对于简单处理编写Makefile文件的工作,这里我把部分编译命令通过变量的形式替换,只需要修改2~12行的数据名称,gcc的四个编译过程就可以被执行输出。clean命令进一步的缩小删除范围,可以精准到具体要删除的文件,防止其他非该Makefile的输出产物被删除。

效果

输出所有产物

清理所有产物

 7.3、升级

Makefile

# 自定义变量
EXEC=my_execfile       # 最终的可执行文件名
OBJ=main.o myfunc.o    # 目标文件
CC=gcc                 # 编译器
FLAGS=-Wall            # 编译选项,输出所有警告和错误信息

# 生成最终可执行文件
$(EXEC): $(OBJ)
        $(CC) -o $@ $^ $(FLAGS)

# 从汇编文件生成目标文件
%.o: %.s
        $(CC) -c $< -o $@ $(FLAGS)

# 从汇编文件生成汇编代码文件
%.s: %.i
        $(CC) -S $< -o $@ $(FLAGS)

# 从预处理文件生成汇编文件
%.i: %.c
        $(CC) -E $< -o $@ $(FLAGS)

# 清理生成的文件
clean:
        rm -f $(EXEC) $(OBJ) $(OBJ:.o=.s) $(OBJ:.o=.i)

# 生成所有中间文件的伪目标
all: $(OBJ:.o=.s) $(OBJ:.o=.i)

# 默认的伪目标
.PHONY: all clean

使用预定义变量和自定义变量结合,并加额外的伪目标以生成所有的中间产物和清理所有的中间产物,使用变量替换技巧将$(OBJ)的.o替换为其他中间产物,并使用.PHONY声明all和clean为伪目标,防止出现同名文件而产生歧义。

效果

输出所有产物

 清理所有产物

8、小结

实际上,中间产物并不是我们最终需要的目标文件,我们需要可执行文件文件就可以了。希望以上步骤对于了解make的编译原理有所帮助。

# 自定义变量
EXEC=my_execfile       # 最终的可执行文件名
OBJ=main.c myfunc.c    # 目标文件
CC=gcc                 # 编译器
FLAGS=-Wall            # 编译选项,输出所有警告和错误信息

# 生成最终可执行文件
$(EXEC): $(OBJ)
        $(CC) -o $@ $^ $(FLAGS)

# 清理生成的文件
clean:
        rm $(EXEC)
# 默认的伪目标
.PHONY: clean

效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值