Sunday, January 10, 2010

Make vs Ant

Ant was developed mainly to run java programs, so it is good at building and running java programs. But you can use the good all Make program to build and even run java programs.

Say I have an ant file that will

  1. Clean the build - ant clean

  2. Compile - ant compile

  3. Make a Jar - ant jar

  4. Run - ant run or simply ant

For this, I will only compile one java file name src/test/
<project name="HelloWorld" basedir="." default="main">

<property name="src.dir" value="src"/>

<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>

<property name="jar.dir" value="${build.dir}/jar"/>
<property name="main-class" value="test.HelloWorld"/>

<target name="clean">
<delete dir="${build.dir}"/>

<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}"/>


<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>

<jar destfile="${jar.dir}/${}.jar" basedir="${classes.dir}">
<attribute name="Main-Class" value="${main-class}"/>


<target name="run" depends="jar">

<java jar="${jar.dir}/${}.jar" fork="true"/>

<target name="clean-build" depends="clean,jar"/>

<target name="main" depends="clean,run"/>


If you want to learn what each line of this means, just follow the excellent ant tutorial at

Here is the Makefile that will do the above tasks,

run: clean jar
java -jar $(JAR_DIR)/$(PROJECT).jar

jar: $(JAR_DIR)/$(PROJECT).jar
$(JAR_DIR)/$(PROJECT).jar: $(CLASSES_DIR)/$(PACKAGE)/*.class
echo Main-Class: $(MAIN_CLASS)> mf
test -d $(JAR_DIR) | mkdir -p $(JAR_DIR)

jar cfm $@ mf -C $(CLASSES_DIR) .
compile: $(CLASSES_DIR)/$(PACKAGE)/*.class

$(CLASSES_DIR)/$(PACKAGE)/%.class: ${SRC_DIR}/$(PACKAGE)/*.java
test -d $(CLASSES_DIR) | mkdir -p $(CLASSES_DIR)

javac -sourcepath src -d ${CLASSES_DIR} $<
rm -rf build mf

You may notice I had to provide the package name to the compile command, as it doesn't have a proper wildcards to represent the jar. Similar to ant all these make tasks will execute only if it is required. i.e. for an example if all the .class files are up to date with .java it will not try to recompile it.

No comments: