Markfile介绍及使用
make工具
当源码文件比较多的时候,不是适合直接输入gcc命令来编译,这时候就需要一个自动化的编译工具。make工具通过Makefile的文件来完成并自动维护编译。
当我们有多个源文件的是时候,我们只用GCC的话就会比较麻烦如:
gcc main.c input.c output.c -o main
那么这样的话生成的可执行文件,是可以运行的,但是如果我们有几千个源文件的话,工作量就非常大。并且,每次使用gcc进行编译,所有源代码都会重新编译,若我们文件较大,那么我们就每次修改都需要等待非常长的时间。
而make就解决了这个文件,综上Makefile可以满足一下几个需求:
-
如果工程没有编译过,那么工程中的所有.c文件都要被编译并且链接成可执行程序。
-
如果工程中只有个别C文件被修改,那么只编译这些被修改的C文件即可。
-
如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的C文件,并链接成可执行文件。
创建Makefile
在工程目录下创建Makefile的文件,文件名一定是Makefile。Makefile编写中所有的首行缩进都是用TAB。我们在新创建的Makefile中编写命令,如果我们需要运行Make的时候,可直接使用“make”命令编译工程。
出错原因:我们编写的Makefile可能会出错一般有两种原因:
-
Makefile中命令缩进没有使用TAB键
-
VI/VIM编译器使用空格代替了TAB键
Makefile语法
Makefile规则格式
Makefile里面是由一系列的规则组成的,这些规则格式如下:
目标```: 依赖文件集合```
命令 1
命令 2
`````
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
make命令会为Makefile中的每个以TAB开始的命令创建一个shell进程去执行。
拿出正点原子的官方给的示例来分析一下(我这里无法用TAB缩进我就用空格先代替)
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
根据上面所述,这个命令一共包括五条规则,1-2为第一条、3-4为第二条、5-6为第三条、7-8为第四条、10-12为第五条。make命令在执行上面Makefile的时候其执行步骤如下:
如果你觉得自己理解了,就跳过下面这段长长的我复制来的分析。
首先更新第一条规则中的 main,第一条规则的目标成为默认目标,只要默认目标更新了那么就认为 Makefile 的工作。在第一次编译的时候由于 main 还不存在,因此第一条规则会执行,第一条规则依赖于文件 main.o、input.o 和 calcu.o 这个三个.o 文件,这三个.o 文件目前还都没有,因此必须先更新这三个文件。make 会查找以这三个.o 文件为目标的规则并执行。以 main.o为例,发现更新 main.o 的是第二条规则,因此会执行第二条规则,第二条规则里面的命令为“gcc–c main.c”,这行命令很熟悉了吧,就是不链接编译 main.c,生成 main.o,其它两个.o 文件同理。最后一个规则目标是 clean,它没有依赖文件,因此会默认为依赖文件都是最新的,所以其对应的命令不会执行,当我们想要执行 clean 的话可以直接使用命令“make clean”,执行以后就会删除当前目录下所有的.o 文件以及 main,因此 clean 的功能就是完成工程的清理,“make clean”的执行过程。
总结一下就额是:
-
make命令会在当前目录下查找以Makefile命名的文件
-
当找到Makefile文件以后就会按照Makefile中定义的规则来编译生成最终的目标文件
-
当发现目标文件不存在,或者目标文件所依赖的文件比目标文件新的话就会执行后面的命令来更新目标
这就是make的执行过程,make工具就是在Makefile中一层层的查找依赖关系,并执行相应的命令。编译出最终的可执行文件。
Makefile变量
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
上述命令中,我们同一个.o文件出现了两次,如果我们的Makefile文件比较复杂的时候重复输入的工作就会非常浪费时间,并且容易输错,为了解决这个问题,Makefile加入了变量支持。
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
第一行我们定义了一个变量objects,并且给这个变量进行了赋值,其值为字符串“main**.o input.o calcu.o”;第三和第四行使用到了变量objects,Makefile中变量的引用方法是“$(变量名)”**。
包括三中赋值方式“=”、“:=”、“”
-
“=”的值取决于=右边所引用的变量的最后一次的有效值
-
“:=”的值取决于引用变量之前的最后一次的有效值
-
“?=” 如果变量没有被赋值,那么此变量就是右边引用的变量;如果已经赋值就使用当前值
-
“+=“在原来的基础上增加
Makefile模式规则
模式规则用处:当多个类似处理的规则时,重复的使用会增加工作量,所以引用模式规则,通过模式规则我们就可以使用一条规则来将所有的.c文件编译为对应的.o文件。
模式规则中,至少在规则的目标定定义中要包含”%“,否则就是一般规则,目标中的”%“表示对文件名的匹配,”%”表示长度任意的非空字符串,例如“%.c”表示所有以.c结尾的文件。
Makefile自动化变量
如果通过一行命令来从不同的依赖文件中生成对应的目标呢?自动变量就可以解决这个问题。
自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个去除,直至所有的符合模式的文件都去玩,自动化变量只应该出现在规则的命令中。常用的三种:<和$^【Makefile中3个常用自动化变量示例】
Makefile条件判断
C语言中我们通过条件判断语句来根据不同的情况来执行不通过的分支,Makefile也一样支持条件判断。
格式:
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字有四个,ifeq、ifneq、ifdef、ifndef,比较熟悉的能猜到,相同、不同、非空、空。
Makefile函数调用
Makefile同样支持函数,Makefile中的函数是已经定义好的,我们直接使用,不支持我们用户自定义函数。
函数的使用方式:
$(函数名 参数集合)
${函数名 参数集合}
可以看出,调用函数和调用普通变量一样,使用符合“$”来标识。参数之间用“,”隔开。
subst函数
subst用于字符串替换,调用方式:
$(subst <form>,<to>,<text>)
将
相关文章
迈进Makefile的世界(入门)
简介 Linux的`make`程序用来自动话编译大型源码,实现只需要一个`make`执行就可以全自动完成。 `make`能自动化完成,是因为项目路径下提供了一个`Makefile`文件,由该文件负责告诉`make`,应该去编译和链接该项目程序。 `make`起初只针对C语言开发,但它实际应用并不限定C语言,而是执行Linux命令去应用到任意项目,甚至不是编程语言。 >此外`make`...
线程池
线程池的原理 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发得线程数量很多,并且每个线程都是执行一个时间很短得任务结束了,这样频繁得创建线程会降低系统的效率,因为频繁创建线程和销毁线程需要时间。 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都可以默认得堆栈大小,以默认优先级运...
线程同步
线程同步的概念 多个线程对内存中的共享资源访问时,让线程进行线性的方式,有顺序的访问。线程对内存的这种访问方式就是线程同步。 下面是一个两个线程同时对变量num,进行加1的操作的demo,但是最终结果与预想结果,有很大差异。下面我们将分析并解决线程同步的问题。 ``` #include <pthread.h> #include <stdio.h> #include <unistd.h> #...