Conditional Compilation
MXMLC’s -define feature allows you to do two things: compile-time constants (as covered previously) and conditional compilation. Both are very useful, so today I’m covering conditional compilation.
Conditional compilation is, thankfully, also simple. All you need to do is surround your code with a compile-time constant:
// Hide the context menu's built-in items in the release version of the app CONFIG::release { var menu:ContextMenu = new ContextMenu(); menu.hideBuiltInItems(); this.contextMenu = menu; }
Here our compile-time constant is CONFIG::release. We must define it as an expression that evaluates to true at compile time. Here are some examples:
Code Included
- true
- 1
Code Not Included
- false
- 0
Compiler Error
- null
- x + y (where x and y are variables)
- {
- foo(
So if the compile-time constant evaluates to true, the resulting code will be:
// Hide the context menu's built-in items in the release version of the app var menu:ContextMenu = new ContextMenu(); menu.hideBuiltInItems(); this.contextMenu = menu;
This is just the above source with the CONFIG::release { and ending } stripped out. I left the indentation and comment in place, though it doesn’t really matter. If the compile-time constant evaluates to false, the resulting code will be:
// Hide the context menu's built-in items in the release version of the app
The whole block from CONFIG::release { through } simply disappears! This is great on many fronts, chiefly optimization and SWF size. On the optimization front there is no faster code than the code that does not exist. This is the ideal way to exclude logging, error checking, and such nice development and debugging code from the final release of the app. On the SWF size front the story is much the same: code that doesn’t exist can’t contribute to the SWF size even a single byte.
One interesting quirk is that the text outside the conditional block must be a compile-time constant and not simply what that constant evaluates to. For example, this will not work:
true {log("literal");}
If you try it, you’ll get the following error from MXMLC:
Syntax error: expecting rightbrace before leftbrace. true{log("literal");} ^
Another unfortunate result of this compile-time definition feature is that it doesn’t allow nearly as much flexibility as C/C++’s #define. Specifically, you can’t make a macro like this C/C++ example:
#define RADTODEG(x) ((x) * 57.29578)
So we end up where we ended up at the end of the last article: an AS3 function that must be (slowly) called. The whole point of a macro in C/C++ is to avoid the function call by inlining its body for improved speed. Sadly, this seems impossible in MXMLC given the limitations discussed above. Chief among them is that you cannot simply use arbitrary text in your define as that would not be a compile-time constant (see the “compiler error” list above). Otherwise we might make a pair of defines like this:
-define=LOG::start,"log(" -define=LOG::end,");"
And use it like this:
LOG::start "hello" LOG::end
This would be replaced and look like this, were C-style #defines allowed:
log( "hello" );
Sadly, they are not. One alternative is to use the C preprocessor as a preprocessing step before your code is compiled, but that tends to get very messy very fast.
In conclusion, conditional compilation goes along with compile-time constants nicely to shift some run-time work forward to compile time. By using this technique we get faster, lighter code. To me, that makes it worthwhile.
#1 by Og2t on February 4th, 2010 ·
Thanks for sharing Jackson, can you do the same with FCSH? And also disable all trace() – as in Flash IDE? I am looking for to compile the SWF server side, preferably using FCSH (for speed).
#2 by Og2t on February 4th, 2010 ·
Ignore my last comment, didn’t realise you can use MXMLC in FCSH ;-)
#3 by mrm on February 17th, 2010 ·
It should be noted that you can’t do gimmicks like this one:
What the above code snippet is trying to achieve is run some code if CONFIG::debug is true and some other code if it’s false. It doesn’t work because the compiler first strips all the comments out and then looks for -define’d constants.
However, you can do this:
#4 by Chris on August 6th, 2013 ·
The following does not work. I’m not sure why ?
if ( ! CONFIG::variable) {
// do something when variable is false
}
#5 by jackson on August 7th, 2013 ·
It’s working for me with ASC 1 and ASC 2. Here’s my test app:
Here’s how I compiled it:
And here’s the output:
#6 by Pier on August 27th, 2013 ·
I using compiler conditionals to separate code that is meant for desktop testing, and mobile release.
The problem is I’m worried I might forget to change the config constant manually, and compile for mobile with code for desktop. Ideally I test all my versions, but you know… sometimes circumstances are not ideal. You need to fix that little bug for some adhoc distribution app and all the pressure is on you… and bam, you forget to change that little thing.
Is there some way to make a trace at compile time, or some other solution to inform of the values of the config constants during compile time?
I’m using Flash Pro btw.
#7 by jackson on August 28th, 2013 ·
Sure, but you’ve got to do it in a pretty brute force way:
That is to say that there’s no way to loop over the defined variables to print them out.
#8 by Pier on August 28th, 2013 ·
But wouldn’t those traces be executed on run-time instead of compile-time?
#9 by jackson on August 28th, 2013 ·
Yes, they would. I missed the part about printing at compile time. I don’t know of anything in AS3 that would allow you to do it other than a horrible hack where you intentionally trigger a compiler warning. For example, you could intentionally leave out a variable type:
Compile with:
Gives this compiler warning which tells you at compile time that mobile is enabled:
Again, it’s a big hack but I don’t see any other pure AS3 way of achieving the same result. You might want into Flash Pro’s build features or use another build system (e.g. Ant scripts) to put the messaging there. For example, an Ant build target could easily echo a message:
#10 by Pier on August 28th, 2013 ·
Thanks Jackson, I’ll check the ANT scripts thing.