Adam Howitt's Blog

Nov 07
2006

Use eclipse, ant and cfcompile.bat to precompile your code

I am the kind of programmer who likes to code a little, test a little.  Sometimes, I code a little, test a little and realize that I have misspelled a tagname or goofed up something incredibly obvious!  

If you use CFEclipse there is a utility built into Eclipse called Ant a tool that ships with ColdFusion called cfcompile.bat you can use to help.  cfcompile.bat is a pre-compiler shipped with ColdFusion which can be used to check your code for compilation errors and ultimately compile java bytecode versions of your code for deployment.  The advantages of this java bytecode are that it

  • avoids the first time compilation hit
  • adds a simple layer of protection to your code

Ant is a build/deployment tool by Apache to automate the routine tasks of programming to make programming and specifically deployment of code simpler.  You can use Ant to
build jar files of your applications for deployment
make copies of framework files and prompt you for the configuration options so you don't have to maintain a checklist of configuration options
move your code to production from the filesystem or your source control package and execute sql scripts

Ant ships with Eclipse and can be programmed to leverage the cfcompile.bat tool in such a way that each time you save a ColdFusion file, it will run the file through the compiler to check for simple errors.

This article will go through the steps of configuring the cfcompile.bat file for your development environment, configuring the ANT script to call cfcompile.bat, associating an ant script with a ColdFusion project for manual compilation and finally automating the process.  The instructions below assume a windows environment but everything presented here is possible in any environment capable of running Eclipse and Coldfusion - the caveat being that you will need to change windows specific commands and filepaths to match your environment.  I'll provide some links at the end for the sites I used to get this working which may help you.

Configuring CFCompile.bat
This step depends on the version you are using.  Standard typically sets the parameters required to run cfcompile without any intervention from you.

1. Find cfcompile.bat.  On standard CF it is under your installation directory/bin. The j2ee version is trickier as the variables are usually blank in the file and if you try to execute it without changing anything it will tell you what you need to fix. For a J2EE server it is likely to be under
C:\JRun4\servers\[servername]\SERVER-INF\temp\[cfusion.warsomething]\WEB-INF\cfusion\bin
2. open cfcompile.bat in a text editor and find the lines
    set CFUSION_HOME=
    set J2EEJAR=
    set WEBINF=
   and set them to the full paths e.g.
    set CFUSION_HOME=C:\JRun4\servers\wjrLocal\SERVER-INF\temp\cfusion.war1118372559\WEB-INF\cfusion
    set J2EEJAR=C:\JRun4\lib\jrun.jar
    set WEBINF=C:\JRun4\servers\wjrLocal\SERVER-INF\temp\cfusion.war1118372559\WEB-INF\
3. Set an environment variable JAVA_HOME to point at the path of your JDK:

  •   right click on "My Computer" and go to properties
  •   click advanced tab and select environment variables
  •   click new under system variables.
  •   set name = JAVA_ROOT
  •   set path to the path to your JDK e.g. C:\Program Files\Java\jre1.5.0_06\

Testing CFCompile
1. Open a command window and navigate to your cfcompile.bat directory e.g.
C:\JRun4\servers\[servername]\SERVER-INF\temp\[cfusion.warsomething]\WEB-INF\cfusion\bin\
2. Type cfcompile and you should see instructions on how to compile files. If you see any errors it is typically helpful about how to address the issue.
3. For example
    cfcompile C:\perforce_amh\walkjogrun\dev\application.cfm
    will return successful 1, total 1, elapsed 0.0 sec
This means you have a working configuration - easier to spot at this stage rather than getting confused looking at the Eclipse messages!  More documentation on cfcompile.bat is available on the Adobe site:livedocs and this technote

Configuring ANT in Eclipse
The next step is to configure ant within eclipse to call cfcompile with a selected file.  
1. Open eclipse and go to Window > Preferences > Ant > Runtime and click the Properties tab
2. Create two new variables project_loc and resource_loc with the value ${project_loc} and ${resource_loc} respectively
3. Add this script somewhere as ant_compile_cf.xml (I created an Ant script project) and set the java_home and cfcompile_path variables to match your environment:

<?xml version="1.0" encoding="UTF-8"?>
<project name="Compile CF" default="compileCheck" basedir=".">
    <property name="JAVA_HOME" value="C:\Program Files\Java\jre1.5.0_06\"/>
    <property name="cfcompile_path" value="c:\JRun4\servers\wjrLocal\SERVER-INF\temp\cfusion.war1118372559\WEB-INF\cfusion\bin\"/>
    <property name="Tail" value="Compile complete"/>
    
    <target name="compileCheck">
        <echo>Project ${project_loc}</echo>
        <echo>Resource ${resource_loc}</echo>
        <exec failonerror="true" dir="${cfcompile_path}" executable="cmd.exe">
          <env key="JAVA_HOME" value="${JAVA_HOME}"/>
          <arg line="/c cfcompile.bat ${resource_loc}" />
        </exec>
        <echo>${Tail}</echo>
    </target>
    
    <target name="deploy">
        <echo>Project ${project_loc}</echo>
        <echo>Resource ${resource_loc}</echo>
        <exec failonerror="true" dir="${cfcompile_path}" executable="cmd.exe">
          <env key="JAVA_HOME" value="${JAVA_HOME}"/>
          <arg line="/c cfcompile.bat -deploy ${project_loc} ${project_loc} ${project_loc}\cfbytecode" />
        </exec>
        <echo>${Tail}</echo>
    </target>
</project>
4. Save the file and right click on the filename in Navigator panel.
5. Select Run As > Ant Build... and give it a name of ant_compile_CF.xml
6. Hit run.  It should finish without any errors showing in the console window since you were attempting to compile an xml file.  This is harmless.

I want to talk through the lines of the code briefly to give you a taste of the power of Ant.  First to note is that it is simply an XML file which means any xml tags must be correctly terminated.  I mention this in case you experiment and see parsing errors.  Next is the project declaration with a name and a default.  The default tells Ant which target method to use if no method is specified when the script is run.  The basedir parameter tells Ant which directory to start in.  The property lines are name-value pairs used to specify global parameters for the entire project.  I set java_home, cfcompile_path and a tail message as global since both scripts reuse that information.  Each target is what you might think of as a method encapsulating a block of code.  Echo writes the two eclipse global variables we configured in the last section to the console so you know which project and specifically which resource (directory or file) is the source for compilation.  The exec command is used here to get a command line and the argline uses /c to run the cfcompile batch file with the parameter we configured for resource_loc which eclipse uses to pass the path to the file or directory to be compiled.  You may notice that there are two options in the file, one just does the compilation but the other will create a bytecode directory for the results which can be used to push code to your production server.

Project Configuration
Next we Configure a project to use the ant script to run the cfcompiler to check for compile time errors
1. Right click on a CF project and go to Properties>Builders
2. Hit New... and select Ant Build
3. Give it a name and hit browse workspace to set the buildfile to the path to your script ant_compile_cf.xml
4. Select a cfm file or a directory of CFM files in the project you configured and click the green play icon with a briefcase in the tool bar.
5. A dialog box appears asking you how you want to run the application.  Select the ant_compile_cf.xml file and click Run.
6. You should see a message to tell you that the file(s) compiled successfully (unless you picked a bad one).

Automatic compilation
The last step which is optional removes the need to manually hit the run button each time you need to compile a file.
1. Right click on a CF project and go to Properties>Builders
2. Select the ant builder you added in the last section and click Edit..
3. Click the targets tab and next to auto build hit set targets then ok to accept the default target of compileCheck
4. Hit OK to close the properties window.
5. As you close the window, the console should show that the cfcompiler has started and your entire project is being compiled.  I've not found a way to stop it from doing that just yet but at least you get the satisfaction that you are starting with good code :-)
6. Now whenever you save a file in the project, the cfcompiler runs to check your code for errors.

Hopefully, if you have made it this far you are up and running with Ant scripts. If this looked interesting you should take a look at using Ant to execute CFUnit tests to keep your CFCs in top shape!

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
[Add Comment] [Subscribe to Comments]
  1. How would you use this on a workstation that does not have ColdFusion installed? I want to execute the precompiling on a remote development server.

    Thanks, - Doug

  2. You can ignore my last comment/question. I figured it out, it was as simple as mapping a network drive and doing it that way.

    Thanks, - Doug

  3. This works really nice. Is it possible to just compile the file that was changed? Right now it compiles my whole project every time i save.

  4. you can also run the cf compile task as a native java task from inside ant. this way it's more cross platform compatible. i've ran this task as a ant task on windows and linux.

    <!-- Setup details --> <target name="init"> <property name="name" value="cfccomponents"/> <condition property="pathroot" value="c:" else="/opt"> <and> <os family="windows" /> </and> </condition> <condition property="coldfusion.instancename" value="daveramsey_com" else="cfmain"> <and> <os family="windows" /> </and> </condition> <property name="jrun.path" value="${pathroot}${file.separator}jrun4" /> <property name="jrun.jar" value="${jrun.path}${file.separator}lib${file.separator}jrun.jar" /> <property name="coldfusion.instancepath" value="${jrun.path}${file.separator}servers${file.separator}${coldfusion.instancename}${file.separator}cfusion-ear${file.separator}cfusion-war${file.separator}" /> <property name="coldfusion.libpath" value="${jrun.path}${file.separator}servers${file.separator}${coldfusion.instancename}${file.separator}cfusion-ear${file.separator}cfusion-war${file.separator}WEB-INF${file.separator}cfusion${file.separator}lib" /> <property name="coldfusion.bootstrap.jar" value="${coldfusion.instancepath}${file.separator}WEB-INF${file.separator}lib${file.separator}cfmx_bootstrap.jar" /> <property name="coldfusion.cfx.jar" value="${coldfusion.instancepath}${file.separator}WEB-INF${file.separator}lib${file.separator}cfx.jar" /> <property name="coldfusion.compiler.classpath" value="${coldfusion.libpath}${file.separator}updates,${coldfusion.libpath}" /> <property name="coldfusion.compiler.libpath" value="${coldfusion.libpath}" /> </target> <target name="compile" depends="init"> <java classname="coldfusion.tools.CommandLineInvoker" failonerror="true" fork="true"> <classpath> <pathelement location="${jrun.jar}"/> <pathelement location="${coldfusion.bootstrap.jar}"/> <pathelement location="${coldfusion.cfx.jar}"/> </classpath> <sysproperty key=" coldfusion.classPath" value="${coldfusion.compiler.classpath}" /> <sysproperty key=" coldfusion.libPath" value="${coldfusion.compiler.libpath}" /> <arg line=" Compiler "/> <arg line=" -cfroot ${coldfusion.instancepath}${file.separator}WEB-INF${file.separator}cfusion${file.separator} "/> <arg line=" -webinf ${coldfusion.instancepath}${file.separator}WEB-INF${file.separator} "/> <arg line=" ${basedir} "/> </java> </target>

  5. OK, so that totally botched my formatting. sorry about that.

  6. I have the need to compile some code on my development PC (windows) and then publish on a linux server with a SERVER CF Installation (not J2EE). Is this possible ? Why if I try a compiled file on my PC it works fine and if I try to run it on the server I get back the error UNEXPECTED CONSTANT #2 54 thrown by a java.lang.IllegalStateExecution ? What I'm missing ? Thanks for any help. Sergio

  7. Hey Sergio, Without seeing the snippet of code causing the error it's hard to say. Are the servers both Windows or are you pushing to a linux box. That can throw a big wrench in the process. If you want to send me the snippet offline I could take a look for you. Adam

  8. Hi Adam,

    I'm getting this kind of problem too: unexpected constant #2 37

    I just put in my .cfm this to test:

    <cfoutput>#now()#</cfoutput>

    But the error stills

  9. @Leon: where do you put this xml file? Every time I try this I get an error when I try to compile the Ant project from cfcompiler complaining that the ant file isn't in the webroot.

  10. Never mind, I just moved the xml file into my project directory which was in the CF webroot. I've gotten a solution working where I hook in Snarl (like Growl on the Mac) to the output so you can get the result without having to keep the console window open. See <a href="http://hofo.com/post.cfm/snarling-radioactive-ants">http://hofo.com/post.cfm/snarling-radioactive-ants</a> for details.

  11. Adam - how do you use this in deployment for production? I'd like to precompile but I'm not clear on what gets copied to the destination directory and how to combine that with ant's SYNC task. I want to of course include all of my xml files and images and so forth - how do you combine the sync or ftp tasks with the precompile?

[Add Comment]