Is there a way to have debug code compiled out for a final build?

Is there an equivalent to the C standard way of having debug code that is disabled or compiled out for a final release build?

In C you would do something like

#if !RELEASEBUILD
... debug code ...
#endif

I expect this to be a bit of a problem with Unity/Mono but thought i'd ask. If it isn't possible then i'll just write some awk scripts that i can run which will allow for the same kind of behavior by manually running it on my script files before doing a final build.

Cheers

As Peter pointed out: Currently, Unity doesn't support project-wide #defines, which in my opinion is a very unfortunate limitation. One thing you can do to get this more into reach is vote up the entry on feedback.unity3d.com: Editor: Interface for listing preprocessor macros (#define) in build settings. With that feature, the issue (and a lot more issues) would be solved.

One thing you could do under "the right circumstances" is compiling DLLs with Visual Studio that you use in Unity. That way, you could use the defines from Visual Studio. Unfortunately, those "right circumstances" are probably quite rare (usually, you'll want to keep most code directly in the Unity project because it simplifies most things).

So, until I get those defines in Unity, what I'm doing is this: I have a couple of defines in every class file where I need them, and I also have a script that runs through all the classes and does a little bit of code replacement to either "activate" or "deactivate" those code sections (I comment them in/out via script). That way, I have "kind of the same functionality" as I would have with proper project wide defines. It's just a hack and somewhat more cumbersome ... but it works for me in a rather complex project (server/client, different client versions etc.)

The whole code that I'm using for this is a bit too much and too complex (and too unpolished) to post but I can give you a few bits that should be helpful to set something like that up for yourself. So, the code I'm posting here is not "easy copy'n'paste code" but it should get you start it - and feel to ask questions (I can still edit this to make things more clear).

Just a word of warning: Replacing code in your source files can ruin your project if you're not careful. I also had a lot of Unity crashes when I developed this (but that was with a much older version of Unity). So either use version control (like the Asset Server) or always keep backup copies. And, speaking of version control: doing these replacements will obviously change your code; and usually, that's not a change you'd usually want to record in your version control - so in most cases, you'll probably just do this for a build and then revert the changes.

That said:

// Activate / deactivate the debug symbol (somewhere in an editor script or console app)
public void ConfigureDebugCode(bool isDebug) {
    ConfigurationHelper helper = new ConfigurationHelper();
    helper.RegisterIncludeSymbol("DEBUG", isProduction);
    helper.ReplaceInAllScriptAssets();
}

// I have this in a separate class; this has a "CONSOLEAPP"-define
public class ConfigurationHelper {

    private string fileFilter = "*.cs";

    private List<string[]> currentReplacements = new List<string[]>(9);

    public void RegisterIncludeSymbol(string symbol, bool activate) {
         string a = string.Format("#define {0} //A", symbol);
         string b = string.Format("//#define {0} //I", symbol);
         RegisterReplaceAwithB(a, b, activate);
    }

    public void RegisterReplaceAwithB(string a, string b, bool revert) {
        if (revert) {
            currentReplacements.Add(new string[] { b, a });
        } else {
            currentReplacements.Add(new string[] { a, b });
        }
    }

    // the following is what I called "unpolished" ;-)

    /// <summary>
    ///     Executes the replacements that were previously registered.
    /// </summary>
    public void ReplaceInAllScriptAssets() {
        if (currentReplacements.Count == 0) {
#if CONSOLEAPP
            Console.WriteLine("ReplaceInAllScriptAssets without registering replacements, not replacing anything!");
#else
            Debug.LogWarning("ReplaceInAllScriptAssets without registering replacements, not replacing anything!");
#endif
            return;
        }

        //Debug.Log("Will be replacing:");
        //foreach (string[] replace in currentReplacements) {
        //    Debug.Log(string.Format("{0} / {1}", replace[0], replace[1]));
        //}

#if CONSOLEAPP
        DirectoryInfo assets = new DirectoryInfo(ProjectPath + "Assets/");
#else
        DirectoryInfo assets = new DirectoryInfo("Assets/");
#endif
        List<FileInfo> changedFiles = new List<FileInfo>();
        FileInfo[] scripts = assets.GetFiles(fileFilter, SearchOption.AllDirectories);
        int index = assets.FullName.Length - "Assets/".Length;
        for (int i=0; i < scripts.Length; i++) {
            FileInfo script = scripts*;*
*#if !CONSOLEAPP*
 *EditorUtility.DisplayProgressBar("Replacing keys in files",* 
 *string.Format("File: {0}", script.FullName.Substring(index)),* 
 *((float) i) / ((float) scripts.Length));*
*#endif*
 *if (script.FullName.Contains("Editor")) {* 
 *// we don't want to mess with editor scripts (like this one ;-) )*
 *//Debug.Log(string.Format("Ignoring editor script: {0}", script.Name));*
 *} else if (script.FullName.Contains("Standard Assets")) {*
 *// we also don't want to mess with scripts from (Pro) Standard Assets*
 *//Debug.Log(string.Format("Ignoring (Pro) Standard Assets script: {0}", script.Name));*
 *} else { // now here's the gold ;-)*
 *//Debug.Log(string.Format("Processing file: {0}", script.FullName.Substring(index)));*
 *StreamReader reader = script.OpenText();*
 *string code = reader.ReadToEnd();*
 *reader.Close();*
 *string newCode = code;*
 *foreach (string[] replace in currentReplacements) {*
 *newCode = newCode.Replace(replace[0], replace[1]);*
 *}*
 _if (!code.Equals(newCode) /* code.GetHashCode() != newCode.GetHashCode()*/) {_
 *script.Refresh();*
 *changedFiles.Add(script);*
 *StreamWriter writer = new StreamWriter(script.Open(FileMode.Create), Encoding.UTF8); // "overwrite"*
 *writer.Write(newCode);*
 *writer.Flush();*
 *writer.Close();*
 *}*
 *}*
 *}*
 *//allReplacements.AddRange(currentReplacements);*
 *currentReplacements.Clear();*
*#if !CONSOLEAPP*
 *EditorUtility.ClearProgressBar();*
 *StringBuilder filesWithReplacements = new StringBuilder("Replacing codes in all scripts DONE!
");*
 *AssetDatabase.StartAssetEditing();*
 *foreach (FileInfo script in changedFiles) {*
 *MonoScript scriptObject = (MonoScript)AssetDatabase.LoadAssetAtPath(script.FullName.Substring(index), typeof(MonoScript));*
 *if (scriptObject != null) {*
 *// this should make sure this is recompiled before build...*
 *EditorUtility.SetDirty(scriptObject);*
 *// is that really needed? I left it in here just to be sure...*
 *AssetDatabase.ImportAsset(script.FullName.Substring(index), ImportAssetOptions.Default);*
 *//AssetDatabase.ImportAsset(script.FullName.Substring(index), ImportAssetOptions.ForceSynchronousImport);*
 *//Thread.Sleep(100);*
 *filesWithReplacements.AppendLine(script.FullName.Substring(index));*
 *} else {*
 *Debug.LogWarning(string.Format("Could not open {0} as asset!", script.FullName.Substring(index)));*
 *}*
 *}*
 *AssetDatabase.StopAssetEditing();*
 *Debug.Log(filesWithReplacements.ToString());*
*#endif*
 *}*
*```*

That isn't strictly possible with Unity as it doesn't support project-wide `#define`s like Visual Studio does.

You can, of course, do something like the following:

if (MyGameSettings.Debug)
{
    ...
}

and if `Debug` is declared as `const` and is false then the inner code will not become part of the binary.

That works for most cases, but if you need to strip out entire classes then you'll need another solution. You could easily write a script to process all your source files to handle the task.

[EDIT]

As of Unity 4, it is possible to create your own project-wide (and platform-specific) preprocessor defines in the Player Settings, as documented here.


[OLD ANSWER]

Note that you can check Debug.isDebugBuild to see if you are currently running a development build (based on the corresponding checkbox in the build settings). This is a runtime check, so code does not get compiled out as the OP requested.

You can also mark classes or methods with the ConditionalAttribute, which tells the compiler to remove code (and calls to it) unless a specific pre-processor define is present. Here’s what it looks like:

using System.Diagnostics;
#define DEBUG

[Conditional("DEBUG")]
class MyConditionalClass
{
    ...
}

This would be much more useful if Unity provided more control over pre-processor defines. (Note that Profiler.BeginSample uses this mechanism to strip profiling hooks from non-development builds. Internally they are using the ENABLE_PROFILER #define, which is perhaps a way to tell if you are in a development build. Probably works for Unity Pro only.)

Sorry for bumping so outdated question, but for any future visitors: you may use DEVELOPMENT_BUILD conditional flag, just like this for example:

#if DEVELOPMENT_BUILD
	private void OnGUI()
	{
		// your debug GUI here
	}
#endif

What does Unity / Mono do in the slightly less obvious case:

    if(InputState.RUN_STATE_MACHINE && InputState.SHOW_DEBUG_MESSAGE){
        ....
    }

when `InputState.RUN_STATE_MACHINE` is const FALSE and `InputState.SHOW_DEBUG_MESSAGE` in not const ???

To a human this is clearly always going to evaluate to FALSE, and so the compiler should strip the entire code block out. However, from my experience, it is almost always possible to trick a compiler into evaluating a statement repeatedly, even if the statement is always FALSE.