背景
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力.
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作.
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
依赖关系和依赖方法
在使用make/Makefile前我们首先应该理解各个文件之间的依赖关系以及它们之间的依赖方法。
依赖关系: 文件A的改变会影响到文件B,那么就称文件B依赖于文件A。
例如,test.o文件是由test.c文件通过预处理、编译以及汇编之后生成的文件,所以test.c文件的改变会影响test.o,所以说test.o文件依赖于test.c文件。
依赖方法: 如果文件B依赖于文件A,那么通过文件A得到文件B的方法,就是文件B依赖于文件A的依赖方法。
例如,test.o依赖于test.c,而test.c通过gcc -c test.c -o test.o得到test.o那么test.o依赖于test.c的依赖方法就是gcc -c test.c -o test.o。
多工程文件编译执行
当你的工程当中有多个源文件的时候,应该如何进行编译生成可执行程序呢?
第一种方法我们直接用gcc指令对多个源文件进行编译,生成可执行文件。
但是进行多文件编译的时候一般不使用源文件直接编译,而是将他变成二进制文件,再将这些二进制文件链接生成可执行文件
若是直接使用源文件生成可执行程序,那么其中一个源文件进行了修改,再生成可执行程序的时候就需要将所以的源文件重新进行编译链接。而若是先用每个源文件各自生成自己的二进制文件,那么其中一个源文件进行了修改,就只需重新编译生成该源文件的二进制文件,然后再将这些二进制文件通过链接生成可执行程序即可。
Makefile文件的简写方式:
$@:表示依赖关系中的目标文件(冒号左侧)。
$^:表示依赖关系中的依赖文件列表(冒号右侧全部)。
$<:表示依赖关系中的第一个依赖文件(冒号右侧第一个)。
上面的程序可以改成这样的简便方式。
注意: gcc/g++携带-c选项时,若不指定输出文件的文件名,则默认输出文件名为xxx.o,所以这里也可以不用指定输出文件名。
项目清理
我们每次重新生成可执行程序之前,要保证没有同命名文件在同一个目录下,要将上一次的清理干净,这里为了方便我们就需要执行较为方便的执行指令。
注意: 一般将这种clean的目标文件设置为伪目标,用.PHONY修饰,伪目标的特性是:总是被执行。
Linux的小程序 - 进度条
行缓冲区的概念
#include <stdio.h>
int main()
{
printf("hello Makefile!\n");
sleep(3);
return 0;
}
这是一个非常简单的c语言代码,这里我们看到的现象是先把printf里面的内容打印出来休息三秒之后程序停止。
那如果是这样呢?
#include <stdio.h>
int main()
{
printf("hello Makefile!");
sleep(3);
return 0;
}
这里我们会看到运行的时候,不会第一时间打印出来,会等三秒钟,那么这意味着sleep函数先执行了吗?
其实不是,显示器对应的是行刷新,即当缓冲区当中遇到’\n’或是缓冲区被写满才会被打印出来,而在第二份代码当中并没有’\n’,所以字符串hello world先被写到缓冲区当中去了,然后休眠3秒后,直到程序运行结束时才将hello world打印到显示器当中。
\r和\n
\r: 回车,使光标回到本行行首。
\n: 换行,使光标下移一格。
既然是\r是使光标回到本行行首,那么如果我们向显示器上写了一个数之后再让光标回到本行行首,然后再写一个数,不就相当于推进了下一个字符的往后延申,像进度条一样。
为了解决不用\n’进行换行将缓冲区当中数据打印出来这个问题
这里我们可以使用fflush函数,该函数可以刷新缓冲区,即将缓冲区当中的数据刷新当显示器当中。
#include <unistd.h>
#include <string.h>
#include<unistd.h>
int main()
{
int i = 0;
char bar[102];
memset(bar, 0 ,sizeof(bar));
const char *lable="|/-\\";
while(i <= 100 ){
printf("[%-100s][%d%%][%c]\r", bar, i, lable[i%4]);
fflush(stdout);
bar[i++] = '#';
usleep(10000);
}
printf("\n");
return 0;
}