// Copyright (c) 2012-2020 Flax Engine. All rights reserved.
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Flax.Build
{
///
/// Utility for building C# assemblies from custom set of source files.
///
public class Assembler
{
///
/// The default assembly references added to the projects.
///
public static readonly Assembly[] DefaultReferences =
{
//typeof(IntPtr).Assembly, // mscorlib.dll
typeof(Enumerable).Assembly, // System.Linq.dll
typeof(ISet<>).Assembly, // System.dll
typeof(Builder).Assembly, // Flax.Build.exe
};
///
/// The output assembly path. Use null to store assembly in the process memory.
///
public string OutputPath = null;
///
/// The source files for compilation.
///
public readonly List SourceFiles = new List();
///
/// The external user assembly references to use while compiling
///
public readonly List Assemblies = new List();
///
/// The external user assembly file names to use while compiling
///
public readonly List References = new List();
///
/// Builds the assembly.
///
/// Throws an exception in case of any errors.
/// The created and loaded assembly.
public Assembly Build()
{
Dictionary providerOptions = new Dictionary();
providerOptions.Add("CompilerVersion", "v4.0");
CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider(providerOptions);
// Collect references
HashSet references = new HashSet();
foreach (var defaultReference in DefaultReferences)
references.Add(defaultReference.Location);
foreach (var assemblyFile in References)
references.Add(assemblyFile);
foreach (var assembly in Assemblies)
{
if (!assembly.IsDynamic)
references.Add(assembly.Location);
}
// Setup compilation options
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.WarningLevel = 4;
cp.TreatWarningsAsErrors = false;
cp.ReferencedAssemblies.AddRange(references.ToArray());
if (string.IsNullOrEmpty(OutputPath))
{
cp.GenerateInMemory = true;
cp.IncludeDebugInformation = false;
}
else
{
cp.GenerateInMemory = false;
cp.IncludeDebugInformation = true;
cp.OutputAssembly = OutputPath;
}
// HACK: C# will give compilation errors if a LIB variable contains non-existing directories
Environment.SetEnvironmentVariable("LIB", null);
// Run the compilation
CompilerResults cr = provider.CompileAssemblyFromFile(cp, SourceFiles.ToArray());
// Process warnings and errors
bool hasError = false;
foreach (CompilerError ce in cr.Errors)
{
if (ce.IsWarning)
{
Log.Warning(string.Format("{0} at {1}: {2}", ce.FileName, ce.Line, ce.ErrorText));
}
else
{
Log.Error(string.Format("{0} at line {1}: {2}", ce.FileName, ce.Line, ce.ErrorText));
hasError = true;
}
}
if (hasError)
throw new Exception("Failed to build assembly.");
return cr.CompiledAssembly;
}
}
}