一、Makefile的概述
1.认识make
- make 是一个命令,是个可执行程序,用来解析 Makefile 文件的命令;
- linux 环境下,这个命令存放在 /usr/bin/ 目录下;
- 当用户输入 make 指令时,系统会自动寻找
makefile、Makefile、GNUmakefile
中任何一个,根据该文件中的指令编译工程。
2.什么是makefile
- makefile 是一个编译指令的脚本,里面记录了一条条编译指令,用于描述程序的编译规则;
- Makefile 文件里面的编译指令是根据我们自己写的程序,编写的编译规则。
3.makeflie与gcc的对比
-
用 gcc 编译的时候,我们要在后面跟上要编译的文件名,如:
gcc main.c func.c
文件量和代码量较少的时候,用这种方式编译还比较方便,但如果整体项目很多,文件很多的时候,编译起来就比较困难,而且还容易漏掉一些文件。没人能保证自己的代码一次运行成功,会反复编译,调试,那每次调试都需要输入很长的 gcc 命令。遇到后期追加功能的时候,时间长了,也忘记项目用到了哪些文件了,对后期工作也会造成困扰;
-
而在 makeflie 里面提前写好了编译指令,只是在编写 makefile 文件的时候需要花费时间,但后面重复编译每次只需要 make 指令调用编译就行了,简化了编译过程。同时后期即使追加功能,以前的编译的文件指令都保存在 makefile 文件里了,也不用担心忘记需要编译哪些文件;
-
gcc 编译很大项目的时候,编译时间会很长,如果对代码进行了修改再编译,即使没有修改代码的文件,也要一起重新编译一次,又得消耗很长的时间;
-
makefile 只会对修改过的代码文件重新编译,其它未修改的直接使用以前编译好的可执行文件,除了第一次编译需要花费较长时间外,后面编译都比较快。因此,make 不仅简化了编译步骤,还节省编译时间,提高编译效率。
二、makefile的语法规则
1.makefile语法规则
1.1语法
先创建一个 makefile 文件,在文件里面写命令:
目标:依赖文件列表
命令列表 // 命令列表前有缩进
- gcc 编译
gcc main.c -o main
- 目标:通常是要产生的可执行文件名,如上面的 main;
- 依赖文件:是用来输入从而产生目标的文件,一个目标通常有一个或多个依赖文件,如上面的 main.c;
- 命令:make 执行的动作,一个规则可以含几个命令,有多个命令时,每个命令占一行,如上面的
gcc main.c -o main
。
- 注意: makefile 文件里面写的是脚本,要严格遵守脚本的语法规则,有时候多一个少一个空格都可能造成错误。
1.2makefile编译演示
先创建 makefile 文件,在文件里写入如下命令:
main:main.c func.c
gcc main.c func.c -o main
接着在 linux 终端输入make
命令即可实现编译。
- 注意:上面只是演示 makefile 命令的语法,和真正的 makefile 实现的功能差远了。这里的 make 只会执行第一个目标的语句,如果下方还有其它语句不会执行。
1.3make命令格式
1.3.1自定义 makefile 文件名
make -f 自定义文件名
- 在终端输入 make 命令时默认在工作目录中寻找名为 GNUmakefile、makefile、Makefile 的文件作为 makefile 输入文件,但如果我们不按照上面的文件名命名,而是修改为自定义的文件名,那么就需要在 make 命令后面加上我们自定义的文件名,如:
make -f my_makefile
但一般不建议这样做。
1.3.2make后跟其它目标
前面说到,make 执行第一个目标的语句后,后面目标的语句就不会执行了,那要执行后面目标的语句,我们可以指定目标:
make 目标
- 例如:makefile
main:main.c func.c
gcc main.c func.c -o main
clean:
rm main.c
可以通过输入:终端输入make clean
,来执行指定的语句。
1.3.3复杂版makefile
main:main.o fun.o
gcc main.o fun.o -o main
main.o:main.c
gcc -c main.c -o main.o
fun.o:fun.c
gcc -c fun.c -o fun.o
clean:
rm main *.o
- 说明:
- 当终端输入 make 命令时,会执行 makefile 文件里的第一条命令,但发现依赖的
main.o fun.o
文件不存在,会执行下面的命令,先生成main.o fun.o
再执行第一条的命令; *.o
里面的 * 是通配符,这里表示所有以.o
结尾的文件;clean:
为假想目标,只有目标,没有依赖。
- 当终端输入 make 命令时,会执行 makefile 文件里的第一条命令,但发现依赖的
三、makefile的变量
makefile 变量类似于 C 语言中的宏,当 makefile 被 make 工具解析时,其中的变量会被展开。变量一般用于:保存文件名列表、保存文件目录列表、保存编译器名、保存编译参数、保存编译的输出等。
1.自定义变量
- 定义格式
变量名=变量值
-
说明
- 注意,等号两边没有空格,应该严格遵循脚本语言的语法编写;
- makefile 变量名可以以数字开头,区分大小写;
- 变量一般都在 makefile 的头部定义,几乎可在 makefile 的任何地方使用;
- 如果需要读取变量的值,需要在变量名前加上美元符号 , , ,(变量名)或${变量名};
- 自定义变量的作用,主要是为了方便切换不同编译方式,方便指定生成的可执行文件名等,如果一个字符在命令中出现多次,就可以通过变量来代替,如:
CC=gcc EXEC=main $(EXEC):main.o fun.o $(CC) main.o fun.o -o $(EXEC) main.o:main.c $(CC) -c main.c -o main.o fun.o:fun.c $(CC) -c fun.c -o fun.o clean: rm $(EXEC) *.o
2.系统环境变量
make 工具会拷贝系统的环境变量并将其设置为 makefile 的变量,在 makefile 中可直接读取或修改拷贝后的变量,读取环境变量的方法和前面读取自定义变量的方法相同,如:
CC=gcc
EXEC=main
$(EXEC):main.o fun.o
$(CC) main.o fun.o -o $(EXEC)
main.o:main.c
$(CC) -c main.c -o main.o
fun.o:fun.c
$(CC) -c fun.c -o fun.o
clean:
rm $(EXEC) *.o
echo $(PWD) // PWD 是一个环境变量
- 说明:
- echo 相当于C语言里的 printf,将内容输出到终端;
- 我们除了可以使用系统的环境变量,还可以自己导出环境变量:
export NUM=100
; - 自己导出的环境变量只在当前终端有效,不会影响系统的环境变量。
3.预定义环境变量
预定义环境变量即 makefile 定义好的环境变量。
- $@ 当前命令的目标名
- $< 当前命令依赖文件列表中的第一个文件
- $^ 当前命令依赖文件列表,带有除去重复文件的功能
- AR 归档维护程序的程序名,默认值为 ar
- ARFLAGS 归档维护程序的选项
- AS 汇编程序的名称,默认值为 as
- ASFLAGS 汇编程序的选项
- CC C 编译器的名称,默认值为 cc
- CFLAGS C 编译器的选项
- CPP C 预编译器的名称,默认值为$(CC) -E
- CPPFLAGS C 预编译的选项
- CXX C++编译器的名称,默认值为 g++
- CXXFLAGS C++编译器的选项
较常用的是前三个,对上面命令的升级版:
CC=gcc
EXEC=main
$(EXEC):main.o fun.o
$(CC) $^ -o $@
main.o:main.c
$(CC) -c $< -o $@
fun.o:fun.c
$(CC) -c $< -o $@
clean:
rm $(EXEC) *.o
echo $(PWD)
上面的代码可以发现,7、8行代码重复,因此可以合并,使用通配符 %:
CC=gcc
EXEC=main
OBJ=main.o fun.o // 将依赖文件通过自定义变量保存
$(EXEC):$(OBJ)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $< -o $@
clean:
rm $(EXEC) $(OBJ)
echo $(PWD)
标签:15,CC,make,makefile,编译,fun,main
From: https://blog.csdn.net/qq_63958145/article/details/144728561