Make vs Ant
By Adrian Sutton
ONLamp.com has an article comparing alternatives to make (heavily biased towards make). In fact it only looks at ant and IDEs, I assume because it’s an extract from a book about make. It also focuses very heavily on Java development which is a real shame because Java development is the one area that make is almost never a good option.
The main reason that make isn’t a good option for Java despite it’s technical abilities is that every Java developer is expected to know at least a little about ant – a huge number won’t know anything about make and very few Java developers who work on Windows will have it installed. Every self-respecting Java developer will have ant installed and configured on their machines. It’s just the done thing when you work with Java. No self respecting C programmer would develop on a machine without make, no self-respecting Java programmer develops on a machine without ant.
Java IDEs are expected to have support for ant built-in and most do it really well. Few Java IDEs have support for make even at the primitive level of syntax highlighting the build file.
To pick on a few specific points:
Although Ant has found wide acceptance in the Java community, it is still relatively unknown elsewhere.
That probably shouldn’t be all that surprising considering ant was designed to work with Java. It’s also not important since if you’re developing a project in Java then anyone who should need to understand your build process should be another Java programmer or at least part of the Java community. Either way, it’s a pretty safe bet that they’ll also know ant. When working with other languages you have to change modes to that language both in terms of syntax and way of doing things. The best editor, coding style, documentation mechanism, design philosophy and build tool will all change when you change languages.
The choice of XML as the description language is appropriate for a Java-based tool.
Glad we’ve got that settled then. ant is a Java-based tool, it’s designed to be used by Java developers for Java programs.
But XML is not particularly pleasant to write or to read (for many). Good XML editors can be difficult to find and often do not integrate well with existing tools (either my integrated development environment includes a good XML editor or I must leave my IDE and find a separate tool).
Ant build files have much better support in Java IDEs than make files. They integrate much better within Java tools than make files do – there’s no reason to leave your IDE, I certainly don’t. If you really want good tool support, there are a number of programs around that specialize in making ant files easier to write – in effect an ant IDE.
When writing Ant build files you must contend with another layer of indirection. The Ant mkdir task does not invoke the underlying mkdir program for your system. Instead, it executes the Java mkdir() method of the java.io.File class. This may or may not do what you expect.
This one I just can’t believe I’m reading… The ant mkdir task is guaranteed to always act the same way on every platform because the java.io.File.mkdir() method is also guaranteed to work in that way. On the other hand, the mkdir program installed on a given system is not guaranteed to do anything. While it’s generally a safe assumption that mkdir will create a directory it may not. It may or may not automatically create parent directories and it may or may not accept any given set of command line options. While it is true that the POSIX standard defines the behavior of mkdir, there are a lot of extensions to it and not all OSs necessarily adhere to the POSIX standard (plus mkdir is the simplest example, there are plenty of other, more complex tasks that ant standardizes which aren’t standardized using the command line tools). There are many reasons to argue against abstraction layers but consistency is definitely not one of them – it is in fact one of the main reasons you use abstraction layers in the first place.
Although Ant is certainly portable, so is make. Writing portable makefiles, like writing portable Ant files, requires experience and knowledge.
Actually, writing portable ant files is really quite straight forward – it takes care of all the main gotchas like path separators and file separators automatically and its abstraction layers remove the need for a huge number of assumptions. When you get into more advanced build processes you can run into platform specifics you need to be aware of but certainly no more so than with make (in fact the same platform specifics will almost certainly affect make). So yes make can be portable but ant achieves it more easily by using abstraction layers and a few neat little hacks.
Also, basic operations like setting the execution bit on a file cannot be performed from the Java API; an external program must be used.
Not from the standard Java API no, but it is within the standard ant API. You’ll want to look at the chmod task.
The Ant tool does not explain precisely what it is doing. Since Ant tasks are not generally implemented by executing shell commands, the Ant tool has a difficult time displaying its actions. Typically, the display consists of natural language prose from print statements added by the task author. These print statements cannot be executed by a user from a shell. In contrast, the lines echoed by make are usually command lines that a user can copy and paste into a shell for re-execution.
I would have considered this a major plus for ant but it is subjective. The main question I’d ask is: have you ever watched a make based build process and been able to read and understand all the output it spits out? I certainly haven’t – it’s typically a huge bunch of very long command line statements that I can’t even start to understand before it scrolls off screen. With ant builds on the other hand all that’s removed and I can see just want the build designer wanted to output – ie: the important stuff.
Last and most importantly, Ant shifts the build paradigm from a scripted to a non-scripted programming language. Ant tasks are written in Java. If a task does not exist or does not do what you want it to do, you must either write your own task in Java or use the exec task. (Of course, if you use the exec task often, you would do far better to simply use make with its macros, functions, and more compact syntax.)
In some six years of using ant now I’ve only ever had to write two ant tasks – one to automate the creation of a WISE build script and one to allow proguard configurations to be generated from filesets. They took about 5 minutes each to develop. While I’m sure it’s possible, I don’t know how to achieve either task at all within make. At the very least I would have wound up writing a separate shell script or more likely a separate perl script to achieve the functionality. It would have also taken me much longer to hunt down the right syntax for what I wanted to do. With the ant tasks however most of my work was already done – the builtin fileset task for ant could be reused to search out the files I needed and feed them into my task as required (while resolving platform dependent file separators and handling quotes and other special characters). Scripting languages are great and all, but there’s definitely something to be said for using a well thought-out library that was designed for the situation and is familiar – not to mention the benefits of not having to know a second programming language to work with the build process.
All that said though, don’t think that I don’t like make – I definitely do. I use it as my build tool of choice for pretty much anything but Java projects including when I’m writing musicals. make is a fantastic tool, but ant is the standard for Java, it was designed to work with Java and no matter how much you might be obsessed with make, ant is the better tool for the vast majority of Java projects.
Now if you were to compare maven and ant you might have a more interesting discussion.