- Home /
How can I change Scripting Define Symbols before a command line batchMode executeMethod?
I am using batchMode to make my builds automatically and in my build scripts I programmatically change the Scripting Define Symbols using the PlayerSettings.SetScriptingDefineSymbolsForGroup method to turn on/off flags that are required for specific build types.
The problem is that some of my code does not compile unless PlayerSettings.SetScriptingDefineSymbolsForGroup has changed #if DEFINES before running my build scripts. This makes my build fail because the project does not compile and it cannot change the Scripting Define Symbols. The only way I can work around this is by committing a ProjectSettings/ProjectSettings.asset with the proper defines so my project compiles before the build starts.
This is not a useful workaround though because it adds manual steps to builds that should be automatic.
The only other way I can think of is doing a search and replace inside the ProjectSettings.asset of all of the Scripting Define Symbols I need to change but judging by how it looks, it might be a bit error-prone to do this with a script. Here is what it looks like inside:
scriptingDefineSymbols:
1: RR_DEV
2: RR_DEV
4: NOT_COMPILING_DEFINE
7:
11: RR_DEV
14: UIRESIZE
16: RR_DEV
25:
So, is there a way to change those symbols before the batchMode executeMethod is called or do I need to do a special script to do this?
@$$anonymous$$simon any luck solving this issue ? Thanks Yury
did you find a correct way? I have the same problem like this.
Answer by BMayne · Aug 04, 2016 at 04:37 PM
Hey there,
This will only help with your temporary solution. Instead of using text to find and replace the define symbols in the YAML scriptable singleton you can edit it with Unity's own functionality. This script has not been tested but it should get you most of the way there.
// Load the Scriptable Singleton from disk. (it should only have one entry but YAML supports more then one)
object[] loadedObjects = InternalEditorUtility.LoadSerializedFileAndForget("ProjectSettings.asset");
// Create a serialized object to let use change it's settings.
SerializedObject projectSettings = new SerializedObject(loadedObjects);
// Find the property we need to modify
var symbols = projectSettings.FindProperty("m_ScriptingDefineSymbols");
// Add a new element to the end
symbols.InsertArrayElementAtIndex(symbols.arraySize);
// Set the new element.
symbols.GetArrayElementAtIndex(symbols.arraySize - 1) = "RR_DEV";
// Apply changes.
projectSettings.ApplyModifiedProperties();
// Save it back to disk.
InternalEditorUtility.SaveToSerializedFileAndForget(projectSettings.targetObjects, "ProjectSettings.asset");
That's a very nice way to edit the property but I don't know how I will be able to execute a method with this code with my current situation. Code inside my project can't be run because of the compile errors on launch and the batch$$anonymous$$ode immediately fails.
$$anonymous$$aybe there could be a way I could run this offline of a Unity project. Something like calling a method inside of a dll in my project ... I will brainstorm some more :)
Answer by rihdus · Aug 18, 2016 at 05:08 AM
If you only need the defines set in the final app being built (i.e. in code for the game itself), just run the build. It will recompile the scripts whenever you call the Build Pipeline.
If your editor script that you're running from the command line needs to be recompiled -- stop doing that if at all possible. Pass in variables from the command line as arguments instead. You can use (for example, including a Build System Boolean Parameter that swaps between DEV and RELEASE):
-batchmode -quit +RR_DEV_${DEV} +RR_RELEASE_${RELEASE}
which might become:
-batchmode -quit +RR_DEV_true +RR_RELEASE_false
Then in your script, replace "#if RR_DEV" with:
string[] CommandLineArgs = Environment.GetCommandLineArgs(); if (CommandLineArgs.Contains("+RR_DEV_true")) { // Do Dev stuff here, possibly including setting #RR_DEV for game code to compile under }
The advantage to this is you can produce multiple build versions at the same time. For example, I make Dev, QA, and Release builds all in a single execution loop with different settings (and scripting defines) for each.
If you absolutely need to modify the scripting defines prior to execution of your Editor scripts, launch Unity twice in your build script. Run a Scripting Define Change function first, and the app build second.
Thanks for sharing your trick with RR_DEV_true/RR_DEV_false, this will be handy for upgrades to our build tool.
For my problem I absolutely need to modify the scripting defines so what do you mean when you say "Run a Scripting Define Change"? I can't using Unity code since no Unity code will run because it does not compile with the current defines. Is this with a script outside of Unity?
Sorry, I don't check the Unity boards very often. In case you're still having issues...
Ok -- the preferred first step is to get your Unity code to compile without any defines set, or to preset a few defines in the Player Settings (Edit -> Project Settings -> Player, then add them under "Scripting Define Symbols" in Other Settings) and then commit the ProjectSetting.asset file with them set correctly (note: future script-based updates to the PlayerSettings will alter this file). If possible, I'd change one of your defines to be a default option (e.g. "RR_Release" is just how it runs if nothing is set) -- essentially, swap your final #elif to an #else wherever it won't compile, so there's always some compiling code available to the system. The other method I've seen is to wrap entire scripts / classes / functions to effectively cut them entirely unless one of the expected defines is set.
Alternately, you may be able to use the .rsp files to set them (via an external script, if needed). If you're using C# or Unity script, there's a set of files you can add defines in (see here under "Global custom #defines": https://docs.unity3d.com/$$anonymous$$anual/PlatformDependentCompilation.html ). I use these to turn on and off aspects of my build system for different projects without needing to make a fully-custom version for each project. I only use "gmcs.rsp", and only target Editor scripts with those defines. Going this route, you either need to set some always-on defines (in which case, why are you putting them in defines?) or you need to eli$$anonymous$$ate those defines. All other scripts need to compile (in some basic fashion) with no defines. The game might not run at all if built that way, but it also won't fail to compile, which allows the build scripts to do their work.
I think your alternative method could be a solution to my problem. I did not know the "rsp" files existed but, like you said, it looks like those could easily be replaced by a separate script which is much easier than changing the ProjectSettings.asset file.
If I run into my problem again, I will certainly try what you are suggesting.
Thank you
Answer by hasanbayat · Oct 21, 2017 at 12:03 PM
You can use AddDefineSymbols to add define symbols automatically.
Features
Multiple Define Symbols
Safety
Runs when Compile ends
Removes Duplicates
Installation
Download the Script or Copy/Paste it from the Below
Open Script
Go to Symbols property and add your own symbols
Go back to Unity and wait for compile ends
All done, now check Player Settings, The symbols added
Here is the code for copy/pasting:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
/// <summary>
/// Adds the given define symbols to PlayerSettings define symbols.
/// Just add your own define symbols to the Symbols property at the below.
/// </summary>
[InitializeOnLoad]
public class AddDefineSymbols : Editor
{
/// <summary>
/// Symbols that will be added to the editor
/// </summary>
public static readonly string [] Symbols = new string[] {
"MYCOMPANY",
"MYCOMPANY_MYPACKAGE"
};
/// <summary>
/// Add define symbols as soon as Unity gets done compiling.
/// </summary>
static AddDefineSymbols ()
{
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup ( EditorUserBuildSettings.selectedBuildTargetGroup );
List<string> allDefines = definesString.Split ( ';' ).ToList ();
allDefines.AddRange ( Symbols.Except ( allDefines ) );
PlayerSettings.SetScriptingDefineSymbolsForGroup (
EditorUserBuildSettings.selectedBuildTargetGroup,
string.Join ( ";", allDefines.ToArray () ) );
}
}