Makefile的编写
在实现Makefile的编写之前呢,我们先来了解一下程序的编译和链接
使用C、C++编写可执行程序,首先要把源文件编译成中间代码文件,Linux下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)
一个项目,拥有成百上千的源程序文件,编译链接这些源文件都是由规则的,Makefile闪亮登场!Makefile确定整个工程的编译规则,只需要一个make命令,就可以实现“自动化编译”。make是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。
现在再来了解一下Make的工作原理
通常在一个项目里,我们的规则是: 1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。 2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。 3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
首先我们先来看一下一般我们在Linux中都是会用gcc/g++来编译C/C++的程序,如以下情况
事先编写了几个测试用的代码用例 1.speak.h 2.speak.c 3.hellospeak.c
编写完之后呢,我们就可以用常规gcc进行编译了
编译如下 这样呢就生成了这个可执行文件了,运行后就成功打印出来了
但是像这种如果是简单的过程的话,这种编译放在一个文件里,那是可以的,如果是那种大工程,都放在一起编译的话,那么会非常的耗费时间,效率不高
那么我们要怎么做才能提高效率呢 首先我们先来简单的实现一些操作 执行效果是一样的 所以呢那些大牛们用弄了一个make的脚本,我们只需要用make这个命令就可以直接执行以上的步骤,但是要执行make命令呢,我们需要编写一个makefile的文本,(不过一般这个makefile我们都可以用cmake来生成,不用我们自己去编写,但是呢这里讲的是自己去编写makefile,所以呢cmake这个就不讲了)
只要我们的Makefile写得够好,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。
首先是Makefile的规则: target … : prerequisites … command … … 1.target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,就不细讲。 2.prerequisites就是,要生成那个target所需要的文件或是目标。 3.command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
当然,如果你还没有安装make,那么用的时候会显示这样的画面
我们只需要执行apt-get install make这个命令就好了(不过前提是你当前是root用户,也就是特权用户的情况下,如果不是的话要加上sudo apt-get install make然后在输入密码),这样就可以安装了。
首先为了示范,我先把刚刚生成的文件都删了 然后呢我们就可以编写makefile了,这里呢就用vi makefile的命令进入里面,编写这个文本。 (特别提醒一下,我们再编写第二段,也就是gcc那一段的时候,我们要先按一下TAB键,不能用空格,不然会出错的!!!) 里面的是不是有我们很熟悉的命令,那个就是我们在前面讲的时候用到的命令 编写完之后呢,我们保存然后退出就可以了
现在呢就可以执行这个make的命令了
直接输入make,然后就可以看到以下情况 然后我们在执行这个文件,就可以看到结果了 然后呢我们再去执行以下make clean的命令,就会看到直接执行了rm的命令,生成的文件直接删除了 以上就是一个比较简单的一个makefile的编写,当然一般那个大型工程的makefile一般都是用cmake来生成,不需要我们自己去写
接下来呢在讲一下Make的工作流程
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。 2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello_demo”这个文件,并把这个文件作为最终的目标文件。 3、如果hello_demo文件不存在,或是hello_demo所依赖的后面的 .o 文件的文件修改时间要比hello_demo这个文件新,那么,他就会执行后面所定义的命令来生成hello_demo这个文件。 4、如果hello_demo所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。 5、当然,我们的C文件和H文件都存在,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件hello_demo了。
Make 变量
一个Makefile里我们发现经常会由重复的内容,如上面范例中的前两行中的 hellospeak.o speak.o 如果我们的工程需要加入一个新的[.o]文件,那么我们好几个地方都需要修改原来的makefile。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们可以使用变量。makefile的变量也就是一个字符串,完全可以理解成C语言中的宏。
变量定义: 变量名 = 值 ##使用shell script 的语法 如: objects = hellospeak.o speak.o
我们上面的makefile 就可以变成:
objects = hellospeak.o speak.o
hello_demo : $(objects)
gcc -o hello_demo $(objects)
hellospeak.o : hellospeak.c speak.h
gcc -c hellospeak.c
speak.o : speak.c speak.h
gcc -c speak.c
.CEN : clean
clean :
rm hello_demo $(objects)
Make 自动推导
make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。
只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个hello.o,那么hello.c,就会是hello.o的依赖文件。并且 gcc -c hello.c 也会被推导出来,于是,我们的makefile再也不用写得这么复杂。我们的新的makefile又出炉了。
objects = hellospeak.o speak.o
hello_demo : $(objects)
gcc -o hello_demo $(objects)
$(objects):speak.h
#hellospeak.o : hellospeak.c speak.h
# gcc -c hellospeak.c
#speak.o : speak.c speak.h
# gcc -c speak.c
.PHONY : clean
clean :
rm hello_demo $(objects)
<奇牛学院>
以上就是makefile的部分知识。
|