189

Just about every Java project that I've seen either uses Maven or Ant. They are fine tools and I think just about any project can use them. But what ever happened to make? It's used for a variety of non-Java projects and can easily handle Java. Sure you have to download make.exe if you use Windows, but Ant and Maven also don't come with the JDK.

Is there some fundamental flaw with make when used with Java? Is it just because Ant and Maven are written in Java?

User1
  • 39,458
  • 69
  • 187
  • 265
  • 41
    If you move stuff around and do more than just invoking the compiler (and even then), the platform-specific stuff gets very awkward to handle in `make`. And having a makefile which only works on one system isn't very nice for a cross-platform language. – Joey Feb 05 '10 at 19:37
  • As an aside, Gradle is a new player in the Java space, as is Gant (to a lesser degree). Maven or Ant is a false dichotomy. – Michael Easter Feb 05 '10 at 20:41
  • 1
    @Michael Easter, the false dichotomy would be Maven/Ant vs. Make. The true dichotomy, if I'm reading you right, would be Gradle/Maven/Gant/Ant vs. Make. But it's kind of hard to say :) – Dan Rosenstark Feb 05 '10 at 22:45
  • An unrelated note - modern distributions of Java can invoke javac transparently on single file sources so that `java Foo.java` runs directly. – Thorbjørn Ravn Andersen Apr 23 '22 at 12:21

17 Answers17

228

The fundamental issue with Make and Java is that Make works on the premise that you have specify a dependency, and then a rule to resolve that dependency.

With basic C, that typically "to convert a main.c file to a main.o file, run "cc main.c".

You can do that in java, but you quickly learn something.

Mostly that the javac compiler is slow to start up.

The difference between:

javac Main.java
javac This.java
javac That.java
javac Other.java

and

javac Main.java This.java That.java Other.java

is night and day.

Exacerbate that with hundreds of classes, and it just becomes untenable.

Then you combine that with the fact that java tends to be organized as groups of files in directories, vs C and others which tend towards a flatter structure. Make doesn't have much direct support to working with hierarchies of files.

Make also isn't very good at determining what files are out of date, at a collection level.

With Ant, it will go through and sum up all of the files that are out of date, and then compile them in one go. Make will simply call the java compiler on each individual file. Having make NOT do this requires enough external tooling to really show that Make is not quite up to the task.

That's why alternatives like Ant and Maven rose up.

mcyalcin
  • 2,074
  • 1
  • 15
  • 12
Will Hartung
  • 115,893
  • 19
  • 128
  • 203
  • 9
    So in order to use make in a huge Java project, it would be necessary to maintain a list of all changed .java files and then call javac at the end? That sounds less than ideal to me. That's the best answer that I've seen so far. – User1 Feb 09 '10 at 23:14
  • 43
    I love this. Essential you are saying Ant was needed to address the fact that javac is too slow. – cmcginty Nov 09 '10 at 01:47
  • 38
    No. Javac is not slow if you use it as it was designed to be used. It is just slow if you use it to compile one file at a time. – Stephen C Apr 30 '11 at 00:23
  • 9
    @Casey javac is not too slow. The JVM is too slow to start. – Thorbjørn Ravn Andersen Jan 18 '12 at 14:02
  • 2
    This answer is correct. Note that using make with less of a performance hit is possible if you use a nailgun to keep the jvm up and running. – mateor Jan 13 '15 at 05:51
  • 2
    Also, inner/anonymous classes produce `SomeClass$1.class` files, and they can add up quickly. They're impossible to track using Make. – Qix - MONICA WAS MISTREATED Jun 01 '16 at 03:42
  • 12
    GNU Make at least has the [`$?` automatic variable](https://www.gnu.org/software/make/manual/make.html#Automatic-Variables) which expands to "all prerequisites that are newer than the target". There is also the feature of [pattern rules with multiple targets](https://www.gnu.org/software/make/manual/make.html#Pattern-Intro) which would run the recipe only once to update all the `.class` files. Combine that with some clever use of file/text functions like `$(wildcard)`, `$(shell)`, `$(eval)` and you can teach your makefile to discover build targets scattered across your directory layout. – Tanz87 Oct 21 '16 at 22:09
  • 1
    Javac is smart and CC is dumb. So Javac knows what files are being referenced and (normally) just re-compile what is needed. No need for header file analysis. The dependency analysis is in the Javac. For this reason, Make is smart about dependencies, while Ant/Maven are dumb. Also javac is really just a parser, not a compiler, and so is really fast. – Tuntable Jul 24 '19 at 23:53
40

Actually, make can handle the recompilation in one command of all outdated java files. Change the first line if you don't want to compile all files in the directory or want a specific order...

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+=$$<)
user1251840
  • 655
  • 5
  • 8
  • 6
    Nice! I was looking for something like that. No need to use a different build tool for every language when the universal classic works fine. Thanks! – rsp Feb 01 '16 at 11:01
  • To pile on: I have a working prototype applying this suggested approach at https://github.com/byronka/atqa/blob/891ac188bbdbe3a14d43c25fbe19aef839bb346e/Makefile – Byron Katz Mar 19 '22 at 19:49
