我是Makefile
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我是Makefile相关的知识,希望对你有一定的参考价值。
Linux就这个范儿 第8章 我是Makefile
P287
Makefile的作用就是——自动化编译,一旦写好,只需要一个make命令(解析Makefile,执行Makefile中描述的操作),整个工程就能完成自动编译,
无论这个工程拥有多少个源代码文件。Makefile定义了一系列的规则,来指定哪些文件需要先编译,哪些文件需要后编译,
哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为Makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。
最典型的就是在微软的Visual Studio中,当你需要别人编写的dll作为你项目的一部分时,如果这个dll采用多线程库,而你的工程却采用了单线程库,
构建这个工程的时候一定会失败。如果你不清楚这些,永远解决不了这个问题。
即便你不具备编写Makefile的技能,那也需要掌握make这个工具的使用方法。因为还有很大一部分你需要的、或者感兴趣的软件是采用源代码方式发行的。
即便rpm、deb等软件打包方案在Linux世界已经大行其道,但是如果你要使用这些软件的最新版本,基本上脱离不了使用make这个工具通过源代码来创建它。
即便那些采用Python、Perl等解释语言开发的软件,绝大多数的情况也是利用Makefile做为安装脚本的。
当然,更进一步说,你有了一个很了不起的创意,并且准备分享给全世界,那么在Linux上你就更需要掌握make乃至Makefile的编写技巧。
因为大多数人是这么做的,我想你还不足以强大到可以改变这一现实的程度。但是如果你一定要说不,那我也没有办法,那你最好远离Linux,因为Linux正在远离你。
不过对于大多数Java程序员来说,Ant和Maven或许是他们更为常用或乐于使用的工具。
但这并不表明Makefile在遇到Java时就会显得有些ED,因为Makefile对Java也提供了良好的支持。
但是为何Ant和Maven在这个行当中走到了领先的位置,还是在于它们相对Makefile的学习周期更为简短,而且Maven能够比较容易地解决一些jar包依赖问题。
但是这里有一个始终让我疑惑的地方,就是当我跟好多Java高手们谈起XML时,他们会将它说得一无是处,就好像是所有问题的根源,但是Ant和Maven又是完全的XML格式而他们又对它爱不释手。
也许就像矛盾冲突是戏剧的精髓一样,人生也是一场戏吧。不过Ant和Maven的确都是非常强大的工具。只是在我看来我更喜欢Makefile,因为它更具灵活性和描述能力,能够用很简单的方式完成更为复杂的任务。
所以即便你是Java程序员,我也希望你能够掌握Makefile,它或许能够更加开阔你的视野。不过很多时候Ant或Maven已经足够用了,
只是我要多说一句的是,纵使IDE可以对它们提供良好的支持,但是作为初学者最好远离IDE。因为IDE是高手的挡泥板,却是初学者的遮阳伞(久不晒太阳会得病的)!
GNU make及其基本用法
实际上Makefile并不是这个工程管理工具的名称,但却是一种约定俗成的叫法。
它是一类工程管理工具的工程描述文件的默认名称,它只是相当于Ant的build.xml和Maven的pom.xml文件。
而且更让初学者头痛的是,这个文件名它不是唯一的。可以是Makefile,可以是makefile(注意Linux的文件名是区分大小写的),甚至是GNUmakefile。
或许你已经注意到了,我刚才说Makefile是一类工程管理工具的工程描述文件,并不是说一个,是不是丈二和尚了?其实我在学习Makefile的时候也遇到了同样的困惑。
后来才慢慢了解到,Makefile是make工程管理工具的工程描述文件,make是类UNIX世界的一个传统工程管理工具,是它们文化的一部分,可以称作Makefile文化。
那么既然是文化,就得允许百花齐放、百家争鸣。
传统UNIX的主要分支,比如Solaris、HP-UNIX、AIX等采用一套Makefile体系;BSD系列如:FreeBSD、OpenBSD、NetBSD等采用一套Makefile体系;
Linux采用另一套Makefile体系。而且即便属于同一体系,在某些方面都会显得大相径庭。
在Linux中采用的是GNU make这一体系,属于GNU计划中的一部分,可以说是所有体系中功能最为丰富、兼容性最好的一个Makefile文化的传承品。
Linux内核的编译是有两个强依赖的,其中一个就是GNU make,另外一个是gcc。
其实大家会奇怪,Linux既然有这么好的通用性和可移植性,为什么会有两个强依赖呢?
其实这就更充分说明GNU make和gcc是足够的NB,它们本身就具备了极强的通用性和可移植性。它们几乎已经被移植到已知乃至未知的所有平台上了,所以作为Linux即便对他们有强依赖也根本不会影响到它的通用性和可移植性。
GNU make已经是当前事实上的“标准”了,就好像它说的是标准普通话,其他make说的都是方言。本章所介绍的内容也是适用于其他make的,毕竟普通话与方言的区别仅在发音上,具体语素和语法习惯还是一致的。
在Linux就是执行make命令来完成工作的(在其他系统中就不一定是这样了)。
make就是Linux系统下的一个工具,在任意目录中执行make都可以(/usr/bin/make),只是效果不同罢了。
make会在执行路径中搜索Makefile文件。前面已经说过,Makefile并不是唯一的选择,还可以是makefile和GNUmakefile。
如果一个路径中同时存在它们三者,make会选择一个。不过不要惊慌,这是有规矩的,要是没有规矩不就乱性了吗?
make的选择顺序是GNUmakefile、makefile和Makefile。
只要选中了一个就不再理会其他的了。这个时候make还是很专一的。
当然你也可以让make不那么专一。方法就是用“—f”选项给make指定一个工作文件。
这个时候任何文件名都可以,只要内容符合Makefile的书写规范就行。“—f”选项有两种变形,分别是“--file=FILE”和“--makefile=FILE”,功能完全相同,随你的喜好决定。
这是一个非常常用的命令选项,尤其是在跨平台项目中,会针对不同的平台提供不同的Makefile文件。
另外一个常用的命令选项是“-d”,用于调试Makefile。在手工编写一个Makfile文件时非常有用。不过不要指望类似于调试C或Java程序那样可以单步跟踪。
它的作用仅是将Makefile的执行过程一一打印出来,让你观察在哪个地方出现了意想不到的错误。变形选项是“-debug[=FLAGS]”,功能会更加丰富一些。
对于只是想通过Makefile来作为阅读代码入口的人来说,make提供了一个“—t”选项,它能够帮你输出为生成一个可执行文件而需要的所有目标文件。
这样你就排除了那些不相干的东西,使得这一严峻的问题变得简单了许多。这个过程并不执行真正的工程创建过程,所以这不会影响到代码的原始性,只是帮你做了很好的梳理,而且过程既简单又快捷。
变形选项是“-touch”,功能完全相同。
对于make这个命令提供的选项还有很多,这里不一一列出,有兴趣的话可以使用“—h”或“-help”选项查看其他的命令以及说明。
如果感觉通过这个命令得到的内容有点过于单薄,那么就可以使用man命令查看它的在线帮助手册,这个“男人”真的很有用!
其实make的用法还远不止是命令选项这些,只是我都留在接下来的内容中了。因为我永远相信:若想真正掌握一个工具是必须去实际使用的。
-f选项:指定makefile
-t选项:输出为生成一个可执行文件而需要的所有目标文件
-d选项:调试makefile
8.2 基本概念
首先让我们了解一下Makefile的基本概念。
8.2.1 第一个Makefile例子
话说有一个功成身退的程序员,闲来无趣准备练习书法消磨时间并期望能有所建树。于是斥巨资购买了上等文房四宝。一日,饭后突然兴起。一番研墨、铺纸、焚香,颇有王、颜之概。待气定神闲,面色凝重地写下一行字:hello world。
好吧,这就是悲催的程序猿,只要学习一些新东西,总是会想到“hello world”。而且有些人居然号称会使用数十门编程语言,那咱们得向这等高手请教一番吧。结果他只告诉了你每门语言如何写“hello world”。我真的不想找骂,所以我给大家展示的第一个例子,跟“helloworld”无关。具体参见代码1所示。
代码1:
all:TinyEdit TinyEdit: main.o line.o buffer.o tools.o chunk.o document.o cursor.o cc main.o line.o tools.o buffer.o -o TinyEdit myless:myless.o line.o buffer.o tools.o chunk.o ccmyless.o line.o tools.o buffer.o -omyless -lcurses myless.o:myless.c line.h buf fer.h tools.h tedef.h cc -c -o myless.o myless.c document.o:document.c line.h buf fer.h cursor.h tools.h tedef.h cc -c -o document.o document.c cursor.o:cursor.c line.h tools.h tedef.h cc -C -o cursor.o cursor.C line.o:line.c line.h buf fer.h tools.h tedef.h cc -c -o line.o line,c tools.o:tools.c tools.h tedef.h cc -c -o tool.o tools.c chunk.o: chunk.c line.h buffer.h tedef.h cc -c -o chunk.o chunk.c buf fer.o:buf fer.c buf fer.h tools.h cc-c -o buffer.o buf fer.c main.o:main.c line.h buf fer.h tedef.h cc -c -o maln.o maln.c
这是我曾经写过的一个行文本编辑器的Makefile文件,虽然看似内容很多,实际上是很好理解的,也基本包含了这一部分我所要讲述的内容。
这个Makefile可以生成两个可执行文件:TinyEdit和myless。
TinyEdit就是一个简单的行文本编辑器:myless是一个简单的文本阅读器。
根据前面我们掌握的知识,当我执行make命令后,就会生成TmyEdit。那我要生成myless怎么办呢?要执行make myless命令。
哈,聪明的你是不是会根据这个联想一下,我要是执行make love这样的命令,是不是就生成love了呢?答案让你失望了,make会报错的。因为这个Makefile中没有love,所以生成不了。
这也给我们传达了一个道理,没有love的make love实际上是一种错误,是产生不了love的。
在这里make后面的参数不是命令选项,而是用于标明make要处理并最终生成的目标。
到这里我猜你们会有一个疑问。就是在生成TinyEdit的时候,并没有指定目标啊?嗯,这的确是个好问题,我们继续下面的内容来找到答案。
F
以上是关于我是Makefile的主要内容,如果未能解决你的问题,请参考以下文章
Makefile:2: *** 缺少分隔符。停止。我该如何解决这个问题我是 Raylib for C++ 的新手