182

我见过的几乎每个 Java 项目都使用 Maven 或 Ant。它们是很好的工具,我认为几乎任何项目都可以使用它们。但是发生了什么?它用于各种非Java项目,可以轻松处理Java。当然,如果你使用 Windows,你必须下载 make.exe,但是 Ant 和 Maven 也没有随 JDK 一起提供。

与 Java 一起使用时,make 是否存在一些基本缺陷?仅仅是因为 Ant 和 Maven 是用 Java 编写的吗?

4

17 回答 17

218

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 倾向于在目录中组织为文件组的事实相结合,而 C 和其他倾向于更扁平结构的文件。Make 对处理文件层次结构没有太多直接支持。

Make 也不太擅长在集合级别确定哪些文件已过期。

使用Ant,它会遍历并汇总所有过期的文件,然后一口气编译它们。Make 将简单地在每个单独的文件上调用 java 编译器。make NOT 这样做需要足够的外部工具才能真正表明 Make 不能完全胜任这项任务。

这就是为什么像 Ant 和 Maven 这样的替代品出现的原因。

于 2010-02-05T19:48:02.227 回答
36

这个古老的make程序可以很好地处理像 C 和 C++ 这样的单独编译的语言。您编译一个模块,它用于#include拉入其他包含文件的文本,并将单个目标文件作为输出写入。编译器在很大程度上是一个一次性系统,具有单独的链接步骤将目标文件绑定到可执行二进制文件中。

但是,在 Java 中,编译器必须实际编译您使用import. 尽管可以编写一些从 Java 源代码生成所有必要依赖项的东西,make以便一次以正确的顺序构建类,但这仍然无法处理循环依赖项等情况。

Java 编译器还可以通过缓存其他类的编译结果来提高效率,同时编译更多依赖于已编译结果的类。单独使用这种自动依赖性评估是不可能的make

于 2010-02-05T19:37:20.150 回答
35

实际上,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+=$$<)
于 2013-12-06T15:29:12.327 回答
30

这个问题基于一个不正确的假设:大量开发人员确实使用make. 请参阅Java 构建工具:Ant 与 Maven。至于开发者为什么使用make:很多开发者要么从来没用过make,要么用过,恨不得用比一千个太阳还要炽热的火。因此,他们使用替代工具。

于 2010-02-05T19:41:47.993 回答
17

关于每个技术优点的所有其他答案都是正确的。Ant并且Maven可能比 make 更适合 Java,或者正如 Hank Gay 指出的那样,它们可能不适合 :)

但是,您询问 Ant 和 Maven 用 Ja​​va 编写是否重要。尽管在 StackOverflow 上我们不考虑这样的想法(关闭!与编程无关!等等),当然这是事情的一部分。在 Rails 上我们使用 Rake,C dudes 使用 make,在 Java 中我们使用 Ant 和 Maven。虽然 Ant 或 Maven 开发人员确实会比其他人更好地照顾 Java 开发人员,但还有另一个问题:您用什么编写 Ant 任务?爪哇。如果您是 Java 开发人员,那么这很容易。

所以是的,其中一部分是使用以您正在使用的语言编写的工具。

于 2010-02-05T19:47:09.560 回答
12

Ant 和后来的 Maven 旨在解决一些令人头疼的问题Make(在创建新的过程中)它只是进化。

...不久之后,几个开源 Java 项目意识到 Ant 可以解决他们在 Makefile 中遇到的问题...。

来自http://ant.apache.org/faq.html#history

他们是否解决任何问题或只是创建一个额外的格式来学习是一个主观的话题。事实是,这几乎是每一项新发明的历史:创造者说它解决了很多问题,而原始用户说这些都是美德。

它的主要优点是可以与 java 集成。

例如,我想类似的历史会发生rake

于 2010-02-05T19:34:26.077 回答
9

Maven(和支持 Ivy 的 Ant 设置)通过 make 解决的主要问题之一是自动依赖解析和下载依赖 jar。

于 2010-02-05T19:37:43.627 回答
8

简短make的回答:因为不好。即使在 C 前端,您也会看到许多替代方案出现。

长答案:make有几个缺陷使其几乎不适合编译 C,并且根本不适合编译 Java。如果需要,您可以强制它编译 Java,但预计会遇到问题,其中一些没有合适的解决方案或解决方法。这里有几个:

依赖解析

make本质上期望文件彼此之间具有树状依赖关系,其中一个文件是构建其他几个文件的输出。在处理头文件时,这已经在 C 中适得其反。make需要make生成一个特定的包含文件来表示 C 文件对其头文件的依赖关系,因此对后者的更改将导致重新构建之前的文件。但是,由于 C 文件本身没有重新创建(只是重新构建),因此 make 通常需要将目标指定为.PHONY. 幸运的是,GCC 支持自动生成这些文件。

在 Java 中,依赖关系可以是循环的,并且没有用于自动生成make格式类依赖关系的工具。antDepend任务可以改为直接读取类文件,确定它导入了哪些类,并在其中任何一个过期时删除该类文件。如果没有这个,任何重要的依赖都可能导致您被迫使用重复的干净构建,从而消除使用构建工具的任何优势。

文件名中的空格

虽然 Java 和 C 都不鼓励在源代码文件名中使用空格,make但即使空格在文件路径中,这也可能是个问题。例如,考虑您的源代码是否存在于C:\My Documents\My Code\program\src. 这足以打破make。这是因为make将文件名视为字符串。ant将路径视为特殊对象。

扫描文件以进行构建