36

The venerable make program handles separately compiled languages like C and C++ reasonably well. You compile a module, it uses #include to pull in the text of other include files, and writes a single object file as output. The compiler is very much a one-at-a-time system, with a separate linking step to bind the object files into an executable binary.

However, in Java, the compiler has to actually compile other classes that you import with import. Although it would be possible to write something that generated all the necessary dependencies from Java source code, so that make would build classes in the correct order one at a time, this still wouldn't handle cases such as circular dependencies.

The Java compiler can also be more efficient by caching the compiled results of other classes while compiling further classes that depend on the results of ones already compiled. This sort of automatic dependency evaluation is not really possible with make alone.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 7
    This seems like more of a make versus javac answer than a make versus ant/maven answer. Based on your answer, why couldn't someone just use make + javac (giving javac an entire package or "module" at a time, so circular dependencies are hidden from make)? Would ant or maven provide any benefit over that approach? – Laurence Gonsalves Feb 05 '10 at 20:02
  • 1
    @Laurence: You could give javac an entire package at once, but then it will recompile *everything* in that package (since that's what you told it to do). It's true that the java compiler is pretty fast, but it's even faster if you let it determine which classes are the minimum needed to recompile after changing something. – Greg Hewgill Feb 05 '10 at 20:10
  • Are you referring to telling javac to only compile your "main" class, and then having it automatically build the stuff it depends on? Last I checked (admittedly, probably in 1.4) that was horribly unreliable. -Xdepend was slightly better (but slower, and still broken), and they removed that flag in 1.3. – Laurence Gonsalves Feb 05 '10 at 20:16
  • 4
    Also, this still doesn't explain why I'd use Ant or Maven rather than just straight javac... – Laurence Gonsalves Feb 05 '10 at 20:19
  • @LaurenceGonsalves Now 12 years later, time has shown that `ant` has fallen into disuse because it doesn't scale. `maven` is the default build engine and caught hold because of dependency handling, with a few alternatives which also uses the Maven dependency ecosystem. – Thorbjørn Ravn Andersen Apr 23 '22 at 12:24
31

The question is based on an incorrect assumption: a non-trivial number of developers do use make. See Java Build Tools: Ant vs. Maven. As for why a developer wouldn't use make: many developers either have never used make, or used it and hated it with a fire that burns hotter than a thousand suns. As such, they use alternative tools.

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • 11
    We use it, and the fire is hotter than a thousand and one suns. – reccles Feb 05 '10 at 20:19
  • 4
    @reccles: Is it just hatred toward build engineering or make itself? How would Ant, Maven, or something else would be better (ie is make a bad tool for its class)? – User1 Feb 05 '10 at 20:34
  • 8
    @User1 `make` has a lot of "features" that may have made sense when it was written, but now are more like bugs, e.g., you must use a TAB character, not spaces, in certain places. That sort of thing probably doesn't bother people who are really experienced in `make`, but it drives the rest of us nuts. – Hank Gay Feb 05 '10 at 20:44
  • 4
    @HankGuy: let your editor worry about that detail. If your editor cannot handle tab <-> space settings correctly, get a new editor and you will be much happier. But you are right in saying that many features are outdated like the way dynamic dependencies are handled (`make depend` anyone?) – D.Shawley Feb 05 '10 at 21:17
  • 1
    @D.Shawley I quite sensibly have my editor(s) configured to insert spaces when I hit the tab key, except that causes problems when I'm editing `Makefile`. If I worked with `make` often enough, I'm sure I would track down an extension/mode/what-have-you that was dedicated to editing `make` files, but why inflict that on myself if I don't have to? Besides, it was just an example of the oddities that make people want to avoid it unless they have long experience with it. – Hank Gay Feb 05 '10 at 21:36
  • 3
    @User1 It's the scale of the project we are building. We have a full time staff member maintaining the make files and build dependencies. Having used maven I found it to be more manageable. Now having said that maven wasn't perfect either. Nothing is more infuriating than trying to figure out what XML setting are needed to do a build that is slightly different then the prescribed setup. – reccles Feb 06 '10 at 18:14
  • @reccles I agree 100% about the difficulties of doing things other than the default in Maven. If I were starting a Java project from scratch, I'd definitely be looking at the newer build tools like Gant, Rake, Ivy, etc. because none of the older tools has overwhelmed me with awesomeness, to say the least. – Hank Gay Feb 06 '10 at 18:55
  • 3
    @HankGay, D.Shawleys comment still stands. Obviously your editor does not know the difference between your source files and Make files. Other editors handle this correct, e.g. Vim. It is configured like that by default, so you never have to think about it. – cmcginty Nov 09 '10 at 01:35
  • 1
    according to the link you posted "Writing build scripts in a real programming language gives Rake a huge advantage over other tools". why is that? that pretty much contradicts the principle of http://en.wikipedia.org/wiki/Convention_over_configuration. i am a happy `ant` user and one of the reasons for that is because build tasks are simplified in target tags and you don't have to do it in a programming language closer to the metal. IMO, the article is a bit too opinionated. – amphibient Feb 07 '13 at 22:25
18

All the other answers about the technical merits of each are true. Ant and Maven may be better suited to Java than make, or as Hank Gay points out, they may not :)

