boostworthyisryantaylor

AS3: Conditional Compilation Demystified

A relatively unexploited (Flex 3) feature of the mxmlc compiler is the ability to define and pass constants to your application at compile time. This is an elegant and handy way to change application behavior without having to make adjustments in your code or an external config file.

In the Flash IDE, you have the option to omit trace actions when you publish your SWF files, but this option does not exist when compiling using Flex Builder or the mxmlc compiler in general. One popular workaround for omitting traces in a non-Flash IDE project was to create custom metadata tags and wrap them around debug code in ActionScript, then run an Ant task that uses regular expressions to remove any code inside those tags right before compiling. This solution is sort of similar, but much safer and more reliable since no code is ever being copied or deleted - it's just a constant being set at compile time that you can then access inline at runtime.

Cutting to the chase, here's how it works. The command-line syntax is:

CODE:
  1. -define=YOUR_NAMESPACE::YOUR_CONSTANT_NAME,yourConstantValue

Better yet, if you are using the Flex Ant tasks:

CODE:
  1. <mxmlc ... >
  2.      <define name="YOUR_NAMESPACE::YOUR_CONSTANT_NAME" value="yourConstantValue" />
  3. </mxmlc>

Now, if you're using Flex Builder, you will want to add the definition(s) in the 'additional compiler arguments' field in the project properties dialog box. Even if you are using an Ant build file to compile, you still want to do this because it will prevent your code from being flagged with errors.

In ActionScript, you can then access this constant by simply addressing it as follows:

ActionScript:
  1. if(YOUR_NAMESPACE::YOUR_CONSTANT_NAME)
  2. {
  3.      // Do something.
  4. }

In most cases, your values will probably be booleans, though you can also pass strings, numbers, and even expressions. A few things to take note of:

    - If you pass a string in the Ant task version, you will need to wrap around it an additional set of double-quotes (and escape them) or single quotes.

    - If you pass a number or string, make sure and apply this constant to a typed constant defined in your ActionScript.

As I mentioned before, this is most useful for differentiating a debug build from a release build. I am using this approach in my logger to prevent any traces from being output unless it is a debug build. I highly recommend this practice of funneling all of your trace calls through a logger or some sort of class first so that you only need to perform the check in one location, rather than all over your application.

If this is new to you, I highly suggest taking it for a spin in one of your projects.

7 Comments so far

  1. erixtekila February 18th, 2008 12:05 pm

    This solution is sort of similar, but much safer and more reliable since no code is ever being copied or deleted

    - Safer ? : The code is compiled as a constant in the swf bytecode. So it's unsafe IMHO.
    - Reliable ? : Do you find Ant tasks not reliable ? Maybe Regular expressions ?
    Can you develop why you find this technic more safer and reliable ?

  2. Ryan Taylor February 18th, 2008 12:43 pm

    @erixtekila - The method I was referring to as unsafe makes a copy of all of the source files, then deletes code inside of them. Why do you consider a constant being compiled into bytecode as unsafe? Likewise, Ant and regular expressions are not what I question the reliability of; it's a task in which code is copied and deleted that concerns me. One little mistake in how the task is written (especially without source control) and you will have quite a mess to clean up. Does that make sense? I wasn't bashing the other method, I just consider this one to be a safer alternative.

  3. erixtekila February 26th, 2008 5:47 pm

    "Why do you consider a constant being compiled into bytecode as unsafe"
    Flex is now opensourced. Everything in the opcode is potentially viewable.
    I, for myself, consider safer to completly hide sensible data from prying eyes if possible.
    BTW all methods have their pros and cons, one should know them, that's it :)

  4. erixtekila February 26th, 2008 5:57 pm

    BTW it seems that the conditonal compilation doesn't include some parts with that notation :
    CONFIG::debug
    {
    addChild( new FPSMeter());
    }

    Check this link : http://blogs.adobe.com/flexdoc/conditionalcompilation.pdf
    The documentation is not really clear for that aspect.

  5. Ryan Taylor February 26th, 2008 10:36 pm

    @erixtekila - I'm talking about compiling a boolean value into bytecode here, not a password or something private. I really feel as if you are misunderstanding this post. I'm also not following your other comment about it not including some parts with that notation. Are you aware that 'CONFIG::debug' and 'if(CONFIG::debug)' are evaluated exactly the same?

  6. erixtekila March 3rd, 2008 6:28 pm

    Sorry, but using some decompiled as3 swf shows that those directives doesn't actually include the code in the bytecode.
    It seems also to me that those directives can be followed by a block of code ( in {}) without any "if" instruction. I mean "if" is evalueted as actionscript at runtime but CONFIG::debug is not. Those directives are in fact stripped from the pcode.
    So I was wrong in saying that as code where included in the final bytecode and anderstand your assomptions too :-P .

  7. Gimlock June 9th, 2009 12:07 pm

    Thanks for the post! Note the PDF reference said that the value must be in quotes, but in my testing it only worked if the value was NOT in quotes. Also, checking via decompiler, conditional compilation was also achieved using the standard if() syntax.

Leave a reply

*
To prove you are human (not an imperial spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word