4 using System.Collections.Generic;
7 using System.Reflection;
8 using System.Runtime.CompilerServices;
9 using System.Runtime.Versioning;
11 using System.Text.RegularExpressions;
14 using Mono.Cecil.Rocks;
15 using SiliconStudio.Core;
19 namespace SiliconStudio.AssemblyProcessor
25 SearchDirectories =
new List<string>();
26 ModuleInitializer =
true;
29 public bool AutoNotifyProperty {
get; set; }
31 public bool ParameterKey {
get; set; }
33 public bool ModuleInitializer {
get; set; }
35 public bool SerializationAssembly {
get; set; }
37 public bool GenerateUserDocumentation {
get; set; }
39 public string NewAssemblyName {
get; set; }
43 public string TargetFramework {
get; set; }
45 public List<string> SearchDirectories {
get; set; }
47 public string SignKeyFile {
get; set; }
49 public bool UseSymbols {
get; set; }
55 public bool Run(
string inputFile,
string outputFile = null)
57 if (inputFile == null)
throw new ArgumentNullException(
"inputFile");
58 if (outputFile == null)
60 outputFile = inputFile;
65 var processors =
new List<IAssemblyDefinitionProcessor>();
78 if (NewAssemblyName != null)
90 if (SerializationAssembly)
95 if (GenerateUserDocumentation)
100 if (ModuleInitializer)
108 assemblyResolver.RemoveSearchDirectory(
".");
109 foreach (
string searchDirectory
in SearchDirectories)
110 assemblyResolver.AddSearchDirectory(searchDirectory);
113 var readWriteSymbols = UseSymbols;
115 var symbolFile = Path.ChangeExtension(inputFile,
"pdb");
116 if (!
File.Exists(symbolFile))
118 readWriteSymbols =
false;
121 var assemblyDefinition = AssemblyDefinition.ReadAssembly(inputFile,
new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols });
124 readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;
128 if (assemblyDefinition.CustomAttributes.Any(x => x.AttributeType.FullName ==
"SiliconStudio.Core.AssemblyProcessedAttribute"))
130 OnInfoAction(
"Assembly has already been processed, skip it.");
134 var targetFrameworkAttribute = assemblyDefinition.CustomAttributes
135 .FirstOrDefault(x => x.AttributeType.FullName == typeof(TargetFrameworkAttribute).FullName);
136 var targetFramework = targetFrameworkAttribute != null ? (string)targetFrameworkAttribute.ConstructorArguments[0].Value : null;
146 case PlatformType.Android:
148 if (
string.IsNullOrEmpty(TargetFramework))
150 throw new InvalidOperationException(
"Expecting option target framework for Android");
153 var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Reference Assemblies\Microsoft\Framework\MonoAndroid");
154 frameworkFolder = Path.Combine(monoAndroidPath,
"v1.0");
155 var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework);
156 assemblyResolver.AddSearchDirectory(additionalFrameworkFolder);
157 assemblyResolver.AddSearchDirectory(frameworkFolder);
161 case PlatformType.iOS:
163 if (
string.IsNullOrEmpty(TargetFramework))
165 throw new InvalidOperationException(
"Expecting option target framework for iOS");
168 var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Reference Assemblies\Microsoft\Framework\MonoTouch");
169 frameworkFolder = Path.Combine(monoAndroidPath,
"v1.0");
170 var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework);
171 assemblyResolver.AddSearchDirectory(additionalFrameworkFolder);
172 assemblyResolver.AddSearchDirectory(frameworkFolder);
177 case PlatformType.WindowsStore:
179 if (
string.IsNullOrEmpty(TargetFramework))
181 throw new InvalidOperationException(
"Expecting option target framework for WindowsStore");
184 frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Reference Assemblies\Microsoft\Framework\.NETCore", TargetFramework);
185 assemblyResolver.AddSearchDirectory(frameworkFolder);
188 var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Windows Kits\8.1\References\CommonConfiguration\Neutral\",
"Windows.winmd");
189 var windowsAssembly = AssemblyDefinition.ReadAssembly(windowsAssemblyPath,
new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols =
false });
190 assemblyResolver.Register(windowsAssembly);
195 case PlatformType.WindowsPhone:
197 if (
string.IsNullOrEmpty(TargetFramework))
199 throw new InvalidOperationException(
"Expecting option target framework for WindowsPhone");
203 frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Reference Assemblies\Microsoft\Framework\WindowsPhoneApp",
"v8.1");
204 assemblyResolver.AddSearchDirectory(frameworkFolder);
207 var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(),
@"Windows Phone Kits\8.1\References\CommonConfiguration\Neutral\",
"Windows.winmd");
208 var windowsAssembly = AssemblyDefinition.ReadAssembly(windowsAssemblyPath,
new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols =
false });
209 assemblyResolver.Register(windowsAssembly);
215 if (SerializationAssembly)
221 var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
222 var stringType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(
string).FullName);
223 var internalsVisibleToAttribute = mscorlibAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName);
224 var serializationAssemblyName = assemblyDefinition.Name.Name +
".Serializers";
225 bool internalsVisibleAlreadyApplied =
false;
228 foreach (var customAttribute
in assemblyDefinition.CustomAttributes.Where(x => x.AttributeType.FullName == internalsVisibleToAttribute.FullName))
230 var assemblyName = (string)customAttribute.ConstructorArguments[0].Value;
233 if ((publicKeyIndex = assemblyName.IndexOf(
", PublicKey=", StringComparison.InvariantCulture)) != -1 || (publicKeyIndex = assemblyName.IndexOf(
",PublicKey=", StringComparison.InvariantCulture)) != -1)
235 assemblyName = assemblyName.Substring(0, publicKeyIndex);
238 if (assemblyName == serializationAssemblyName)
240 internalsVisibleAlreadyApplied =
true;
245 if (!internalsVisibleAlreadyApplied)
248 if (assemblyDefinition.Name.HasPublicKey)
249 serializationAssemblyName +=
", PublicKey=" + ByteArrayToString(assemblyDefinition.Name.PublicKey);
252 var internalsVisibleToAttributeCtor = assemblyDefinition.MainModule.Import(internalsVisibleToAttribute.GetConstructors().Single());
253 var internalsVisibleAttribute =
new CustomAttribute(internalsVisibleToAttributeCtor)
255 ConstructorArguments =
257 new CustomAttributeArgument(assemblyDefinition.MainModule.Import(stringType), serializationAssemblyName)
260 assemblyDefinition.CustomAttributes.Add(internalsVisibleAttribute);
263 assemblyDefinition.Write(inputFile,
new WriterParameters() { WriteSymbols = readWriteSymbols });
266 assemblyDefinition = AssemblyDefinition.ReadAssembly(inputFile,
new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols });
269 readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;
274 bool modified =
false;
278 foreach (var processor
in processors)
279 modified = processor.Process(assemblyProcessorContext) || modified;
282 assemblyDefinition = assemblyProcessorContext.Assembly;
284 if (modified || inputFile != outputFile)
288 var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
289 if (mscorlibAssembly == null)
291 OnErrorAction(
"Missing mscorlib.dll from assembly");
295 var attributeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof (Attribute).FullName);
296 var attributeTypeRef = assemblyDefinition.MainModule.Import(attributeType);
297 var attributeCtorRef = assemblyDefinition.MainModule.Import(attributeType.GetConstructors().Single(x => x.Parameters.Count == 0));
298 var voidType = assemblyDefinition.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(
"System.Void"));
305 assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
306 assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, attributeCtorRef));
307 assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
308 assemblyProcessedAttributeType.Methods.Add(assemblyProcessedAttributeConstructor);
311 var outputDirectory = Path.GetDirectoryName(outputFile);
312 if (!
string.IsNullOrEmpty(outputDirectory) && !Directory.Exists(outputDirectory))
314 Directory.CreateDirectory(outputDirectory);
318 assemblyDefinition.MainModule.Types.Add(assemblyProcessedAttributeType);
319 assemblyDefinition.CustomAttributes.Add(
new CustomAttribute(assemblyProcessedAttributeConstructor));
320 assemblyDefinition.Write(outputFile,
new WriterParameters() { WriteSymbols = readWriteSymbols });
325 OnErrorAction(e.Message, e);
334 var result =
new StringBuilder(bytes.Length * 2);
335 foreach (byte
b in bytes)
336 result.AppendFormat(
"{0:x2}",
b);
337 return result.ToString();
340 private void OnErrorAction(
string errorMessage,
Exception exception = null)
342 if (OnErrorEvent == null)
344 var builder =
new StringBuilder();
345 builder.AppendLine(errorMessage);
346 if (exception != null)
348 builder.AppendLine(exception.ToString());
349 var nextE = exception;
350 for (
int index = 0; nextE != null; nextE = nextE.InnerException, index++)
351 builder.AppendFormat(
"{0}{1}",
string.Concat(Enumerable.Repeat(
" ", index)), nextE.Message).AppendLine();
352 builder.AppendLine();
355 Console.WriteLine(builder);
359 OnErrorEvent(errorMessage, exception);
363 private void OnInfoAction(
string infoMessage)
365 if (OnInfoEvent == null)
367 Console.WriteLine(infoMessage);
371 OnInfoEvent(infoMessage);
PlatformType
Describes the platform operating system.
Mono.Cecil.TypeAttributes TypeAttributes
Action< string > OnInfoEvent
static string ByteArrayToString(byte[] bytes)
Mono.Cecil.MethodAttributes MethodAttributes
static string ProgramFilesx86()
Get Program Files x86
Action< string, Exception > OnErrorEvent
bool Run(string inputFile, string outputFile=null)