However, you asked if it matters that Ant and Maven are written in Java. Although on StackOverflow we don't consider such thoughts (closed! not-programming-related! etc.), OF COURSE THAT'S PART OF THE THING. On rails we use Rake, C dudes use make, and in Java we use Ant and Maven. While it's true that the Ant or Maven developers will look after the Java developer perhaps better than others, there's also another question: what do you write Ant tasks in? Java. If you're a Java developer, that's an easy fit.

So yeah, part of it is to use tools written in the language you are tooling.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 7
    Ant also arose at a time when the Java community was infatuated with XML. (Which isn't to say XML doesn't have a place.) – Laurence Gonsalves Feb 05 '10 at 20:10
  • 3
    @Laurence Gonsalves, that is *so* true. But please, we don't talk about fads here on SO :) I was teaching Java dev at the time, and EVERYTHING was XML. Now it's still XML, but no one cares. – Dan Rosenstark Feb 05 '10 at 20:50
  • 1
    The tooling comment is an interesting one. `make` comes from a UNIX background so the tooling is done by writing useful compact utilities and pipelining them together. This is why most of the stitching is done using shell commands. – D.Shawley Feb 05 '10 at 21:20
  • 2
    @D. Shawley, all true regarding `make` and small Unix utils. GIT is a child of that process too. On a personal note, I wouldn't say it's not better. But it's a huge paradigm shift for Java programmers. Ant is much more consonant with Java ways-of-thinking. – Dan Rosenstark Feb 06 '10 at 09:11
13

Ant and later Maven were designed to solve some headaches caused by Make ( while creating new ones in the process ) It is just evolution.

...Soon thereafter, several open source Java projects realized that Ant could solve the problems they had with Makefiles....

From http://ant.apache.org/faq.html#history

Whether they solve anything or just create an extra format to learn is a subjective topic. The truth is that's pretty much the history of every new invention: The creator says it solves a lot of problems and the original users say those are virtues.

The main advantage it has, is the possibility to integrate with java.

I guess a similar history would be with rake for instance.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • 4
    That's not very specific. What headaches caused by make does Maven solve? – Laurence Gonsalves Feb 05 '10 at 19:35
  • 1
    @Gonsalves: Well that's one of the subjective aspects of every new technology, the creator of the alternative says it solves a lot of problems and the creators of the replaced technology say that those are not defects but virtues and so on. I think in this particular situation was the java integration and cross compilation out of the box – OscarRyz Feb 05 '10 at 19:39
  • 2
    [Refering to your edit of answer, not your most recent comment] That still doesn't explain what problems were solved, only that the creators ant claim that problems were solved... :-/ My impression has been that Ant originally created to be a simpler alternative to Make. Over time, people found that there were things that it was missing and so they added features until Ant became just as complex as make, but with binutils built-in (make relies heavily on external tools like cp, rm, etc.), and of course there's the XML syntax. – Laurence Gonsalves Feb 05 '10 at 19:42
  • 2
    Yes, but when the best the creator of a new alternative can do is say "this solves problems the old one had" without actually saying what those problems are that's not so useful for those considering which option to use. Does Ant solve problems *I* have with make, or does it solve things I don't consider to be problems while introducing new problems for me? – Laurence Gonsalves Feb 05 '10 at 19:45
10

One of the major issues solved by Maven (and Ivy-enabled Ant setups) over make is automated dependency resolution and downloading of your dependency jars.

Ophidian
  • 9,775
  • 2
  • 29
  • 27
9

Short answer: Because make isn't good. Even on the C front you see many alternatives popping up.

Long answer: make has several flaws that make it barely suitable for compiling C, and unsuitable at all for compiling Java. You can force it to compile Java, if you want, but expect running into issues, some of which do not have a suitable solution or workaround. Here are a few:

Dependency resolution

make inherently expects files to have a tree-like dependency on each other, in which one file is the output of building several others. This already backfires in C when dealing with header files. make requires a make-specific include file to be generated to represent the dependency of a C file on its header files, so a change to the latter would cause the prior to be rebuilt. However, since the C file itself isn't recreated (merely rebuilt), make often requires specifying the target as .PHONY. Fortunately, GCC supports generating those files automatically.

In Java, dependency can be circular, and there's no tool for auto-generating class dependencies in make format. ant's Depend task can, instead, read the class file directly, determine which classes it imports, and delete the class file if any of them are out of date. Without this, any non-trivial dependency may result in you being forced to use repeated clean builds, removing any advantage of using a build tool.

Spaces in filenames

While neither Java nor C encourage using spaces in your source code filenames, in make this can be problem even if the spaces are in the file path. Consider, for example, if your source code exists in C:\My Documents\My Code\program\src. This would be enough to break make. This is because make treats filenames as strings. ant treats paths as special objects.

Scanning files for build

make requires explicitly setting which files are to be built for each target. ant allows specifying a folder which is to be auto-scanned for source files. It may seem like a minor convenience, but consider that in Java each new class requires a new file. Adding files to the project can become a big hassle fast.

And the biggest problem with make:

make is POSIX-dependent

Java's motto is "compile once run everywhere". But restricting that compilation to POSIX-based systems, in which Java support is actually the worst, is not the intention.

Build rules in make are essentially small bash scripts. Even though there is a port of make to Windows, for it to work properly, it has to be bundled with a port of bash, which includes a POSIX emulation layer for the file system.

This comes in two varieties:

  1. MSYS which tries to limit the POSIX translation to file paths, and can therefore have unpleasant gotchas when running external tools not made especially for it.

  2. cygwin which provides a complete POSIX emulation. The resulting programs, however, tend to still rely on that emulation layer.

For that reason, on Windows, the standard build tool isn't even make at all, but rather MSBuild, which is also an XML-based tool, closer in principle to ant.

By contrast, ant is built in Java, can run everywhere, and contains internal tools, called "tasks", for manipulating files and executing commands in a platform-independent way. It's sufficiently versatile that you can actually have an easier time building a C program in Windows using ant than using make.

And one last minor one:

Even C programs don't use make natively

