简体   繁体   中英

Java Ant build.xml issue

I am writing a build file for its basic run, clean and compile properties. Here is what I have:

<?xml version="1.0" encoding="ISO-8859-1"?>

<project default="compile">
   <description>
      Compile and run the Java files for Lab7
   </description>

   <target name="prob1" depends='compile'>
      <java classname='prob1'>
         <classpath path='./'/>
         <arg value='Gertrude'/>
         <arg value='Justin'/>
      </java>
   </target>

   <target name="prob2" depends='compile'>
      <java classname='prob2'>
         <classpath path='./'/>
         <arg value='28'/>
      </java>
   </target>

   <target name="prob3" depends='compile'>
      <java classname='prob3'>
         <classpath path='./'/>
         <arg value='2000'/>
      </java>
   </target>

   <target name="prob4" depends='compile'>
      <java classname='prob4'>
         <classpath path='./'/>
         <arg value='2'/>
      </java>
   </target>

  <target name="compile">
    <javac srcdir='./' includeantruntime="false"/>
  </target>

  <target name="clean">
    <delete>
        <fileset dir="./">
            <include name='*.class'/>
        </fileset>
    </delete>
  </target>
</project>

I am trying to run each prob with different arguments one at a time. Like in prob1 i want to run it with the first name then again with the second name, how do I do this?

Yes something like that is possible using antlib, which offers a wide range of functionalities like for loops, if conditions and macros. You can define a macro like

<macrodef name="call-cc">
   <attribute name="target"/>
   <attribute name="param1">
   <attribute name="param2">
   <element name="yourtask">
      <java classname='$name'>
        <classpath path='./'/>
        <arg value='@{param1}'/>
        <arg value='@{param2}'/>
      </java>
   </element>

</macrodef>

and then you can call it like this

<call-cc target="unittests" param1="bla" param2="blabla"/>

You can read about antlib in the manual

As explained by @Moataz and @jheddings, the ANT macrodef is the best way to abstract these kinds of repetitive and parameterized actions.

The following working example also demonstrates some further refinements to your build, such as using properties to abstract the location of your projects files and the use of ANT paths to control runtime classpaths.

<project default="compile">

    <description>
    Example build file. Demonstrates the following
    - Properties
    - Build paths
    - Running java programs using a macrodef
    </description>

    <property name="src.dir"     location="src/main/java"/>
    <property name="build.dir"   location="build"/>
    <property name="classes.dir" location="build/classes"/>

    <path id="runtime.path">
        <pathelement location="${classes.dir}"/>
    </path>

    <macrodef name="call-prog">
        <attribute name="classname"/>
        <attribute name="arg1"/>
        <attribute name="arg2" default=""/>
        <sequential>
            <java classname='@{classname}' classpathref="runtime.path">
                <arg value='@{arg1}'/>
                <arg value='@{arg2}'/>
            </java>
        </sequential>
    </macrodef>

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

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

   <target name="prob1" depends='compile'>
        <call-prog classname="org.demo.App" arg1="Justin" arg2="Gertrude"/>
   </target>

   <target name="prob2" depends='compile'>
        <call-prog classname="org.demo.App" arg1="28"/>
   </target>

   ..
   ..   
</project>

Finally, when you've built up a store of common macodefs that you use in all your builds you can consider packaging them as an ANTlib . Best way to share build logic in ANT in my opinion. For this simple example it would be overkill.

You can do this using antcall or macrodef like so:

<target name="run-prob" depends="compile">
  <fail unless="prob-class" />
  <fail unless="prob-args" />

  <java classname="${prob-class}">
    <classpath path="./"/>
    <arg line="${prob-args}"/>
  </java>
</target>

<target name="prob1" depends="compile">
  <antcall target="run-prob">
    <param name="prob-class">prob1</param>
    <param name="prob-args">justin gertrude</param>
  </antcall>
</target>

<target name="prob2" depends="compile">
  <prob class="prob2">
    <arg value='28'/>
  </prob>
</target>

<macrodef name="prob">
  <attribute name="class" />
  <element name="args" implicit="true" />
  <sequential>
    <java classname="@{class}">
      <classpath path="./"/>
      <args />
    </java>
  </sequential>
</macrodef>

The advantage of using antcall is that you could execute calls from the command line, like so:

ant -Dprob-class=prob3 -Dprob-args=2000 run-prob

The advantage of using macrodef is that is looks a bit cleaner and more obvious in the ant file. Of course, you could also mix the two methods and call the macro from your antcall target or vice-versa.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM