fcshctl: the Flex Compiler Shell Controller

Posted on November 3, 2008
Filed under ActionScript 3, Flex, jEdit, Programming, Scripts

Introduction

Like I’ve mentioned before in this blog, I develop Flex applications using the Flex SDK and jEdit instead of Adobe’s Flex Builder IDE. This setup has worked very well for me but one annoying issue I’ve had to deal with because of this is the slow compilation speed: every time I make a small change into one of my projects and recompile it, the mxmlc compiler (that my build scripts are calling) has to load the JVM into memory and recompile my whole project from scratch, which obviously takes a while. Compiling things in Flex Builder is a lot faster, and the reason for that is the Flex Compiler Shell, which it uses for compilation instead of mxmlc.

Update (Version 0.5.1, Mar 17, 09):

  • Display a “compiling…” message before sending fcsh a compilation command in order to let the user know that something is going on and that they should wait instead of just killing the process.
  • If the log file exists when fcshctl runs, check if there are any other fcshctl instances running, and if not, assume that the log file has been orphaned, delete it and continue.
  • Exit with status code 0 (“ok”) if fcsh output ends in the “Nothing has changed since the last compile” message.


Update (Version 0.5, Dec 10, 08):

  • Made it possible to specify a filename as the argument to the “clear” command — fcshctl will then try to find the first compile target id matching the specified filename and clear the corresponding id (example: “fcshctl clear MyApp.mxml”)
  • Made fcshctl find compile target ids corresponding to specific filenames or paths by asking fcsh directly via the “info” command instead of retaining them on its own in a temporary file (this is in order to avoid problems that could arise if this temp file and fcsh’s own list of retained compile target ids would get out of sync.)
  • Added command “id” which can be used to find the first compile target id matching a specified string (example: “fcshctl id MyApp.mxml”)

Update (Version 0.4, Nov 4, 08):

  • Made the script use only one logfile (i.e. one with a static path) and check its existence (and if it does exist, wait for it to be deleted) before continuing, so as to make sure no two fcshctl instances can try to send commands to fcsh at the same time, or before an already running command has finished executing and returned control to the prompt.

The basic idea behind the Flex Compiler Shell is that it would stay in memory between compilations (thus avoiding the cost of loading up the JVM every time you want to compile something) and use a technique called incremental compilation that, as the name suggests, is based on the idea of only compiling the parts of your project that have changed since the last compilation (thus making the process a lot faster). When you run the Flex Compiler Shell executable (called fcsh), you’re thrown into an interactive shell where you can run commands in order to compile your projects and control the operation of fcsh itself.

The Problem

When I found out about fcsh, tried it out and saw how much faster it was than mxmlc, of course I wanted to immediately start using it instead in my build scripts. The biggest problem with doing this, though, is the fact that the basic operation of these two programs is fundamentally different: when you run mxmlc, it compiles the project, prints some messages to standard output and then exits (with the exit status 0 if the compilation was successful or 1 if it wasn’t), which is perfect for integrating it into build scripts. Fcsh, on the other hand, throws you into a shell of its own and expects you to essentially operate it from within itself (instead of simply calling it with some arguments and then having it return with some standard output and an exit status like mxmlc).

The other issue that makes fcsh more difficult to use in general is that in order to use the incremental compilation feature, you have to first compile your project like you normally would (using the “mxmlc” command), then make note of the “compile target id” number that fcsh then assigns to this project and specifies in its output, and for future compilations use the “compile N” (where N is the compile target id) command.

The Solution

I tried to search for a solution to this problem that somebody else might have come up with but didn’t find an adequate one (a list of the ones that I could find is further down), so I decided to give it a shot myself. My approach, called fcshctl (short for “fcsh controller”), is basically a simple bash script that:

  1. starts the fcsh process if it isn’t already running
  2. forwards its arguments to fcsh as commands
  3. reads the output of that command from the fcsh interactive shell and prints it to the standard output
  4. exits with status 0 (success) or >0 (failure)

In addition to this, I also made the script automatically and transparently invoke the incremental compilation feature whenever applicable so that I wouldn’t have to worry about keeping track of the compile target ids and using a different command for the compilation whenever one had already been assigned.

Below is a summarization of the pros and cons of this solution:

Pros:

Cons:

Download

You can download fcshctl here:

fcshctl has been tested with fcsh versions 3.0.0 build 477 and 3.1.0 build 2710 on Mac OS 10.5.5. It is licensed under the MIT License.

The script requires the following to be in your $PATH: rm, mv, cat, ps, sleep, tail, head, grep, awk, screen, xargs and basename. You also need to have the FLEX_HOME environment variable set to point to the Flex SDK root path.

Example of use

fcshctl $ export FLEX_HOME=/Users/username/code/SDKs/flex_sdk_3.1
fcshctl $
fcshctl $ ./fcshctl     

Usage: fcshctl <commands>

  Substitute <commands> with any commands you
  would like to send fcsh, just like you would
  enter them in the interactive fcsh shell
  session.

  To get a list of the available commands, run:

    fcshctl help

fcshctl $ 
fcshctl $ ./fcshctl help
List of fcsh commands:
mxmlc arg1 arg2 ...      full compilation and optimization; return a target id
compc arg1 arg2 ...      full SWC compilation
compile id               incremental compilation
clear [id]               clear target(s)
info [id]                display compile target info
quit                     quit
fcshctl $ 
fcshctl $ ./fcshctl mxmlc ~/code/Flex/projects/testbed/testbed.mxml 
Loading configuration file /Users/username/code/SDKs/flex_sdk_3.1/frameworks/flex-config.xml
Recompile: /Users/username/code/Flex/projects/testbed/testbed.mxml
Reason: The source file wasn't fully compiled.
Files changed: 0 Files affected: 1
/Users/username/code/Flex/projects/testbed/testbed.mxml(28):  Error: Incorrect number of arguments.  Expected 2.

    func1("toka");

fcshctl $ echo $?
1
fcshctl $ 
fcshctl $

Other similar solutions

Below is a list of other approaches to the problem of integrating fcsh to non-standard (i.e. non-Flex Builder) workflows (roughly in order from most promising to least promising), and short lists of reasons why I personally didn’t want to use them. If my solution doesn’t seem good to you, you should maybe check some of these out.

fcsh tools by Mike Rowe

flex-compiler-shell-daemon by Leonardo Soto Muños (also see his blog post about it)

FCSH Wrapper by Mihai Vasilache

http://code.google.com/p/fsch/ by nimrod97

BigSource Zarkov by BigSource GbR

Comments

21 Responses to “fcshctl: the Flex Compiler Shell Controller”

Show/hide comments & reply form: