I'm using VS2010/2012 and I was wondering if there is a way (perhaps using reflection) to see how an assembly is build.
When I run in Debug, I use the #if DEBUG to write debug information out to the console.
However, when you end up with a bunch of assemblies, is there then a way to see how they where build? Getting the version number is easy, but I haven't been able to find out how to check the build type.
There are 3 ways:
private bool IsAssemblyDebugBuild(string filepath)
{
return IsAssemblyDebugBuild(Assembly.LoadFile(Path.GetFullPath(filepath)));
}
private bool IsAssemblyDebugBuild(Assembly assembly)
{
foreach (var attribute in assembly.GetCustomAttributes(false))
{
var debuggableAttribute = attribute as DebuggableAttribute;
if(debuggableAttribute != null)
{
return debuggableAttribute.IsJITTrackingEnabled;
}
}
return false;
}
Or using assemblyinfo metadata:
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
Or using a constant with #if DEBUG in code
#if DEBUG
public const bool IsDebug = true;
#else
public const bool IsDebug = false;
#endif
I prefer the second way so i can read it both by code and with windows explorer
Once they are compiled, you can't, unless you put the metadata yourself.
For example, you could use either AssemblyConfigurationAttribute or .NET 4.5's AssemblyMetadataAttribute
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
or
#if DEBUG
[assembly: AssemblyMetadata("DefinedVariable", "DEBUG")]
#endif
Related
Is it possible to "gray out" the code if it doesn't exist like we do in Platform Dependent compilation (ex: #If UNITY_EDITOR)?
For example I don't want the compiler to complain if the code doesn't exist in the project. Specifically, I want to "hide" "GoogleMobileAds.Api;" package, which I don't have in the project, but it may be in the future.
Preprocessors are not an invention of Unity but is a c# thing.
If there are no specific defines listed in the Platform dependent compilation first make sure that your packages don't bring their own custom defines. Photon PUN e.g. actually does bring own defines like PHOTON_UNITY_NETWORKING, PUN_2_OR_NEWER, etc. But that's totally up to the providers of such libraries.
You can see/check this in the Edit -> Project Settings -> Player Settings -> Other Settings -> Scripting Define Symbols
Scripting Define Symbols
Set custom compilation flags. For more details, see the documentation on Platform dependent compilation.
Then you can just invent your own ones and add them to your code like e.g. USE_GOOGLE, USE_FIREBASE, etc
#if USE_GOOGLE
// some Google API related stuff
#endif
and later once you actually have according package in your project add these defines to the Scripting Define Symbols mentioned above.
If you know the full qualified assembly name of one type contained in the optional package you are looking for you can use e.g.
[assembly: OptionalDependency("Namespace.SubNameSpace.TypeName", "YOUR_DEFINE_SYMBOL_HERE")]
which is well hidden in Unity.XRTools.Utils!
This will internally on compile time check if the type Namespace.SubNameSpace.TypeName exists and if so define YOUR_DEFINE_SYMBOL_HERE so you can again in your code wrap the optional stuff in
#if YOUR_DEFINE_SYMBOL_HERE
...
#else
...
#endif
Alternative
For packages you own/implemen yourself there is a way to do this kind of automatically I used in the past. The following script as soon as it exists in a project it automatically adds the given define to the PlayerSettings if it doesn't exists yet
#if !USE_GOOGLE
public static class UseGoogleDefineSetter
{
const string DEFINE = "USE_GOOGLE";
[InitializeOnLoadMethod]
private void Init()
{
// Get current defines
var currentDefinesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
// Split at ;
var defines = currentDefinesString.Split(';').ToList();
// check if defines already exist given define
if (!defines.Contains(DEFINE))
{
// if not add it at the end with a leading ; separator
currentDefinesString += $";{DEFINE}";
// write the new defines back to the PlayerSettings
// This will cause a recompilation of your scripts
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, currentDefinesString);
}
}
}
#endif
Update Unity 2020+
The method was semi replaced by a better one operating on a list/array instead of an entire string which is expensive. And in the newest version also the build pipeline slightly changed.
So in newer Unity versions I would rather use something like e.g. (assuming 2020 is the oldest version you want to support/use)
#if !USE_GOOGLE
public static class UseGoogleDefineSetter
{
const string DEFINE = "USE_GOOGLE";
[InitializeOnLoadMethod]
private void Init()
{
EditorUtils.AddScriptingSymbol(DEFINE);
}
}
#endif
and to make it easy and general
public static class EditorUtils
{
#if UNITY_2021_2_OR_NEWER
private static NamedBuildTarget GetActiveNamedBuildTarget()
{
var buildTargetGroup = GetActiveBuildTargetGroup();
var namedBuildTarget = NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
return namedBuildTarget;
}
#endif
private static BuildTargetGroup GetActiveBuildTargetGroup()
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
return buildTargetGroup;
}
public static void AddScriptingSymbol(string define)
{
#if UNITY_2021_2_OR_NEWER
var namedBuildTarget = GetActiveNamedBuildTarget();
PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget, out var defines);
#else
var buildTargetGroup = GetActiveBuildTargetGroup();
PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup, out var defines);
#endif
var defineList = defines.ToList();
if (!defineList.Contains(define))
{
defineList.Add(define);
}
#if UNITY_2021_2_OR_NEWER
PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, defineList.ToArray());
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defineList.ToArray());
#endif
}
}
Both scripts go of course either in a folder called Editor and/or in an assembly only compiled for the Unity Editor or need to be wrapped additionally in #if UNITY_EDITOR
I need the following logic
#if (DEV || QA || RELEASE)
//add when dev or qa or release configuration
#endif
Is it possible in c#?
Yes. Quoting the #if documentation on MSDN:
You can use the operators && (and), || (or), and ! (not) to evaluate whether multiple symbols have been defined. You can also group symbols and operators with parentheses.
#define DEBUG
#define MYTEST
using System;
public class MyClass
{
static void Main()
{
#if (DEBUG && !MYTEST)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && MYTEST)
Console.WriteLine("MYTEST is defined");
#elif (DEBUG && MYTEST)
Console.WriteLine("DEBUG and MYTEST are defined");
#else
Console.WriteLine("DEBUG and MYTEST are not defined");
#endif
}
}
Here simple code how to do it. You can read full documentation on C# Preprocessor Directives
Yes. These are called "preprocessor directives" or compiler directives.
This question already has answers here:
C# !Conditional attribute?
(8 answers)
Closed 8 years ago.
What is the C# System.Diagnostics.Conditional equivalent of #if (!DEBUG)?
I want to encrypt a section of the app.config file of a console application if it has not been compiled in DEBUG mode. This is achieved like so:
public static void Main(string[] args)
{
#if (!DEBUG)
ConfigEncryption.EncryptAppSettings();
#endif
//...
}
but somehow, I prefer decorating the encrypt method with a conditional attribute:
[Conditional("!DEBUG")]
internal static void EncryptAppSettings()
{
//...
}
however this makes the compiler sad: The argument to the 'System.Diagnostics.ConditionalAttribute' attribute must be a valid identifier...
What is the correct syntax for negating the Conditional argument?
EDIT:
Thanks to #Gusdor, I used this (I preferred to keep the Program.cs file free of if/else debug logic):
#if !DEBUG
#define ENCRYPT_CONFIG
#endif
[Conditional("ENCRYPT_CONFIG")]
internal static void EncryptAppSettings()
{
//...
}
Using the attribute will be a bit of a hack but it can be done.
#if DEBUG
//you have nothing to do here but c# requires it
#else
#define NOT_DEBUG //define a symbol specifying a non debug environment
#endif
[Conditional("NOT_DEBUG")]
internal static void EncryptAppSettings()
{
//...
}
#if DEBUG
// do nothing
#else
//your code here
#endif
I am attempting to use Pre-compiler directives to toggle certain features in my application. I am using Pre-compiler directives as opposed to const static variables because these features will not occur in the release version of the application.
Is it true that C# does not allow for all C Pre-compiler commands, ie, #if X > Y & etc.? My below code is throwing compiler errors. Is it possible to use Pre-compiler directives to toggle functionality in my application?
My solution is a very 'C++/C' way of achieving this functionality. What is the C# way of achieving this functionality?
#define DEBUG 1 // Not allowed to assign values to constants?
#define USE_ALTERNATE_METHOD 0
public class MyApplication
{
public MyApplication()
{
#if DBEUG > 0 // Not allowed these kinds of directives?
RegressionTests.Run();
#endif // DEBUG > 0
}
public void myMethod
{
#if USE_ALTERNATE_METHOD > 0
// Do alternate stuff
#else
// Do regular stuff
#endif // USE_ALTERNATE_METHOD > 0
}
}
Specifying just #if DEBUG does the work.
You cannot use pre-processor definitives like #define DEBUG 1 .
However you can just specify #define DEBUG or #define CustomDefinition and use it with the Conditional attribute.
Eg,
You can just do this:
#if DEBUG
Console.WriteLine("This will work in DEBUG mode alone");
#endif
Or you can specify conditional-attributes on top of the method that you wanna execute only in the debug mode.
Eg,
[Conditional("DEBUG")]
void ExecuteOnlyInDebugMode()
{
// do stuff you wanna do.
}
For your example it has to be like this:
#define DEBUG
#define USE_ALTERNATE_METHOD
public class MyApplication
{
public MyApplication()
{
#if DEBUG
RegressionTests.Run();
#endif
}
public void myMethod
{
#if USE_ALTERNATE_METHOD
// Do alternate stuff
//do not execute the following. just return.
#endif
// Do regular stuff
}
}
You can find more info here . Beautifully explained.
Also, read more that Conditional attribute, here.
How do find 32BitProcess running on 64BitOperatingSystem using C# Preprocessor directivies.
For More info, i need to declare the dll name(based on the bit) to access the extern function. I need the following code using Preprocessor way.
public String WABDll;
if (64Bit)
{
WABDll = "Win-64.dll";
}
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
else if(32Bit)
{
WABDll = "Win-32.dll";
}
i tried the following way
#if _64BIT
public const String WABDll = "Win-64.dll";
#elif _32BIT
public const String WABDll = "Win-32on64.dll";
#else
public const String WABDll = "Win-32.dll";
#endif
Any Suggestions.
Don't do this with preprocessor directives; determine the environment at runtime using the Environment class. The Is64BitOperatingSystem and Is64BitProcess properties should give you the information you need.
You can't solve this:
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
compile time, since compiler does not know in advance where the program will run.
I can suggest you creating more solution "paltform", declaring some custom compiler flag and using them accordingly. Of course you need to know deploy time which executable must run on which platform.