ant multiple source directories with copied resources

ant
21,367

Solution 1

I'm not sure of a way to do it with built-in Ant tasks but you could use an ant-contrib <for> task

<path id="src.path">
  <pathelement location="src" />
  <pathelement location="src-gen" />
</path>

<target name="build">
    <javac destdir="bin">
        <src refid="src.path" />
    </javac>
    <for param="dir">
        <path refid="src.path" />
        <sequential>
            <copy includeemptydirs="false" todir="bin">
                <fileset dir="@{dir}">
                    <exclude name="**/*.java" />
                </fileset>
            </copy>
        </sequential>
    </for>
    <jar destfile="dist/foo.jar" basedir="bin"/>
</target>

Solution 2

Normally, you simply list them all together:

<javac destdir="bin">
    <src path="${src.dir}"/>
    <src path="${src2.dir}"/>
    <src path="${src3.dir}"/>
</javac>

You can try the <sourcepath/> attribute. I've never used it, but I believe you can use it to define a path of various source files, and use that:

<path id="source.path">
    <pathelement path="${src.dir}"/>
    <pathelement path="${src2.dir}"/>
    <pathelement path="${src4.dir}"/>
</path>

<javac destdir="bin">
    srcpathref="source.path"/>

The first will work, but not 100% sure about the second.

Solution 3

The simple solution is to just specify multiple filesets, in the same manner as the javac task supports multiple "src" attributes:

   <target name="build" depends="init" description="Create the package">
      <javac destdir="${classes.dir}" includeantruntime="false">
         <src path="src/main1/java"/>
         <src path="src/main2/java"/>
      </javac>

      <copy todir="${classes.dir}" includeemptydirs="false">
         <fileset dir="src/main1" excludes="**/*.java"/>
         <fileset dir="src/main2" excludes="**/*.java"/>
         <flattenmapper/>
      </copy>
   </target>

This of course assumes that the number of source code locations is fixed, which is not unreasonable to expect.

If you want to drive this using a list property you must resort to embedding a script within your build to process this list (I can't endorse ant-contrib):

<project name="demo" default="build">

   <property name="src.dirs"    value="src/main1,src/main2"/>
   <property name="build.dir"   location="build"/>
   <property name="classes.dir" location="${build.dir}/classes"/>

    <target name="bootstrap">
        <mkdir dir="${user.home}/.ant/lib"/>
        <get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.6/groovy-all-2.1.6.jar"/>
    </target>

   <target name="init">
      <mkdir dir="${classes.dir}"/>
   </target>

   <target name="build" depends="init" description="Create the package">
      <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>

      <groovy>
         def srcDirs = properties["src.dirs"].split(",")

         ant.javac(destdir:properties["classes.dir"], includeantruntime:false) {
            srcDirs.each {
               src(path:"${it}/java")
            }
         }

         ant.copy(todir:properties["classes.dir"], includeemptydirs:false) {
            srcDirs.each {
               fileset(dir:it, excludes:"**/*.java")
            }
            flattenmapper()
         }
      </groovy>
   </target>

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

</project>

Notes:

  • Compare the "build" targets. You'll notice that the groovy solution calls ANT in the same manner. This is why I really like groovy's integration with ANT.
  • Example also includes a "bootstrap" target to download the groovy jar dependency from Maven Central. You could alternatively use ivy to manage your build's dependencies.
Share:
21,367
Marcin Wisnicki
Author by

Marcin Wisnicki

Updated on January 04, 2020

Comments

  • Marcin Wisnicki
    Marcin Wisnicki over 4 years

    Consider minimal build.xml fragment which builds jar from sources and includes all non-java resources:

    <property name="src.dir" value="src" />
    
    <target name="build">
        <javac destdir="bin">
            <src path="${src.dir}" />
        </javac>
        <copy includeemptydirs="false" todir="bin">
            <fileset dir="${src.dir}">
                <exclude name="**/*.java" />
            </fileset>
        </copy>
        <jar destfile="dist/foo.jar" basedir="bin"/>
    </target>
    

    Now imagine that I need to support a list of source directories:

    <property name="src.dirs" value="src;src-gen" />
    

    How can i modify above script to make it happen ? javac will happily take list of directories but for copy I need to transform string into list of filesets with exclusions or find some other way.