28

In AS3 you can pass a constant to the compiler

-define+=CONFIG::DEBUG,true

And use it for conditional compilation like so:

CONFIG::DEBUG {
   trace("This only gets compiled when debug is true.");
}

I'm looking for something like #ifndef so I can negate the value of debug and use it to conditionally add release code. The only solution I've found so far was in the conditional compilation documentation at adobe and since my debug and release configurations are mutually exclusive I don't like the idea of having both DEBUG and RELEASE constants.

Also, this format works, but I'm assuming that it's running the check at runtime which is not what I want:

if (CONFIG::DEBUG) {
   //debug stuff
}
else {
   //release stuff
}

I also considered doing something like this but it's still not the elegant solution I was hoping for:

-define+=CONFIG::DEBUG,true -define+=CONFIG::RELEASE,!CONFIG::DEBUG

Thanks in advance :)

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
takteek
  • 7,020
  • 2
  • 39
  • 70

4 Answers4

22

This works fine and will strip out code that won't run:

if (CONFIG::DEBUG) {
   //debug stuff
}
else {
   //release stuff
}

BUT this will be evaluated at runtime:

if (!CONFIG::DEBUG) {
   //release stuff
}
else {
   //debug stuff
}

mxmlc apparently can only evaluate a literal Boolean, and not any kind of expression, including a simple not.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • Could you please quote a documentation ? – tzuchien.chiu Aug 13 '13 at 08:31
  • With AIR 33 in 2020, both these examples are evaluated at runtime - classes referenced in both if and else blocks will be compiled in whether the constant is true or false. Chris' answer (CONFIG::DEBUG with no IF statement) is evaluated at compile time. – Sarah Northway Jun 18 '20 at 23:10
8

Use the if / else construct : the dead code will be removed by the compiler and it will not be tested at runtime. You will have only one version of your code in your swf.

If you are not sure use a decompiler or a dump tool to see what really happens.

http://apparat.googlecode.com/files/dump.zip

http://www.swftools.org/

...

Patrick
  • 15,702
  • 1
  • 39
  • 39
  • 1
    Seems reasonable. On the other hand, the Flash/Flex compiler can be _astoundingly stupid_, so as you say, I'd check before using that if performance really matters to you. – aaaidan Jun 11 '10 at 02:42
  • 3
    -1. The *if/else* construct doesn't work.. simple test to prove it: [Embed] a heavy file in such an if/else block. If the output filesize changes accordingly then it works, otherwise it doesn't. Also such an if/else block produces syntax errors when used outside a function which leads to the conclusion that the code block won't get stripped! – bummzack Jul 06 '12 at 12:20
  • Yes, I think this technique relies too much on a side effect of the optimiser. Conditional compilation is much better. If you need something like #ifndef, see my answer below. – Chris Hill Oct 31 '12 at 22:59
  • It seems my answer is not well understood, it was using the if (CONFIG::DEBUG) {.. as stating in the question, not an arbitrary if construct, it is a conditional compilation depending on compiler flag. This is exactly the same answer that get upvote but without the if (!CONFIG::DEBUG) part. – Patrick Nov 01 '12 at 07:54
6

While Patrick's answer fulfills the question's criteria, it does not cover all use cases. If you are in an area of code that allows you to use an if/else statement then this is a good answer. But if you are in a place where you cannot then you will need a better solution. For example, you may want to do something like this to declare a constant in a class:

private var server:String = "http://localhost/mystagingenvironment";

or for a live release:

private var server:String = "http://productionserver.com";

(this is an example and I'm not advocating this as production code).

I use xml configs and use the loadConfig+="myconfig.xml" to do my configuration instead of passing large numbers of command line params. So in the <compiler> section of your xml config:

<define>
    <name>CONFIG::debug</name>
    <value>false</value>
  </define>
<define>
    <name>CONFIG::release</name>
    <value>!CONFIG::debug</value>
</define>

This works well for all use cases:

CONFIG::debug
{
    private var server:String = "http://localhost/mystagingenvironment";
}
CONFIG::release
{
    private var server:String = "http://productionserver.com";
}

This has the additional benefit of working consistently across applications. It also does not rely on the 'optimize' flag being true, like Patrick's answer (although I think we can assume that 99.999999% of all swfs have optimize=true, I only set it to false when the optimizer breaks my AS3).

It does have the drawback that it doesn't compile all code paths, just the ones that are included. So if you're not using a build server to create release builds and tell you when things break, be prepared for surprise errors when you do your release build ("But it compiled in debug! Crap, I need this to launch now!").

Chris Hill
  • 1,914
  • 1
  • 16
  • 24
  • This seems like the most elegant solution. less compiler parameters, and a nice separation in an external XML file. To get this to work, the XML file should contain an additional "flex-config" root element, as seen here: http://help.adobe.com/en_US/air/build/WSfffb011ac560372f2012b5a4128cca83a39-8000.html. I also found this: http://www.flashdevelop.org/community/viewtopic.php?f=13&t=9696 which uses an 'append=true' attribute. I've tried all of this, but still my application does not work the way it did without the xml arguments. it does compile though. Anyone having similar problems? – Michahell Oct 13 '12 at 17:25
  • i cannot seem to edit my previous comment, but: after re-reading the drawback, it makes sense. I'm using aditional source paths for my project, including a library project. To add: not only release builds will break. also regular debug builds :( Which alltogether is really bad, because this is a nice and clean way to conditional compiling. Ah well, on to quick & dirty & working then. – Michahell Oct 13 '12 at 17:42
  • Sorry to hear you are having issues. I have had good luck with XML files and they are really, really good to have when you are working on really big projects with, say, 5 development environments! Here is an example flex config xml that I used for a small prototype. This is pretty similar to what I would use on a large scale project: http://enemyhideout.com/example_flex_configs/game-flex-config.xml – Chris Hill Oct 31 '12 at 22:51
  • Thanks. I see i haven't updated my comment here but i got this working with ANT / Jenkins a while ago. It really is a nice way to do conditional compiling in all places (same codebase, different builds for IOS / Android f.e.). Thanks again! – Michahell Nov 04 '12 at 10:47
0

Just my two cents about Chris Hill's answer (which is the solution I also use regularly): it seems that using the loadConfig+="myconfig.xml" option makes the compiler searching for the myconfig.xml file in the Flex SDK directory whereas the -load-config+=myconfig.xml option makes it searching for the myconfig.xml file in the project's directory, which is the behavior I strongly prefer as you can then easily distribute this file with your project sources...

Subodh Joshi
  • 12,717
  • 29
  • 108
  • 202
Żabojad
  • 2,946
  • 2
  • 32
  • 39