views:

565

answers:

3

I want to build an ant script that does exactly the same compilation actions on a Flash Builder 4 (Gumbo) project as the Project->Export Release Build... menu item does. My ant-fu is reasonably strong, that's not the issue, but rather I'm not sure exactly what that entry is doing.

Some details:

  • I'll be using the 3.x SDK (say, 3.2 for the sake of specificity) to build this.
  • I'll be building on a Mac, and I can happily use ant, make, or some weird shell script stuff if that's the way you roll.
  • Any useful optimizations you can suggest will be welcome.
  • The project contains a few assets, MXML and actionscript source, and a couple of .swcs that are built into the project (not RSL'd)

Can someone provide an ant build.xml or makefle that they use to build a release .swf file from a similar Flex project?

A: 

I had some issues with the Adobe Flex Ant tasks a while back, so I ended up using an exec call to the mxmlc compiler with a boatload of options and we've just built upon it from there. There are a few nagging doubts that what I do with the build.xml is not exactly the same that FB3 (what we have) does, but this might be enough to help get you started... you say your ant-fu is reasonably strong, so I'll skip over most of my build file and let you piece together the pieces.

<!--flex stuff-->
<property name="dir.flex.sdk"                 value="${system.build.flex.sdk}"/>
<property name="dir.flex.home"                value="${dir.abc}/flex/sdks/${dir.flex.sdk}"/>
<property name="dir.flex.projects"            value="${dir.abcd_plat}/webapp/flexprojects/"/>
<property name="dir.modules"                  value="${dir.war}/modules/"/>
<property name="FLEX_HOME"                    value="${dir.flex.home}"/>
<property name="APP_ROOT"                     value="${dir.war}"/>
<property name="flexc.exe"                    value="This should be set in the build-${os.family}.xml file"/>
<property name="asdoc.exe"                    value="This should be set in the build-${os.family}.xml file"/>
<property name="optimizer.exe"                value="This should be set in the build-${os.family}.xml file"/>
<property name="flex.mxmlc"                   value="${dir.flex.home}/bin/${flexc.exe}"/>
<property name="flex.compc"                   value="${dir.flex.home}/bin/${compc.exe}"/>
<property name="flex.asdoc"                   value="${dir.flex.home}/bin/${asdoc.exe}"/>
<property name="flex.optimizer"               value="${dir.flex.home}/bin/${optimizer.exe}"/>
<property name="flex.options.warnings"        value="false"/>
<!--options that are used in common for compiling all .swc and .swf files-->
<property name="flex.meta.1"                  value="-creator 'MyCorp.' -publisher 'MyCorp.'"/>
<property name="flex.meta.2"                  value="-title MegaProduct -description http://ourURL.com"/&gt;
<property name="flex.meta.props"              value="${flex.meta.1} ${flex.meta.2}"/>
<property name="debug.options"                value="-optimize=true -debug=false"/>
<property name="common.flex"                  value="-as3 -target-player=9.0.124 -warnings=${flex.options.warnings}"/>
<property name="license.flex3"                value="(put your own here)"/>
<property name="common.fixed"                 value="-license=flexbuilder3,${license.flex3} -sp ${dir.war} -library-path+=${dir.webinf}/lib"/>
<property name="flex.common.args"             value="${flex.meta.props} ${debug.options} ${common.flex} ${common.fixed}"/>
<!--this is currently unused, but if we make a debug version, this can be set to make a separate output file-->
<property name="swf.suffix"                   value=""/>

<!--=================================================================================
    MACRODEFs
-->
<!--this is used to extract .swf files from 3rd party .swc libraries, in order to do dynamic linking-->
<macrodef name="extract-flex-lib" description="For modularizing flex compilation">
    <attribute name="swc-lib" default="NOT SET"/>

    <sequential>
        <!--use a copy task - it can get the file out of the zip, and rename it at the same time-->
        <copy todir="${dir.war}" preservelastmodified="true">
            <zipfileset src="${dir.webinf}/lib/@{swc-lib}.swc">
                <patternset>
                    <include name="library.swf"/>
                </patternset>
            </zipfileset>
            <mapper type="glob" from="library.swf" to="@{swc-lib}-debug.swf"/>
        </copy>
        <!--run the flex optimizer on the extracted .swf - note the as3 metadata that's kept, it's required-->
        <exec executable="${flex.optimizer}" failonerror="true">
            <arg line="-keep-as3-metadata='Bindable,Managed,ChangeEvent,NonCommittingChangeEvent,Transient'"/>
            <arg line="-input @{swc-lib}-debug.swf -output @{swc-lib}.swf"/>
        </exec>
        <!--delete the unoptimzed swf, don't need it anymore-->
        <delete file="@{swc-lib}-debug.swf"/>
    </sequential>
</macrodef>

<!--this is used to compile our internal flex modules-->
<macrodef name="flexc-mxml" description="For building the flex modules during flex compilation">
    <attribute name="name"        default=""/>
    <attribute name="mxml.args"   default="${flex.common.args} ${module.args}"/>
    <attribute name="sourcePath"  default=""/>
    <attribute name="destPath"    default=""/>

    <sequential>
        <echo message="  Compiling with mxmlc: @{name}"/>
        <exec executable="${flex.mxmlc}" failonerror="true">
            <arg line="@{mxml.args} @{sourcePath} -output @{destPath}"/>
        </exec>
    </sequential>
</macrodef>

<!--this is used to compile our subprojects under abcd_plat/webapp/flexprojects-->
<macrodef name="flexc-subproject" description="For compiling the flex subprojects into .swc files">
    <attribute name="name"        default=""/>
    <attribute name="xtra.args"   default=""/>

    <sequential>
        <echo/>
        <echo message=" Compiling subproject: @{name}"/>
        <xslt in="${dir.flex.projects}/@{name}/.flexLibProperties" out="${dir.flex.projects}/@{name}/src/manifest.xml" style="${dir.war}/build-manifest-style.xsl"/>
        <exec executable="${flex.compc}" failonerror="true">
            <arg line="-load-config+=${dir.flex.projects}/@{name}/include-files.xml"/>
            <arg line="-namespace http://@{name}.ourURL.com ${dir.flex.projects}/@{name}/src/manifest.xml"/>
            <arg line="-include-namespaces http://@{name}.ourURL.com @{xtra.args}"/>
            <arg line="-library-path+=${dir.webinf}/lib -sp ${dir.flex.projects}/@{name}/src -output ${dir.webinf}/lib/@{name}.swc"/>
        </exec>
    </sequential>
</macrodef>


<!--=================================================================================
    This is where all the compilation is done.  The actual work is split among
    several different tasks in order to organize them better.

    This target uses the html-wrapper task defined in flexTasks.jar - see taskdef above.
-->
<target name="flexcompile" depends="flexc-modularize" description="Builds the Flex sources" unless="flexc.notRequired.main">
    <echo message="Compiling MegaProduct Flex application on OS family: ${os.family}"/>
    <echo message="   mxmlc is: ${flex.mxmlc}"/>
    <echo message="   compc is: ${flex.compc}"/>

    <!--compile flex sub-projects first (main application depends on these extra libraries)-->
    <antcall target="flexc-projects"/>

    <!--compile the main MegaProduct application-->
    <antcall target="flexc-main"/>

    <!--compile the foobar stuff, which link against the main app.  these foorbars are modules
     inside a subproject, so they are handled differently from other flex projects and modules-->
    <antcall target="flexc-foorbars"/>

    <!--generate the html wrapper for the .swf-->
    <html-wrapper title="MyCorp MegaProduct" application="app_name" swf="app_name" history="false" template="express-installation"/>
</target>

<target name="flexc-projects">
    <!--the name must match the name of the folder exactly, also they are not in parallel as some depend on others-->
    <flexc-subproject name="Dockable"/>
    <flexc-subproject name="EXRibbon" xtra.args="-source-path+=${dir.flex.projects}/EXRibbon/locale/en_US/"/>
    <!--note: MPLib does some extra stuff with the image dir in order to link against images correctly-->
    <copy todir="${dir.flex.projects}/MPLib/src/image"><fileset dir="${dir.war}/image"/></copy>
    <flexc-subproject name="MPLib"/>
    <delete dir="${dir.flex.projects}/MPLib/src/image"/>
</target>

<target name="flexc-main">
    <!--the link report is used to create the symbols in the main swf, and modules link against it-->
    <property name="link.report"   value="${dir.war}/abc_link_report.xml"/>

    <!--modular.args is set in flexc-modularize.  If not set, this sets it to an empty property-->
    <property name="modular.args"  value=""/>

    <!--set up options specific for the main part and for the modules-->
    <property name="main.args"     value="-link-report=${link.report} ${modular.args}"/>
    <property name="module.args"   value="-load-externs=${link.report}"/>

    <!--compile abc_flex.mxml here-->
    <echo message="Compiling abc_flex application, sub-applications and modules..."/>
    <echo/>
    <flexc-mxml name="abc_flex" mxml.args="${flex.common.args} ${main.args}"
            sourcePath="${dir.war}/abc_flex.mxml" destPath="${dir.war}/abc_flex${swf.suffix}.swf"/>

    <!--compile MPMainSubApplication.mxml sub-application here-->
    <flexc-mxml name="MPMainSubApplication" mxml.args="${flex.common.args} ${main.args}"
            sourcePath="${dir.war}/MPMainSubApplication.mxml" destPath="${dir.war}/MPMainSubApplication.swf"/>

    <!--compile internal modules next - just add new modules to the list here -->
    <parallel>   <!--do in parallel - it goes faster and they don't depend on each other-->
        <property name="dir.module.src" value="${dir.war}/module/"/>
        <flexc-mxml name="module1"      sourcePath="${dir.module.src}/editor/Editor.mxml"          destPath="${dir.module.src}/editor/Editor.swf"          />
        <flexc-mxml name="RunModule"   sourcePath="${dir.module.src}/run/RunModule.mxml"          destPath="${dir.module.src}/run/RunModule.swf"          />
        <!--<flexc-mxml name="JobManager"  sourcePath="${dir.module.src}/jobmanager/JobManager.mxml"  destPath="${dir.module.src}/jobmanager/JobManager.swf"  />-->
        <flexc-mxml name="Editor2"        sourcePath="${dir.module.src}/edit/Editor.mxml"                destPath="${dir.module.src}/edit/Editor.swf"                />
    </parallel>
</target>

NOTES:

I'm not sure if it's a good idea or not, but we just put the .swc files to include with our Java middle tier libs in WEB-INF/lib, so whenever we add a new flex lib to source control we just drop it in there. The compilation is done in the macros, and most of the parameters are defined as properties in the top section. The targets split the work because our app is quite large; you probably don't need those but it's an example of doing modules within sub-projects plus the link-report and follows the way a sub-project is referenced from the main application (I think). Our build machine is linux, so that's why the flexc.exe property (and others) are defined that way - it gets set at runtime. Names have been munged by hand for this answer, so please double-check for typos if you cut-n-paste anything.

Also, the incremental compilation isn't actually used; it seems to be buggy. Ditto for the modularization stuff, so I didn't include that target.

I built all of this myself so I'm rather proud of it, but if there's anything that looks iffy or smells bad, please feel free to let me know. Thanks!

weiji
+1  A: 

One quick way to know the compiler options is to add this tag into your compiler options:

-dump-config your/drive/to/store/the/xmlfile.xml

This will output the entire ant compiler options and you can copy off the parts you want to keep.

jonbcampos
A: 

HellFire Compiler Daemon (http://bytecode-workshop.com/) can generate build.xml directly from the compiler calls made by Flex/Flash Builder. That means your ant script produces SWCs and SWFs based on the exact same set of compiler settings that you set in Flex/Flash Builder.

Also, check out this blog:

http://stopcoding.wordpress.com/2010/01/15/ant-tasks-for-hfcd-now-available-2/

Clement