在 Linux 环境下编程,make 工具的使用以及编写 Makefile 文件是很重要的。当然,make 工具对在 Windows 环境下编程的程序员也是有用的。

Makefile 文件描述了整个工程的编译、连接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建那些中间文件以及如何创建这些中间文件、如何最后产生我们想要得可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写 Makefile 的好处是能够使用一行命令来完成“自动化编译”,一旦提供了正确的 Makefile,编译整个工程你所要做的唯一的一件事就是输入 make 命令。整个工程完全自动编译,极大提高了效率。

make 是一个命令工具,它解释 Makefile 中的规则。在 Makefile 文件中描述了整个工程所有文件的编译顺序、编译规则。Makefile 有自己的书写格式、关键字、函数。而且在 Makefile 中可以使用系统 shell 所提供的任何命令来完成想要的工作。Makefile 在绝大多数的 IDE 开发环境中都在使用,已经成为一种工程的编译方法。

当对工程中的若干源文件修改以后,只需要重新执行 make 命令,就会自动根据修改情况完成源文件的对应目标文件的更新、中间文件的更新、最终的可执行程序的更新。make 通过比较对应文件的最后修改时间,来决定哪些文件需要更新、那些文件不需要更新。对需要更新的文件 make 就执行相应的命令来重建它,对于不需要重建的文件 make 什么也不做。

Makefile 文件的规则包含了文件之间的依赖关系和更新此规则目标所需要的命令,如下所示:

目标: [依赖]

  [命令]

make 程序根据规则的依赖关系,决定是否执行规则所定义的命令的过程我们称之为执行规则

通常,make 在执行命令行之前会把要执行的命令行输出到标准输出设备,我们称之为回显。但是,如果规则的命令行以字符“@”开始,则 make 在执行这个命令时就不会回显这个将要被执行的命令。

如果使用 make 的命令行参数“-n”或“--just-print”,那么 make 执行时只显示所要执行的命令(也包括了使用“@”字符开始的命令),但不会真正的去执行这些命令。

为了忽略一些无关命令执行失败的情况,我们可以在命令之前加一个减号“-”,来告诉 make 忽略此命令的执行失败。

默认的情况下,make 执行的是 Makefile 中的第一个规则,此规则的第一个目标称之为终极目标(就是一个 Makefile 最终需要更新或者创建的目标)。

好了,我们现在以“也谈在 .NET 平台上使用 Scala 语言(续)”这篇文章中的例子来简要说明了一下 Makefile 文件的编写方法。

在上图中,第一行的五个文件是源程序文件,最后一行的两个文件是我们最终要生成的目标文件。其余四个文件都是编译过程中产生的中间文件。

第1行到第8行定义了一些变量供以后使用。变量的引用方法是 $(变量名),我们在第8行中已经看到了。

第10行到第11行定义了一个模式规则,指明了如何从 .cs 文件生成 .dll 文件。在模式规则中,目标是一个带有模式字符“%”的文件,使用模式来匹配目标文件。文件名中的模式字符“%”可以匹配任何非空字符串,除模式字符以外的部分要求一致。例如:%.dll 匹配所有以 .dll 结尾的文件。模式规则依赖文件中同样可以使用“%”,依赖文件中模式字符“%”的取值情况由目标中的“%”来决定。例如:对于模式规则 %.dll: %.cs ,它表示的含义是:所有的 .dll 文件依赖于对应的 .cs 文件。

在该模式规则命令中,使用了以下自动化变量

  • $@: 规则目标文件名
  • $<: 规则的第一个依赖文件名

第13行定义的规则中的 all 是我们的终极目标。这个规则没有命令部分,仅仅是为了生成或更新它的依赖:dotnet.exe 和 CsTest.exe。

第15行到第16行定义的规则指明了如何从 dotnet.msil 生成 dotnet.exe。

第18行到第19行定义的规则指明了如何从 CsTest.cs 生成 CsTest.exe。

第21行到第22行定义的规则指明了如何从 dotnet.scala 生成 dotnet.msil。

第24行到第26行定义的规则用来运行编译好的目标文件。

第28行到第29行定义的规则用来清除当前目录下编译生成的所有文件。目标 clean 没有任何依赖文件,它只有一个目的,就是通过这个目标名来执行它所定义的命令。Makefile 文件中那些没有任何依赖只有执行动作的目标称为伪目标。可输入 make clean 来执行 clean 目标所定义的命令

