hasseg.org

fcshctl: the Flex Compiler Shell Controller

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

21 Comments

Chris Hill November 29, 2008 at 6:39 AM

Hi Ari,

Thanks for this extremely useful utility! I have been using it for a bit and it has been pretty stable. I have written a follow-up article to yours which explains how to set up the Error List plugin to listen to fcshctl’s output.

http://ubergeek.tv/article.php?pid=146

I mention that I have had a couple issues. It basically hangs until I rm the log file. This hasn’t really been a big issue for me, but if I’m able to determine why it does this I’ll let you know.

Ali Rantakari December 8, 2008 at 5:04 PM

Hey Chris,

I haven’t had the script hang on me at all so if you find more info on why it might be happening for you and maybe even how to fix it, it would be greatly appreciated. Thanks!

Vern Takebayashi December 10, 2008 at 4:49 AM

Hello Ari,

I tried running your fcshctl utility. It worked fine on my Ubuntu 8.04.1 desktop machine (except I have to rm the log file as Chris Hill reported above). However, when I tried to run it on an old server running Debian Etch, it hangs up even when trying to run the help message

i.e.

./fcshctl help

This produces the following error messages: ./fcshctl: line 227: screen: command not found ./fcshctl: line 126: screen: command not found ./fcshctl: line 132: screen: command not found ./fcshctl: line 133: screen: command not found ./fcshctl: line 153: screen: command not found

If you can give me an idea as to what might be causing this, I will try to track down what might have happened. I am able to run the fcsh utility from the SDK, so the SDK itself runs okay.

Thanks for putting out this utility. I will probably try placing it on a better server when I get a chance (as the Debian Etch machine I tried it on is an old machine and it may also be missing some dependencies).

I’ll let you know if I figure out anything.

Vern

Ali Rantakari December 10, 2008 at 2:16 PM

Hi Vern,

The problem is that you don’t seem to have GNU Screen installed on that Debian box.

This, I think, is what you need: http://packages.debian.org/etch/screen

Or if you do have it, make sure it’s in your $PATH when you call fcshctl.

Ali Rantakari December 10, 2008 at 5:22 PM

Hi guys,

I made some changes to the script (see the changelog at the beginning of the post.) You should try the new version to see if it fixes the lock-ups you’ve been having due to the logfile not being removed correctly.

Chris Hill December 10, 2008 at 9:55 PM

Hi ali, I have installed the new version, I’ll tell you if I see any improvement. I hope I haven’t made it out to be a big deal, as it happens about once a week max. Its so infrequent it makes it hard to debug :)

Thanks again!

Vern Takebayashi December 10, 2008 at 11:54 PM

Hi Ari,

Thanks for figuring out that I was missing GNU screen. After installing this package everything works. I have tried the new version (v0.5) and it seems to have cleared up the screen log issue. Great work!

Vern Takebayashi December 11, 2008 at 12:04 AM

Hi Ali,

You don’t have to post this. I just wanted to apologize for my other two posts where I put your name as Ari (instead of Ali).

Thanks again for all your great work.

Max March 17, 2009 at 8:03 PM

I often use Control+C to kill a process, but fcshctl does not handle this well. Afterwards it continually waits for the log file at /tmp/fcshctl_screen_log to be removed, which never happens.

Perhaps I am too quick to Control+C, but a program with no output during compilation (until the end) looks the same as a program that is frozen. Perhaps an initial message would help?

I guess it’s up to you if these things are bugs or features, but to me they are bugs. Other than that it’s a great program, thank you very much for sharing this.

Ali Rantakari March 18, 2009 at 12:25 AM

Hi Max,

Thanks for the suggestions. I uploaded a new version that checks for other running fcshctl processes using ps and if no other instances seem to be running, deletes the log file (assuming it has been orphaned for example due to a previous fcshctl process being killed before it had had a chance to remove the log file) and continues. It also displays a “compiling…” message like you suggested.

Max March 18, 2009 at 3:33 AM

Yes, it works perfectly now. Thank you very much!

Dustin June 22, 2009 at 9:04 AM

Very helpful! Thanks so much for sharing!

google.com/accounts/o8… August 6, 2009 at 11:06 AM

http://code.google.com/p/fsch/ wrapper is now scriptable with ant

Chris Hill September 9, 2009 at 9:26 PM

Hello again,

I have made the following modification to your bash script so that it prints out dots while it waits for output from the log:

# monitors the screen log file and waits until the prompt "(fcsh)" # appears at the end wait_for_prompt_in_logfile() { while sleep ${LOGFILE_MONITOR_INTERVAL} do lastLine="`tail -n 1 \"${LOGFILE}\"`" [ "${lastLine:0:6}" == "(fcsh)" ] && break echo -n '.' done echo }

Thanks again for such a useful bit of code! :)

Ralph Krausse January 19, 2010 at 8:10 PM

GREAT but I am windows guy. How do you send commands to the fcsh? Sockets? How do you know what to send?

thx Ralph

Ali Rantakari January 20, 2010 at 12:07 AM

Hi Ralph,

If you’re using Windows, I suggest you check out the other options I listed here (at the bottom of the post), or just search Google for some other solution that’s designed for Windows. You can of course install some sort of Unix environment (like Cygwin) onto your Windows box for running this, but it doesn’t seem like a smart way to go about it in my opinion.

Jack Lucky September 26, 2010 at 12:00 PM

Have a look at this “Fast Flex Compiler, without the interactive (and blocking!) shell.” http://code.google.com/p/flex-compiler-shell-daemon/

My desperate life quest for efficiency » Blog Archive » Cross-platform convenience wrapper around fcsh(fast incremental Flex builds) September 28, 2010 at 1:41 PM

[…] a little bit of googling I discovered a wrapper around fcsh - the fcshctl tool. It is almost ideal except several […]

Pavel Shevaev September 29, 2010 at 12:58 PM

Hi! I was quite inspired by your script, great job thanks. The only downside is the fact it’s *nix only. For this reason I created a cross-platform version of a similar wrapper around fcsh - http://efiquest.org/2010-09-28/50/

Endel August 17, 2011 at 11:06 PM

Hi! Is it open source? I would be great if you share the source code of fcshctl, so the community can support it.

Ali Rantakari September 22, 2011 at 8:47 PM

Hi Endel – the script is licensed under the MIT license.

Categories