Comparing ant and make as Java build tools By GusherJizmac in Technology Mon Sep 24, 2001 at 08:44:18 PM EST Tags: Software (all tags) | ||
Recently, the tool ant has come to the forefront as a build tool for Java. It usesXML build files and contains many built-in commands to make it easy to work with Java code and Java projects. There are extensionsto it to simplify developing web-based Java applications with tools like BEA Weblogic.Upon hearing about ant, many developers might first ask "Why not just use make?". This author has extensive experience with make, and withJava development, and the following article attempts to answer this question by offering a comparison of antand make as build tools, under the assumption that Java applications are being developed. The conlusion drawn is thatwhile ant has some powerful advantages, it is not as easily extensible, nor as flexible as make for most developmentsituations and there isn't a strong argument in favor of using it.
| ||
|
When my company first began serious Java application development (in the form of web-based, J2EE applications), my instinctwas to create a Makefile system to handle the compilation of Java code, as well as some basic development environment setupprocedures. This was done and included in our standard development procedure. Then, a while ago, I began reading about ant,which purported to be a better tool for automating builds in a Java environment. After reading about it, I decided toimplement a simple J2EE application (using Tomcat and Oracle) using ant, instead of my company's Makefile system. This articledocuments my experience and impressions about using ant as a Java development tool. First, however, I provide a simple overviewof the two tools. makeIf you aren't familiar with make (wherby I mean specificallyGNU Make), it is a UNIX-basedtool that reads a Makefile, which is a set of targets (with dependants) that get "made" when a target is out of date. What happens when a target is "made" is entirely up to the Makefile author. Usually, this means compiling source code intoobject or executable code, but it could be anything, including checkout of resources from source control or creatingdistributable archives. What happens during a make is typically calls to various shell commands. Since make originallywas a UNIX program, make was designed assuming the full range of UNIX commands. Make is very flexible, in that you have a wide latitude to define variables, manipulate those variables and pass them to any command available on your system. A simple Makefile might look like this: ant is part of the Apache Jakarta project. Ant has a similar concept to makein terms of targets and dependants, but ant doesn't assume that targets and dependants are files by default. Ant also doesn'tassume that the purpose of dependants are to bring targets up to date, it's merely a simple dependancy. Ant alsomakes use of built-in commands to implement targets, rather than assuming shell commands are available (although you canexecute arbitrary shell commands). This makes ant run on any Java-supported platform.Many of the commands are specific to compiling or working with Java code. Since ant iswritten in Java, it has the added feature of running the Java compiler from within itself, which ends up making compilationquite fast. Ant relies on this fact, even, because the typical compilation target results in compiling every singlejava source it can find each time you run it. For users of make, this may sound horrendous, but the compilation step (for me)took the same amount of time to compile one class as it did for 50. Ant also uses an XML-based syntax for creating the buildfiles (although it is not strict XML in the sense that a DTDfor all of ant cannot easily be made, and the syntax allows for a lot more flexibility than you might expectin an XML file). Following is an example: I have many years of experience with GNU make, and worked on our company's Makefile system. I'm familiar with makespros and cons, especially with respect to Java development, which I've been doing steadily for the past 3 years. Thisis obviously going to make me a little biased against ant, because I know much more about make. However, my first experiencewith make was to create platform independant (UNIX, Windows, OS/2) build-files for creating shared libraries, so I rememberwhat it was like to have to learn a wierd tool and get it to work in a general sense. Also, creating shared libraries (at leastat the time) was not the trivial task that compilation is, and so I needed to learn make quite well to get it working right.My hope was that this experience would allow me to be objective with respect to ant. I downloaded and installed ant, and set it up as my compilation tool for my project. Our company's Makefile system does the following things for the average developer:
Once I had my ant file, I was off and developing and didn't really notice much of a difference between using make. With bothsystems I simply type a 'make' or 'ant' and my code compiles. The first time I build, my jars get checked out. Comparison of the two ToolsMy comparison will take two parts: The first will focus on the differences with using each tool for my specific task, namely writing a Java-based web application. The second part will discuss my more general impressions of ant vs. make as build tools,apart from my specific project (but still within the realm of writing Java applications). Using ant on my J2EE Web ApplicationBoy does ant compile fast! The biggest difference I noticed was the speed at which ant compiled. I was quite distressed whilecreating my buildfile that ant would be compiling all the code every time, but after the first compile, I had to change toby output directory to verify that the classes were actually there, because I couldn't believe it had compiledall those sources so quickly. From a pure user perspective, however, ant didn't integrate with vim out of the box. With make (more specifically javac), you can have vim run your build and thenstep you to each line with syntax errors, because vim can parse the output of javac. Since ant reformats javac's output, vim wasn't able to do this. I assume that some tweaking with vim could alleviate this, but I didn't look into it. Thereformatting (which amounts to indenting javac's output and prepending each line with a flag indicating that the output came from javac)made it harder to read the output of javac (probably because I was used to reading it direct from javac). I'm not sureif there is an option to disable this, but I couldn't find it. I did have a somewhat difficult time getting ant to checkout my jar files only if they didn't exist. It required using the"uptodate" builtin command and creating a timestamped file. Perhaps there is a better way to do it, but the documentation wasn't clear. Accomplishing this in make was quite simple. I could make a target named for each jar (make allows for creatingmake-time targets dynamically, wheras ant can only have static targets defined at buildfile-creation), and then the commandfor that target is to check it out of CVS. The effect is that the checkout only happens when the file doesn't exist. Using ant to make a full-blown development systemMy company's Makefile system supports (or will support) additional functionality, including tagging source files, committingclass files for distribution, running checks on source files before tagging, and other things needed for a sophisticateddevelopment environment. Implementing these is fairly straightfoward, because make and shell programming is very similarto LISP programming, where code and data are interchangeable, and there is a high degree of dynamicism. This allows fora general-purpose Makefile that needs to know little or nothing about the files on which it operates. My checkout example aboveindicates what I mean. A better example is if I want to make a "tag" target, that tags all source files as "stage", so they canbe pushed to a staging environment. Before tagging, I need to make sure that each file has been committed to CVS.I can't imagine how to do this with ant without writing a builtin command or shell script (or, worse yet, hard-coding thejava source file names in the buildfile). I'm sure it can be done, but in make, it is very simple. Since you can construct targets and commands dynamically at make-time, I can write a generic make target that does this check andfails if any file isn't committed to CVS. Being able to do this easily is, in my opinion, is a pretty basic feature that a build system should have. Ant could supportthis with a more robust variable assignment mecahnism and with a way to create dynamic targets, or a way to treat propertyvalues as lists for iteration. Integrating ant with other systems also seems to be quite cumbersome. You bascially have two choices to integrate antwith other systems (e.g. clear case if you don't use CVS): writing a java class, or using the <Exec...> builtin command.Writing a Java class seems quite cumbersome, and often Java is not suited to executing system-level tasks involved with running command-line tools typically provided by configuration management tool vendors. Using the builtin command is alsosomewhat cumbersome, as it is not as flexible as just running the command through a shell. You are bascially specifyingall the parameters to pass to the java method that executes external commands, and as mentioned before, this is not always appropriate for executing command line tasks. Even if this is done (as many have done with providing builtin commands for BEA Weblogic), your commands won't work ifthe interface changes. For example, BEA radically changed their EJB deployment procedure between version 4.5 and 5.1. An antbuiltin task would have to be rewritten, recompiled and redistributed to accomodate this. Another example is the change betweenjavadoc for java 1.1 and for java2. If such a change occurs again, ant will not easily be able to take advantage of thebetter featureset. This is because with ant, you would have to reimplement your builtin task. With make, you can easilychange your Makefile. Additionally, ant doesn't have nearly the documentation, developer knowledge, or proven value that make has. I know that whateverneeds my organization will have (including developing non-Java applications), make will be able to support them. I cannot say thesame for ant. That said, ant has some good things going for it. For one, if you are a developer that knows neither make nor ant, you willbe up and compiling javacode a lot faster with ant. ant essentially provides a builtin Makefile for compiling and runningJava code, and that's pretty good. Make was designed with compiling C code in mind, and getting it to work with Javarequires some non-obvious make coding that does require some prioir knowledge of make to do. Additionally, ant compiles incredibly fast. While I didn't try ant on a real sized project (e.g. 1000s of classes), for my one-person development effort, it wasmuch faster than make (of course, you could have make call ant for compiling). Finally, ant is truely cross-platform. Ant will run on Max OS 9 and VMS. Make will not (without additional software installed). In make's favor, I should point out that Cygwin provides free versions ofmake and all other GNU tools for windows, including bash, and that the vast amount of Java coders in the world are usingeither UNIX or Windows. So, for most Java coders, make is platform independant (although it does require an extra packagefor Windows). SummaryOK, I don't want to fill this article up with anecdotal evidence or, worse yet, ranting. So, I'll try to capture my thoughtsin the following pros/cons table:
I've also come up with the following, that I believe characterizes the situations in which ant or make are warranted:
While ant is an interesting tool, I don't see it as a heavy-duty build tool for Java development. Furthermore, ant's overalldesign seems to be the opposite of make. ant tries to be all things to all people and reimplements functionality that's availableand proven on UNIX. ant tries to have a command for everything. Looking at the list of builtin commands one can't help butget the feeling that ant was made by someone who did not understand make and didn't want to learn it, and slowly realized that there's a lot of functionality a build tool will need if it cannot rely on the UNIX command set. Comments on the ant homepage supportthis (e.g. "Makefiles are inherently evil") to an extent. make, on the other hand, is a framework for running arbitrary commands.True, make requires UNIX to be useful, but UNIX commands are available on almost all platforms where Java is beingdeveloped. Yes, make can be hard to learn, and it does have it's quirks, but it works and it works well for almost anysituation. The make code to implementjava compilation (ant's biggest draw, IMO) is quite simple (even if non-trival to derive). This is one time only operation.I think ant is great if you are a single developer who can't afford an IDE and don't want to mess with make. With ant, you'llbe up and running quickly. For a Release Engineer or Lead Programmer on a project, though, make is a tried and testedtool that works just as well with Java as it does with C, and you know that it will do whatever you want it to do. References
I know that many of you who prefer ant will want to put me in my place and point out that because I don't know ant very well, I willbe biased towards make. Aside from requestng that you post constructive comments on this issue instead of flames, I wouldask that you keep the following in mind:
|
http://www.kuro5hin.org/story/2001/9/24/155525/350