目录
一、概念
二、使用实例
三、原理
四、进度条程序
1、缓冲区问题
1、概念
2、\r和\n
2、代码编写
一、概念
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一条命令,是一个解释makefile中指令的命令工具,makefile是一个文件,两个搭配使用,完成项目自动化构建。
二、使用实例
首先,我们创建两个文件:Makefile和test.c。
我们先在源文件test.c中简单写一段代码。
然后我们再编写Makefile:第二行和第六行必须以tab开头。
接着我们使用make命令,发现生成了可执行程序。
最后我们运行可执行程序:
我们发现程序成功执行了。以上就是make/makefile(m可以大写)的简单使用。
三、原理
要想弄清楚原理,首先我们必须要知道两个概念:依赖关系和依赖方法。
如何编写makefile:
1、建立依赖关系,谁依赖于谁(比如上面的例子,mytest依赖于test.c,因为test.c是我们自己创建出来的,mytest是通过test.c编译出来的)。
2、新起一行,必须以tab键开头,建立依赖方法,即两者的依赖关系是通过什么方法建立起来的(比如上面的例子,mytest依赖于test.c的关系是通过tes.c编译而形成的)。
3、清理:清理文件/临时数据
使用make clean后,可执行程序就会被清理掉,需要重新make。相当于vs中的重新生成解决方案。
像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
基本原理:
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会从上到下按顺序找文件中的第一个目标文件,在上面的例子中,他会找到“mytest”这个文件,并把这个文件作为最终的目标文件。
3、如果mytest文件不存在,或是mytes所依赖的后面的test.c文件的文件修改时间要比mytest这个文件新,那么,他就会执行后面所定义的命令来生成mytest这个文件。
4、如果mytest所依赖的test.c文件不存在,那么make会在当前文件中找目标为test.c文件的依赖性,如果找到则再根据那一个规则生成test.c文件。
5、make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
注:在make推导的时候会根据依赖关系而推导,从上到下,当依赖文件列表不存在会继续根据依赖文件列表所对应的项而继续。
4、伪目标
这里的.PHONY:被该关键字修饰的对象是一个伪目标。伪目标表示该目标总是被执行的。比如:上面的clean,只要你一直输入命令,它就会一直执行。
而非伪目标,并不能总是执行成功,比如:上面的例子,一旦你make好了,即生成了mytest后,除非你修改了test.c,不然你是无法再重新make的。
四、进度条程序
接下来,我们就用上面学到的内容来写一个简单的进度条程序。
1、缓冲区问题
1、概念
首先,我们来看一看下面的代码:
运行结果就是先输出字符串hello world然后休眠3秒之后结束运行。那么对于以下代码呢?
上述代码的结果就是:我们看到程序先休眠了3秒,然后打印字符串hello之后结束运行。
这是为什么呢?上面的两个代码,唯一的区别就是一个有 “\n”,一个没有。而且,我们知道,程序一定是从上到下依次执行的,那为什么第二个代码我们看到的是先休眠呢?这就和缓冲区有关了。
其实,第六行的代码早就执行完了,只是信息没有被立马显示出来。
理由是:显示器对应的是行刷新,即当缓冲区当中遇到“\n”或是缓冲区被写满才会被打印出来,而在第二份代码当中并没有“\n”,所以字符串hello先被写到缓冲区当中去了,然后休眠3秒,直到程序运行结束时才将hello打印到显示器当中。
那如果我们不加\n,有没有什么方法能够帮助我们解决这个问题呢?这里我们可以使用fflush函数,该函数可以刷新缓冲区,即将缓冲区当中的数据刷新当显示器当中。
这下我们看到的结果就是先打印hello,再休眠了。
2、\r和\n
\r: 回车,使光标回到本行的起始位置。
\n: 换行,使光标移动到当前位置的正下方的位置。
注:我们键盘中的回车按键相当于两者的结合。而在语法中,\n就是两者的结合。
2、代码编写
* 倒计时程序
有了上面 \r 回车的概念,那么如果我们向显示器上写了一个数之后再让光标回到本行的起始位置,然后再写一个数,不就相当于将前面一个数字覆盖了吗?然后我们使用循环,不就可以实现连续覆盖了吗,这就相当于一个倒计时程序。如下:
运行结果:
有了倒计时代码,我们就可以写进度条代码:
运行结果如下:
注:%-100s:表示预留100的空间,-表示从左到右进行打印。如果不加-,将会从右向左打印。%%表示百分号。