前言:
本章主要内容有认识与学习Linux
环境下如何使用项目自动化构建工具——make/makefile
。
当我们编写一个较大的软件项目时,通常需要将多个源文件编译成可执行程序或库文件。为了简化这个过程,我们可以使用 make
工具和 Makefile
文件。Makefile
文件可以帮助我们自动化构建和管理软件项目,从而提高效率和可靠性。它还可以跨平台使用,因为 make
工具可以在各种不同的操作系统和编译器上运行。
Makefile
文件包含了一系列规则,每个规则描述了如何从源文件生成目标文件。在每个规则中,我们定义了目标文件和其依赖关系,并且指定了需要执行的命令。
示例:
创建一个新文件 Makefile
:
touch Makefile
编辑 Makefile
文件:
//vim进行编辑
vim Makefile
//写入内容
Test : Test.c
gcc Test.c -o Test
//保存退出
这样就写好了一个Makefile
文件 了,那么这样写有什么含义呢?
其实每个 Makefile
文件存在的意义就是生成一个最终目标文件,而 Makefile
文件里最开始的文件就被认定为是最终目标文件(示例中的Test
文件)。
示例中,要想生成目标文件 Test
,我们需要通过 Test.c
文件经过编译后生成目标文件 Test
。所以Test.c
与 Test
产生了依赖关系,用 :
表示。而接下来的 gcc Test.c -o Test
这条指令就是解释目标文件 Test
需要和 test.c
产生怎样的关系。
当然依赖关系有时候也可以不存在。因为 make
的目的是产生目标文件,不用管通过什么手段,也不管有没有目标文件,例如:
//没有依赖关系的示例
Test :
touch Test
有的时候,一个依赖关系可能不足以生成最终目标文件,此时我们还需建立多层依赖关系,例如:
Test : test.o
gcc test.o -o Test
test.o : test.s
gcc -c test.s -o test.o
test.s : test.i
gcc -S test.i -o test.s
test.i : Test.c
gcc -E Test.c -o test.i
为了生成最终的目标文件Test
,系统会根据依赖关系一层一层的寻找下去。如上例,要生成Test
,就得找到 test.o
,要生成 test.o
就要生成 test.s
…,在这样一层一层的寻找的时候,如果有哪个过程中出现了断层(生成目标文件失败),则会出现报错。
上个示例结果如下,make
指令执行 Makefile
后,不仅最终目标文件生成了,过程中的目标文件也都会生成:
make
是一条指令,它与Makefile
相伴相生。
当我们执行 make
指令时,make
工具会读取 Makefile
文件,并根据其中的规则来生成目标文件。它会检查每个规则中的依赖关系和目标文件的最新修改时间,从而决定哪些规则需要执行。
通俗讲就是,系统为了效率,并不会对已经生成的目标文件或未曾改动的目标文件再作复杂的编译并重新生成。
它会检查源文件与可执行文件最近修改时间的新旧,判断是否进行编译。
当我们只输入 make
指令时,它会默认最终目标文件。倘若我们只是想生成过程中的某一个目标文件,则需要指定该文件名。例如:只需生成 test.o
即可:
Test : test.o
gcc test.o -o Test
test.o : test.s
gcc -c test.s -o test.o
test.s : test.i
gcc -S test.i -o test.s
test.i : Test.c
gcc -E Test.c -o test.i
make test.o
在 Makefile
中,一般还会加入一个目标文件 clean
且用 .PHONY
修饰 ,其作用是清理生成项目文件。例如:
Test : test.o
gcc test.o -o Test
test.o : test.s
gcc -c test.s -o test.o
test.s : test.i
gcc -S test.i -o test.s
test.i : Test.c
gcc -E Test.c -o test.i
.PHONY : clean
clean :
rm -f Test test.i test.s test.o
被 .PHONY
修饰的目标文件意为 总是被执行的。例如,我们执行 make test.o
命令后,可以执行,但是第二次却不行了,因为该目标文件已经存在且为最新。但是被.PHONY
饰后可以一直被执行。
本文到此结束,码文不易,还请多多支持哦!