为什么没有人使用make for Java?
几乎所有我见过的Java项目都使用Maven或Ant。 他们是很好的工具,我认为任何项目都可以使用它们。 但是发生了什么? 它用于各种非Java项目,并可以轻松处理Java。 当然,如果你使用Windows,你必须下载make.exe,但Ant和Maven也不能使用JDK。
与Java一起使用时,是否存在一些基本缺陷? 仅仅是因为Ant和Maven是用Java编写的?
Make和Java的基本问题是,Make的工作原理是指定一个依赖关系,然后是规则来解决这个依赖关系。
使用基本的C,通常是“将main.c文件转换为main.o文件,运行”cc main.c“。
你可以在java中做到这一点,但你很快就会学到一些东西。
大多数情况下,javac编译器启动缓慢。
和…之间的不同:
javac Main.java javac This.java javac That.java javac Other.java
和
javac Main.java This.java That.java Other.java
是昼夜。
加剧了数以百计的课程,而且变得站不住脚。
然后你把这个结合起来,java往往被组织成目录中的文件组,vs C和其他倾向于平坦结构的文件。 Make没有太多直接的支持来处理文件的层次结构。
做也不是很好在收集水平确定什么文件是过时的。
使用Ant,它会经历和总结所有过时的文件,然后一次编译它们。 Make将简单地调用每个单独文件上的java编译器。 如果不这样做,就需要有足够的外部工具才能真正显示出Make不能胜任这个任务。
这就是为什么像Ant和Maven这样的替代品上涨的原因。
古老的make
程序可以很好地处理像C和C ++这样的编译语言。 您编译一个模块,它使用#include
来拉入其他包含文件的文本,并将单个目标文件写入输出。 编译器是一个非常单一的系统,有一个单独的链接步骤将目标文件绑定到可执行的二进制文件中。
但是,在Java中,编译器必须实际编译通过import
其他类。 尽pipe可以编写一些能够从Java源代码生成所有必需的依赖关系的东西,因此make
会按照正确的顺序构build类,但这仍然不能处理循环依赖等情况。
通过caching其他类的编译结果,Java编译器也可以更高效,同时编译依赖于已经编译的结果的更多类。 这种自动的依赖性评估不可能独自完成。
这个问题是基于一个不正确的假设:不less开发者都使用make
。 请参阅Java构build工具:Ant vs. Maven 。 至于开发商为什么不使用make
:许多开发者从未使用过make
,或者使用过它,并且用比一千个太阳炎热的火来讨厌它。 因此,他们使用替代工具。
关于每个技术优点的所有其他答案都是真实的。 Ant
和Maven
可能比Java更适合Java,或者像Hank Gay指出的那样,他们可能不会:)
但是,您问到Ant和Maven是否使用Java编写是否重要。 虽然在StackOverflow上,我们并不认为这样的想法(封闭的!不是与编程相关的!等等),当然这是事物的一部分。 在Rails上,我们使用Rake,C dudes使用make,而在Java中我们使用Ant和Maven。 尽pipeAnt或Maven开发人员会比其他人更好地照顾Java开发人员,但还有另外一个问题:你在写什么Ant任务? Java的。 如果你是一个Java开发人员,那很容易。
所以是的,其中的一部分是使用您正在使用的语言编写的工具。
实际上,make可以在所有过时的java文件的一个命令中处理重新编译。 如果您不想编译目录中的所有文件或想要特定顺序,请更改第一行…
JAVA_FILES:=$(wildcard *.java) # # the rest is independent of the directory # JAVA_CLASSES:=$(patsubst %.java,%.class,$(JAVA_FILES)) .PHONY: classes LIST:= classes: $(JAVA_CLASSES) if [ ! -z "$(LIST)" ] ; then \ javac $(LIST) ; \ fi $(JAVA_CLASSES) : %.class : %.java $(eval LIST+=$$<)
ant和后来的Maven被devise来解决由Make
造成的一些头痛(在创build新的过程中),这只是进化。
此后不久,几个开源Java项目意识到Ant可以解决他们在Makefiles中遇到的问题….
从http://ant.apache.org/faq.html#history
不pipe他们解决什么问题,或者只是创build一个额外的格式来学习是一个主观的话题。 事实是,这几乎是每一个新发明的历史:创造者说,它解决了很多问题,原来的用户说这些都是美德。
它的主要优点是可以与java集成。
我猜想类似的历史将与rake
例如。
Maven(和启用了Ivy的Ant设置)解决的主要问题之一就是自动依赖parsing和下载你的依赖瓶。
我认为最可能的解释是有几个因素阻碍了Java社区在关键时期(90年代后期)使用make:
- 由于Java包含多个平台,一般来说,Java程序员不像程序员一般局限于Unix环境(例如C和Perl程序员)那样擅长Unix工具。 请注意,这是一般的。 毫无疑问,有很多天才的Java程序员对Unix有着深刻的理解。
- 因此他们不善于制造,也不知道如何有效地使用制造。
- 尽pipe可以编写一个简短的Makefile来高效地编译Java,但需要特别注意以独立于平台的方式来执行此操作。
- 因此,对本质上独立于平台的构build工具产生了兴趣。
- 正是在这样的环境下,Ant和Maven才被创造出来。
简而言之,虽然肯定可以用于Java项目,但有一点机会使其成为事实上的Java构build工具。 那一刻已经过去了。
使脚本倾向于天生依赖于平台。 Java应该是独立于平台的。 因此,只有在一个多平台源代码平台上运行的构build系统才是一个问题。
除非我没有人假设没有人是(错)使用make for java是错误的。
“使用GNU Makepipe理项目”(在GFDL下提供)包含了一个完整的章节,专门介绍如何使用make
项目。
因为它包含了一个使用make而不是其他工具的优点和缺点的长长的列表(希望是公平的),所以你可能想看看那里。 (见: http : //oreilly.com/catalog/make3/book/ )
Ant是一种基于XMLconfiguration的Makefiles改进,而Maven是一个对Ant的依赖构build工具改进。 有些项目使用全部三个。 我认为JDK项目使用了makefile和ant的混合。
简答:因为make
不好。 即使在C方面,你也会看到很多select。
长的答案: make
有几个瑕疵,使得它几乎不适合编译C,而不适合编译Java。 如果需要,可以强制编译Java,但是可能会遇到问题,其中一些问题没有适当的解决scheme或解决方法。 这里有几个:
依赖分辨率
固有地期望文件彼此具有树状的相关性,其中一个文件是构build其他几个文件的输出。 处理头文件时,这已经在C中反弹了。 make
需要生成一个make
-specific包含文件来表示一个C文件对它的头文件的依赖性,所以对后者的改变会导致先前被重build。 但是,由于C文件本身没有被重新创build(只是重build),因此经常需要将目标指定为.PHONY
。 幸运的是,GCC支持自动生成这些文件。
在Java中,依赖关系可以是循环的,在make
格式中没有自动生成类依赖关系的工具。 ant
的Depend
任务可以直接读取类文件,确定它所导入的类,并删除类文件,如果其中任何一个是过时的。 没有这个,任何不平凡的依赖可能会导致你被迫使用重复的干净的构build,消除使用构build工具的任何优势。
文件名空间
尽pipeJava和C都不鼓励在你的源代码文件名中使用空格,但是在这种情况下,即使空格在文件path中,也可能是个问题。 例如,考虑一下你的源代码是否存在于C:\My Documents\My Code\program\src
。 这将足以打破make
。 这是因为make
文件名作为string。 ant
将path视为特殊对象。
扫描生成的文件
make
要求明确地设置为每个目标构build哪些文件。 ant
允许指定一个要自动扫描源文件的文件夹。 这看起来可能有点不太方便,但考虑到在Java中,每个新类都需要一个新文件。 将文件添加到项目可以快速成为一个很大的麻烦。
而最大的问题在于:
make是POSIX依赖的
Java的座右铭是“编译一次到处运行”。 但是,将这种编译限制在基于POSIX的系统中,其中Java支持实际上是最糟糕的,而不是这个意图。
在make
中构build规则基本上是小bash
脚本。 尽pipeWindows有一个端口,为了正常工作,它必须与bash
端口捆绑在一起,其中包括一个用于文件系统的POSIX仿真层。
这有两个种类:
-
MSYS
试图将POSIX转换限制为文件path,因此在运行不是特别为其创build的外部工具时,可能会有不愉快的问题。 -
cygwin
提供了一个完整的POSIX仿真。 结果程序,但是,往往仍然依靠这个仿真层。
出于这个原因,在Windows上,标准的构build工具根本就没有make
,而MSBuild
也是基于XML的工具,原则上更接近于ant
。
相比之下, ant
是用Java构build的,可以在任何地方运行,并且包含内部工具,称为“任务”,以平台无关的方式处理文件和执行命令。 这是非常灵活的,你实际上可以有一个更容易的时间build立在Windows使用ant
比使用make
的C程序。
最后一个小小的一个:
即使C程序本身不使用make
您最初可能不会注意到这一点,但C程序通常不附带Makefile
。 它们附带一个CMakeLists.txt
,或者一个bash
configuration脚本,用于生成实际的Makefile
。 相比之下,使用ant
构build的Java程序的源代码则附带了一个预先创build的ant
脚本。 Makefile
是其他工具的产物 – 这就是多lessmake
不适合自己构build的工具。 ant
是独立的,可以处理Java构build过程所需的所有内容,而不需要额外的需求或依赖关系。
当你在任何平台上运行ant
时,它只是工作(tm)。 你做不到。 这是令人难以置信的平台和configuration依赖。
其中一个重要的原因是Ant和Maven(以及大部分的Java目标SCM,CI和IDE工具)都是由java开发人员用java编写的。 这使得集成到开发环境中变得更加简单,并允许其他工具(如IDE和CI服务器)在构build/部署基础结构中集成部分ant / maven库。
曾几何时,我曾经在一个使用gmake的Java项目上工作。 我的回忆是朦胧的,但是IIRC我们很难处理javac期望的包目录结构。 我还记得build立JAR文件是一件麻烦事,除非你有一些微不足道的东西。
Ant和Maven从更现代化的angular度来看待构build依赖关系图和对其的pipe理……但是正如奥斯卡所说,他们在尝试用make来解决老问题的同时也创造了自己的问题。
我从来没有使用GNU Make for Java项目,但我曾经使用jmk 。 可悲的是,自2002年以来没有更新。
它具有一些特定于Java的function,但足够小,可以包含在源代码tarball中,而不会显着增加其大小。
现在,我只是假设任何Java开发人员与Ant安装共享代码。
ApacheAnt与Make没有任何区别。 Make是关于描述文件之间的依赖关系,以及如何构build文件。 Ant是关于“任务”之间的依赖关系,实际上更多的是将构build脚本粘合在一起的方式。
它可以帮助你AntVsMake