让我们来试试看吧:

ben@ben-vbox:~/Projects/ScalaNet$ makegmcs -out:RuntimeFramework.dll -t:library -pkg:dotnet -r:System.Xml.Linq.dll RuntimeFramework.csgmcs -out:DotNet.dll -t:library -pkg:dotnet -r:System.Xml.Linq.dll DotNet.csgmcs -out:TheXmlTree.dll -t:library -pkg:dotnet -r:System.Xml.Linq.dll TheXmlTree.csscalac-net -Xassem-path RuntimeFramework.dll:DotNet.dll:TheXmlTree.dll dotnet.scalailasm -output:dotnet.exe dotnet.msilAssembling 'dotnet.msil' , no listing file, to exe --> 'dotnet.exe'Operation completed successfullygmcs -out:CsTest.exe -r:RuntimeFramework.dll -r:DotNet.dll -r:TheXmlTree.dll CsTest.cs

可以看到,一切正常,所有的文件都按我们设想的进行编译:

  • 调用 gmcs 三次编译出三个 .dll 文件,使用第10行到第11行定义的模式规则
  • 调用 scalac-net 编译出 dotnet.msil 文件,使用第21行到第22行定义的规则
  • 调用 ilasm 汇编出 dotnet.exe 文件,使用第15行到第16行定义的规则
  • 调用 gmcs 编译出 CsTest.exe 文件,使用第18行到第19行定义的规则

让我们继续吧:

ben@ben-vbox:~/Projects/ScalaNet$ makemake: 没有什么可以做的为 `all'。ben@ben-vbox:~/Projects/ScalaNet$ touch CsTest.csben@ben-vbox:~/Projects/ScalaNet$ makegmcs -out:CsTest.exe -r:RuntimeFramework.dll -r:DotNet.dll -r:TheXmlTree.dll CsTest.csben@ben-vbox:~/Projects/ScalaNet$ make -n cleanrm -f *.exe *.dll *.msilben@ben-vbox:~/Projects/ScalaNet$ ls -l *.exe-rwxr-xr-x 1 ben ben 4096 2009-12-27 19:13 CsTest.exe-rw-r--r-- 1 ben ben 3584 2009-12-27 18:56 dotnet.exe

可以看出,第一个 make 命令什么也不干,因为所有的目标已经是最新的了。然后假设我们修改了 CsTest.cs 源程序文件,再次使用make 命令,正如我们所希望的,它仅仅重新编译 CsTest.cs 文件。最后,我们使用了 -n 参数执行 make -n clean命令,它仅仅显示这条要执行的命令,而不实际执行,所以 .exe 文件还在,没有被删除。

通过以上的学习,你应该已经初步了解如何编写 Makefile 文件。如需进一步学习,推荐:GUN make 中文手册。该手册非常长,讲的内容非常多,从中可以看出 make 工具的功能是非常强大的。

但是,我相信这篇文章中讲解的内容大多数情况下已经足够使用了,要相信“80/20法则”。而且,作为一个优秀的程序员,在面对一个复杂问题时,应该是寻求一种尽可能简单、直接并且高效的处理方式来解决,而不是将一个简单问题在实现上复杂化。如果想在简单问题上突出自己使用某种语言的熟练程度,是一种非常愚蠢、且不成熟的行为。

在 Windows 操作系统下可以用 nmake 命令来代替 make 工具,其 Makefile 文件基本上和 Linux 下的一致。

当然,下面两个东东有时候也是有用的:

  • MinGW: Minimalist GNU for Windows
  • Cygwin: A Linux-like environment for Windows

对了,本文中的所有源代码可以到 http://bitbucket.org/ben.skyiv/scalanet/downloads/ 页面下载。
也可以使用 hg clone http://bitbucket.org/ben.skyiv/scalanet/ 命令下载。
关于 hg ,请参阅 Mercurial 备忘录。

浅谈 make 工具相关推荐

  1. MYSQL优化浅谈,工具及优化点介绍,mysqldumpslow,pt-query-digest,explain等

    MYSQL优化浅谈 msyql是开发常用的关系型数据库,快速.稳定.开源等优点就不说了. 个人认为,项目上线,标志着一个项目真正的开始.从运维,到反馈,到再分析,再版本迭代,再优化- 这是一个漫长且考 ...

  2. java实现续打功能_浅谈报表工具的打印方案

    报表工具除了基本的绘制报表,完成数据呈现(也就是让终端用户能看到报表),打印也是报表的基本功能之一. 当前报表工具很多,可以按地域.开闭源等划分,包括有杰表.水晶.Style Report.birt. ...

  3. 浅谈DevSecOps工具链中的源代码安全保障

    近期,很多企业开始关注DevSecOps,下面根据作者对其理解,简单分析一下在DevSecOps的源代码安全该如何考虑和建设. 主要分5部分: 1.DevSecOps建设的背景和目的 2.安全才是提升 ...

  4. 精讲▍自然语言处理浅谈 技术/工具/方法和应用全都有了

    NLP方向 作者|陈颂光  编辑|树袋熊 由于人们之间普遍以自然语言的形式交流,互联网和各种数据库中的这些非结构化数据中蕴藏了价值连城的大量信息.然而,对于计算机而言,理解自然语言相当困难,实际上这可 ...

  5. 浅谈阅读工具Kindle的合理利用

    在亚马逊中文网上注册账户,绑定自己的Kindle邮箱,可以利用其网站上的免费书籍补充自己的Kindle,前提是让自己的Kindle链接上网络,没有网络的Kindle用起来太麻烦了. 1.网络可以使用的 ...

  6. python可视化工具bokeh_浅谈python可视化包Bokeh

    本文研究的主要是python可视化包Bokeh的相关内容,具体如下. 问题:需要把pandas的数据绘图并通过网页显示,matplotlib需要先保存图像,不合适. 解决:在网上搜了一下,找到一篇介绍 ...

  7. 浅谈eform自定义表单工具和协同办公系统

    浅谈eform自定义表单工具和协同办公系统 提起"协同办公",随便在百度或者Google搜索一下,就能让你看到眼花缭乱的信息,国内的各大协同办公软件厂商都在鼓吹着自己对协同的理解和 ...

  8. CAN诊断浅谈 如何用CAN工具进行诊断

    转:https://mp.weixin.qq.com/s/bcuoUQfkfyx6rtbgw-Z_BQ 引言: 从之前的课程我们了解到, 车上的智能硬件设备太多, 即ECU节点太多, 这些节点通过CA ...

  9. 嘴哥有料系列-can工具1:CAN诊断浅谈 + 如何用CAN工具进行诊断

    原文章:https://mp.weixin.qq.com/s/bcuoUQfkfyx6rtbgw-Z_BQ 引言: 从之前的课程我们了解到, 车上的智能硬件设备太多, 即ECU节点太多, 这些节点通过 ...

最新文章

  1. 利用Spring-Boot解析Excel、用Java分析Excel、告别手动输入用程序读取Excel
  2. php使用fputcsv进行大数据的导出
  3. table偏见和HTML仇外心理
  4. [Leedcode][第215题][JAVA][数组中的第K个最大元素][快排][优先队列]
  5. 经验 | 在C++平台上部署PyTorch模型流程+踩坑实录
  6. 图像检索:一维直方图+欧几里得距离+flann+KNN
  7. ListView控件使用简介(转载)
  8. python开发基础作业02:三级菜单,使用字典dic及列表
  9. 深入浅出SharePoint——站点的部署
  10. Android 一步步教你从ActionBar迁移到ToolBar
  11. 计算机组成原理 唐朔飞 知识点,计算机组成原理知识点总结(唐朔飞版)
  12. 数据库系统概论第五版(笔记)
  13. PS美容磨皮插件:dr5白金版mac版(兼容ps2020)
  14. GBASE 8s UDR内存管理_02_mi_dalloc
  15. pandas 透视表bug InvalidIndexError: Reindexing only valid with uniquely valued Index objects
  16. Qt之调用FFTW3实现音频频谱(原理)
  17. css3选择器详细探索
  18. 京东2018校园招聘一面、二面
  19. 数据分析——Kettle插件开发异常信息总结
  20. IS-IS协议基本概述

热门文章

  1. “现有人工智能都是二流的”
  2. Higher level thinking
  3. php使用curl发送 json数据
  4. 吞吐量、速率、背板带宽
  5. 超大ISO文件的分卷刻录方法
  6. Event Grid更新了!可轻松处理物联网装置遥测
  7. 推荐很好用的Goroutine连接池
  8. spring-boot-starter家族成员简介
  9. linux下DHCP服务器设置——让自己的智能手机上自己的wifi网络
  10. spring中的class配置不能使用properties中的字符串