make需要明确设置要为每个目标构建哪些文件。ant允许指定要自动扫描源文件的文件夹。这似乎是一个小小的便利,但考虑到在 Java 中每个新类都需要一个新文件。将文件添加到项目中可能会很快变得很麻烦。

最大的问题是make

make 依赖于 POSIX

Java 的座右铭是“编译一次,到处运行”。但是,将编译限制在基于 POSIX 的系统上,其中 Java 支持实际上是最差的,并不是本意。

构建规则make本质上是小bash脚本。尽管有makeWindows 的端口,但要使其正常工作,它必须与 的端口捆绑在一起bash,其中包括文件系统的 POSIX 仿真层。

这有两个品种:

  1. MSYS它试图将 POSIX 转换限制为文件路径,因此在运行不是专门为它制作的外部工具时可能会遇到令人不快的问题。

  2. cygwin它提供了完整的 POSIX 仿真。然而,生成的程序往往仍然依赖于该仿真层。

出于这个原因,在 Windows 上,标准构建工具甚至根本不是,make而是.MSBuildant

相比之下,ant它是用 Java 构建的,可以在任何地方运行,并且包含称为“任务”的内部工具,用于以独立于平台的方式操作文件和执行命令。它的用途非常广泛,实际上您可以在 Windows 中使用ant比使用make.

最后一个小问题:

甚至 C 程序本身也不使用 make

您最初可能没有注意到这一点,但 C 程序通常不附带Makefile. 它们附带一个CMakeLists.txt. 或bash配置脚本,可生成实际的Makefile. 相比之下,使用构建的 Java 程序的源代码ant带有ant预构建的脚本。AMakefile是其他工具的产品 - 这make就是不适合单独作为构建工具的程度。ant是独立的,可以处理 Java 构建过程所需的一切,没有任何额外的要求或依赖项。

当您ant在任何平台上运行时,它都能正常工作(tm)。你不能用make. 它非常依赖于平台和配置。

于 2016-03-02T13:57:18.260 回答
6

使脚本往往天生依赖于平台。Java 应该是独立于平台的。因此,拥有一个只能在一个平台上为多平台源库工作的构建系统是一个问题。

于 2010-02-06T21:44:50.460 回答
6

我认为最可能的解释是,在关键时期(1990 年代后期),有几个因素不鼓励在 Java 社区中使用 make:

  1. 因为Java 包含多个平台,Java 程序员通常不像通常局限于Unix 环境的程序员(例如,C 和Perl 程序员)那样擅长Unix 工具。请注意,这是一般情况。毫无疑问,有并且曾经是对 Unix 有深刻理解的天才 Java 程序员。
  2. 因此,他们不太擅长make,也不知道如何有效地使用make。
  3. 虽然可以编写一个简短而简单的 Makefile 来有效地编译 Java,但需要特别注意以独立于平台的方式这样做。
  4. 因此,人们对本质上独立于平台的构建工具产生了兴趣。
  5. 正是在这个环境中创建了 Ant 和后来的 Maven。

简而言之,虽然 make 肯定可以用于 Java 项目,但有机会让它成为事实上的 Java 构建工具。那一刻已经过去了。

于 2013-03-03T02:29:12.663 回答
6

除非我不是一个人,否则没有人(错误)使用 make for java 的假设是错误的。

“使用 GNU Make 管理项目”(在 GFDL 下提供)包含专门用于使用makejava 项目的完整章节。

由于它包含使用 make 而不是其他工具的利弊的长列表(希望是公平的),您可能想看看那里。(见:http: //oreilly.com/catalog/make3/book/

于 2013-04-07T03:50:14.187 回答
3

Ant 是对 Makefile 的一种面向 XML 配置的改进,而 Maven 是对 Ant 的依赖构建工具的改进。一些项目使用所有这三个。我认为 JDK 项目过去常常混合使用 makefile 和 ant。

于 2011-03-17T14:30:39.170 回答
1

一个重要原因是 Ant 和 Maven(以及大多数面向 Java 的 SCM、CI 和 IDE 工具)都是由 Java 开发人员用 Java 编写的。这使得集成到您的开发环境中变得更加简单,并允许其他工具(例如 IDE 和 CI 服务器)将部分 ant/maven 库集成到构建/部署基础架构中。

于 2010-02-05T20:29:57.583 回答
1

曾几何时,我从事一个使用 gmake 的 Java 项目。我的回忆很模糊,但是 IIRC 我们很难处理 javac 期望的包目录结构。我还记得构建 JAR 文件很麻烦,除非你有一些琐碎的事情。

于 2010-02-08T19:55:57.887 回答
1

ApacheAnt 与 Make 完全不同。Make 是关于描述文件之间的依赖关系,以及如何构建文件。Ant 是关于“任务”之间的依赖关系,实际上更多的是一种将构建脚本粘合在一起的方式。

它可以帮助你AntVsMake

于 2014-09-15T09:53:18.077 回答
0

Ant 和 Maven 从更“现代”的角度处理构建依赖图及其管理……但正如 Oscar 所说,他们在尝试解决 make 的旧问题时产生了自己的问题。

于 2010-02-05T19:37:21.947 回答
0

我从未将 GNU Make 用于 Java 项目,但我曾经使用过jmk。遗憾的是,它自 2002 年以来一直没有更新。

它具有一些特定于 Java 的功能,但足够小,可以包含在您的源代码压缩包中,而不会显着增加其大小。

现在我只是假设任何与我共享代码的 Java 开发人员都安装了 Ant。

于 2010-02-05T20:16:56.770 回答