最近,闲的没事干,想写一个C语言扫雷。看了一篇博客,用到了多文件编程。我之前也没有了解过makefile文件,就打算深入了解一下。结果一学习,就学习了一天。到现在,都还没有开始写扫雷。(逃
网上关于makefile文件的介绍都很长,我这里主要是把一些大佬的博客整合一下,我感觉这样才能让我更好的理解。
=============================================================================
一.GCC相关命令介绍
一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link).
也就是源文件(.c 文件或者.cpp文件)首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error)。
Gcc编译器在编译一个C语言程序时可以继续细分,细分成4个步骤
1.将C语言源程序预处理,生成.i文件。
2.预处理后的.i文件编译成为汇编语言,生成.s文件。
3.将汇编语言文件经过汇编,生成目标文件.o文件。
4.将各个模块的.o文件链接起来生成一个可执行程序文件。
在写makefile文件之前,我们一定要了解一下gcc相关命令格式
(1).gcc -c
c选项表示编译、汇编指定的源文件(也就是编译源文件),但是不进行链接。使用-c选项可以将每一个源文件编译成对应的目标文件。
gcc -c main.c
编译器编译main.c生成中间文件main.o
(2)gcc -o
gcc [infile] -o [outfile]
[infile] 表示输入文件(也即要处理的文件),它可以是源文件,也可以是汇编文件或者是目标文件;
[outfile] 表示输出文件(也即处理的结果),它可以是预处理文件、目标文件、可执行文件等
-o主要是用于指定输出(out)文件名.
gcc -c main.c -o a.o
将源文件 main.c 编译为目标文件 a.o。如果不使用 -o 选项,那么将生成名为 main.o 的目标文件。
gcc -E main.c -o demo.i
//gcc -E是进行文件的预处理,主要加载头文件,宏替换,处理带”#”的句子
对源文件 main.c 进行预处理操作,并将结果放在 demo.i 文件中。如果不使用 -o 选项,那么将生成名为 main.i 的预处理文件。
(3)gcc
gcc 不带任何参数,可以把文件直接编译成可执行文件
gcc main.c -o main.exe
直接把main.c源文件编译成main.exe可执行文件(-o只是规定输出文件的名称)
gcc main.o -o main.exe
直接把main.o中间文件编译成main.exe可执行文件
其实,我觉得只要了解过了这三个命令就行了。其他的比如说预编译命令或者变成汇编语言的命令,我感觉用不到。如果你想要继续深入了解,可以访问这个GCC常用选项
二.编写一个makefile文件
make命令执行时,需要一个 Makefile文件,以告诉make命令需要怎么样的去编译和链接程序。首先,我们用一个示例来说明Makefile的书写规则。我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
1.如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2.如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3.如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。
edit : main.o AAA.o BBB.o CCC.o
gcc -o edit main.o AAA.o BBB.o CCC.o
main.o : main.c
gcc -c main.c
AAA.o : AAA.c AAA.h
gcc -c AAA.c
BBB.o : BBB.c BBB.h
gcc -c BBB.c
CCC.o : CCC.c CCC.h
gcc -c CCC.c
clean :
rm edit main.o AAA.o BBB.o CCC.o
我们把上面的代码保存在一个文件中,文件名可以叫makefile或Makefile。
从上面的实例中,我们可以看出,代码的主要结构为
target:prerequisites …
command(指令)
target也就是一个目标文件,可以是Object File,也可以是执行文件
prerequisites就是,要生成那个target所需要的文件。
command也就是make需要执行的命令。
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件.
上面的文件中,main.o依赖于main.c,AAA.o依赖于AAA.c和AAA.h,以此类推。依赖的关系实质就是目标文件是由哪些文件生成的,main.o是由main.c生成的,AAA.o是由AAA.c和AAA.h生成的。
Makefile文件中,命令的执行是看prerequisites中的文件是否比target更新,prerequisites中如果有一个的文件比target文件要新的话,command所定义的命令就会被执行。程序会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,那么,命令就会执行
比如我在AAA.h中添加了一个函数申明,AAA.c不动,这是只有AAA.h是变了的,AAA.c没变。我们首先比较AAA.o和AAA.c的更新日期,发现是一样的,没有问题。接着比较AAA.o和AAA.h的更新日期,发现AAA.h更新时间更晚。此时,满足命令的执行条件。我们就会执行gcc -c AAA.c这个命令。其实,这也很好理解,你头文件都变了,中间文件肯定要重新编译一下的。
我们执行make命令(不跟参数,就光光输入一个make),makefile文件默认执行第一行的语句,这里是
edit : main.o AAA.o BBB.o CCC.o
接下来程序会检查main.o AAA.o BBB.o CCC.o这四个文件是否更新过,如果有一个文件被更新过的话,edit下的程序段就会执行
gcc -o edit main.o AAA.o BBB.o CCC.o
我们如果只执行make命令(不跟参数,就光光输入一个make),那么就永远无法执行到clean那行代码。我们输入make clean,就可以执行clean的代码.这行代码是把生成的中间文件全部清除掉。
==============================================================================
我这个博客复制了好多别人博客上的段落,如果看不懂,可以去看看原博客
参考链接:https://www.cnblogs.com/aiguona/p/9162500.html
参考链接:http://c.biancheng.net/view/666.html