You may not initially notice this, but C programs generally aren't shipped with a Makefile. They are shipped with a CMakeLists.txt, or a bash configuration script, which generates the actual Makefile. By contrast, the source of a Java program built using ant is shipped with an ant script pre-built. A Makefile is a product of other tools - That's how much make is unsuitable to be a build tool on its own. ant is standalone, and deals with everything you need for your Java build process, without any additional requirements or dependencies.

When you run ant on any platform, it Just Works(tm). You can't get that with make. It's incredibly platform and configuration dependent.

SlugFiller
  • 1,596
  • 12
  • 12
8

I think the most likely explanation is that several factors discouraged the use of make within the Java community in a critical period of time (the late 1990s):

  1. Because Java encompasses multiple platforms, Java programmers in general were not as adept at Unix tools as were programmers generally confined to a Unix environment (e.g., C and Perl programmers). Note that this is IN GENERAL. Without a doubt there are and were gifted Java programmers with a deep understanding of Unix.
  2. Consequently they were less adept at make and didn't know how to use make effectively.
  3. While it is possible to write a short and simple Makefile that compiles Java efficiently, extra care is required to do so in a platform-independent way.
  4. Consequently there was an appetite for an intrinsically platform-independent build tool.
  5. It was in this environment that Ant and later Maven were created.

In short, while make most certainly can be used for Java projects, there was a moment of opportunity to make it the de facto Java build tool. That moment has passed.

8

Unless I am no one the assumption no one is (mis)using make for java is wrong.

"Managing Projects with GNU Make" (available under GFDL) contains a complete chapter dedicated to using make with java projects.

As it contains a long (and hopefully fair) list of the pros and cons of using make instead of other tools you might want to take a look there. (see: http://oreilly.com/catalog/make3/book/)

mikyra
  • 10,077
  • 1
  • 40
  • 41
  • Is this an accurate summary? _make_ (in various flavors) is usable for Java, but with some pain. _Ant_ and _Maven_ (and _jmake_?) do some special things that Java needs/likes, to make Java projects faster and easier to build. They also can be used for a more platform-independent build process for non-Java projects, but are more tuned for Java. – Phil Perry Mar 06 '14 at 18:27
  • The book is from 2004 and I had a closer look at the Java chapter. It is not a trivial task and make cannot do it on its own even with a lot of scripting in the Makefile. – Thorbjørn Ravn Andersen Apr 23 '22 at 12:40
6

Make scripts tend to be inherently platform dependent. Java is supposed to be platform independent. Therefore having a build system that only works on one platform for a multi-platform sourcebase is kindof a problem.

Brian Fox
  • 6,782
  • 4
  • 27
  • 31
3

Ant is an XML configuration oriented improvement over Makefiles and Maven is a dependency build tool improvement over Ant. Some projects use all three. I think the JDK projects used to use a mix of makefiles and ant.

Berlin Brown
  • 11,504
  • 37
  • 135
  • 203
1

One big reason is that both Ant and Maven (and most java targeted SCM, CI and IDE tools) are written in java by/for java developers. This makes it simpler to integrate into your development environment and allows other tools such as the IDE and CI servers to integrate portions of the ant/maven libraries within the build/deployment infrastructure.

Chris Nava
  • 6,614
  • 3
  • 25
  • 31
1

Once upon a time I worked on a Java project that used gmake. My recollection is hazy but IIRC we had a hard time dealing with the package directory structure that javac expects. I also remember that building JAR files was a hassle unless you had something trivial.

1

ApacheAnt isn't anything like Make. Make is about describing dependencies between files, and how to build files. Ant is about dependencies between "tasks", and is really more of a way of gluing build scripts together.

it may helps you AntVsMake

Venky Vungarala
  • 1,175
  • 10
  • 6
0

Ant and Maven approach the build dependency graph and the management of it from a more 'modern' view... But as Oscar says, they created their own problems while attempting to address the old problems with make.

John Weldon
  • 39,849
  • 11
  • 94
  • 127
0

I've never used GNU Make for Java projects, but I used to use jmk. Sadly it hasn't been updated since 2002.

It had some Java-specific functionality but was small enough to include in your source tarball without significantly increasing its size.

Nowadays I just assume any Java developer I share code with has Ant installed.

finnw
  • 47,861
  • 24
  • 143
  • 221