Reusable Ant Task: Compile Flex If Source Was Updated

I’m working on a project that compiles 11 Flex applications. My Ant build file was getting pretty messy and I was continually commenting out files that I didn’t want to build. By using an Ant macro and some uptodate trickery I was able to significantly decrease my build times when I am only updating files for a single application. The macro also helped to make the build much more manageable.

You can find the whole build here:
http://flexapps.cvs.sourceforge.net/flexapps/census/build.xml?revision=1.14&view=markup

First I setup a macro:

  <macrodef name="compileflex">
    <attribute name="src"/>
    <attribute name="dest"/>
    <element name="uptodatefiles" optional="true"/>
    <sequential>
      <uptodate property="@{src}.uptodate" targetfile="@{dest}">
        <srcfiles file="@{src}"/>
        <srcfiles file="build/base.swc"/>
        <srcfiles file="${src.flex.dir}/flex.css"/>
        <uptodatefiles/>
      </uptodate>
      <antcall target="compilemxml">
        <param name="src" value="@{src}"/>
        <param name="dest" value="@{dest}"/>
      </antcall>
    </sequential>
  </macrodef>

The macro calls the “compilemxml” target when the swf is not up-to-date. The compilemxml target is a pretty plain Ant target:

  <target name="compilemxml" unless="${src}.uptodate">
    <java jar="${flex.sdk.dir}/lib/mxmlc.jar" fork="true" maxmemory="128m">
      <jvmarg value="-Dapplication.home=${flex.sdk.dir}"/>
      <arg value="-external-library-path+=build/base.swc"/>
      <arg value="-runtime-shared-libraries=base.swf"/>
      <arg value="-licenses.license" />
      <arg value="charting"/>
      <arg value="${charting}"/>
      <arg value="-compiler.services" />
      <arg value="etc/flex/services-config.xml" />
      <arg value="-compiler.context-root" />
      <arg value="/census" />
      <arg value="-file-specs" />
      <arg value="${src}" />
      <arg value="-output" />
      <arg value="${dest}" />
    </java>
  </target>

The macro is simple to use:

  <compileflex src="${src.flex.dir}/flex_soap_as.mxml" dest="build/census.war/flex_soap_as.swf"/>

In that instance, the uptodate check will check the src file, the swc, and the css to see if they are uptodate. If any of them were updated more recently than the swf, then compilemxml will be called. If you have other unique files which need to also be checked, you can pass those in a uptodatefiles element:

  <compileflex src="${src.flex.dir}/index.mxml" dest="build/census.war/index.swf">
      <uptodatefiles>
        <srcfiles file="${src.flex.dir}/Test.as"/>
        <srcfiles dir="${src.flex.dir}" includes="Wizard*"/>
        <srcfiles file="${src.flex.dir}/IFrame.mxml"/>
        <srcfiles file="${src.flex.dir}/BarItemRenderer.as"/>
        <srcfiles file="${src.flex.dir}/ChartBackgroundFill.as"/>
        <srcfiles file="${src.flex.dir}/ChartLegendCombo.mxml"/>
        <srcfiles file="${src.flex.dir}/CustomAxisRenderer.mxml"/>
        <srcfiles file="${src.flex.dir}/DataGridHeaderSeparator.as"/>
      </uptodatefiles>
    </compileflex>

The one kinda-hack I had to do to make this work, was to make sure that the property which gets set by the uptodate task is unique for each time compileflex is called. I used the ${src}.uptodate property name to accomplish this.

This build is pretty catered to my needs, however, you should be able to easily customize it to fit your needs. I hope you find this useful. Let me know if you have any questions!

This entry was posted in Flex, Java. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Shailesh Mangal

    James,

    I have been looking for maven based build solution for Flex. This helps me build both my flex and server side java with one tool. Wondering what are your thoughts on the same.

    -Shailesh

  • http://www.jamesward.org James Ward

    I have heard of someone working on a Flex Maven plugin. But I don’t know if it was ever released. You might want to try searching the flexcoders Yahoo! group archive.

    -James

  • Rob Seegel

    Simple and effective. When I use it, I think I’d do one of the following:

    Move the code in compilexml target into the compileflex macro, where the antcall is, but nest it below an if task using antcontrib.
    Create a custom ant task that uses the Java task internally, and handles the dependency checking.

    Either one of these would make your script even more efficient without sacrificing readability (IMO) and eliminate the cost of reparsing your script each time antcall is used. Thanks for sharing it.

  • http://www.jamesward.org James Ward

    Thanks Rob. Good feedback. When I will get some free time I’ll see if I can make those changes.

  • Calvin

    Have you tried using the element for compiling your mxml files? Might be a better solution than creating a new target and using element to build it.

    Example:

    Anyway, just FYI. We are considering your updateFile solution.

    Thanks,
    Calvin