private static ILProcessor NotImplementedBody(MethodDefinition method) { var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(method.Module.Assembly); var notImplementedExceptionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(NotImplementedException).FullName); method.Body = new MethodBody(method); var il = method.Body.GetILProcessor(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Newobj, method.Module.ImportReference(notImplementedExceptionType.GetConstructors().Single(x => !x.IsStatic && !x.HasParameters))); il.Emit(OpCodes.Throw); return(il); }
public UpdatableListCodeGenerator(AssemblyDefinition assembly) : base(assembly) { declaringType = assembly.MainModule.GetType("SiliconStudio.Xenko.Updater.UpdatableListAccessor`1"); indexField = assembly.MainModule.GetType("SiliconStudio.Xenko.Updater.UpdatableListAccessor").Fields.First(x => x.Name == "Index"); // TODO: Update to new method to resolve collection assembly var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); var ilistType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(IList <>).FullName); var ilistItem = ilistType.Properties.First(x => x.Name == "Item"); ilistGetItem = assembly.MainModule.ImportReference(ilistItem.GetMethod).MakeGeneric(declaringType.GenericParameters[0]); ilistSetItem = assembly.MainModule.ImportReference(ilistItem.SetMethod).MakeGeneric(declaringType.GenericParameters[0]); }
public bool Process(AssemblyProcessorContext context) { var assembly = context.Assembly; var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); if (mscorlibAssembly == null) { throw new InvalidOperationException("Missing mscorlib.dll from assembly"); } // Resolve mscorlib types var assemblyFileVersionAttributeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(AssemblyFileVersionAttribute).FullName); var assemblyMethodConstructor = assembly.MainModule.ImportReference(assemblyFileVersionAttributeType.Methods.FirstOrDefault(method => method.IsConstructor && method.Parameters.Count == 1)); var stringType = assembly.MainModule.TypeSystem.String; // TODO: Git Commit SHA var gitCommitShortId = "0"; // Use epoch time to get a "unique" build number (different each time) var build = (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds; // Get current AssemblyVersion and clone it var version = assembly.Name.Version; var fileVersion = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, build, gitCommitShortId); // Copy build/revision to the AssemblyFileVersion bool fileVersionUpdated = false; for (int i = 0; i < assembly.CustomAttributes.Count; i++) { var customAttribute = assembly.CustomAttributes[i]; if (customAttribute.AttributeType.FullName == typeof(AssemblyFileVersionAttribute).FullName) { customAttribute.ConstructorArguments.Clear(); customAttribute.ConstructorArguments.Add(new CustomAttributeArgument(stringType, fileVersion)); fileVersionUpdated = true; break; } } if (!fileVersionUpdated) { var assemblyFileVersion = new CustomAttribute(assemblyMethodConstructor); assemblyFileVersion.ConstructorArguments.Add(new CustomAttributeArgument(stringType, fileVersion)); assembly.CustomAttributes.Add(assemblyFileVersion); } return(true); }
private void EnsureInitialized(AssemblyProcessorContext context) { if (isInitialized) { return; } var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly); siliconStudioCoreAssembly = context.Assembly.Name.Name == "SiliconStudio.Core" ? context.Assembly : context.AssemblyResolver.Resolve(new AssemblyNameReference("SiliconStudio.Core", null)); pooledClosureType = context.Assembly.MainModule.ImportReference(siliconStudioCoreAssembly.MainModule.GetType("SiliconStudio.Core.Threading.IPooledClosure")); // Func type and it's contructor var funcType = mscorlibAssembly.MainModule.GetTypeResolved("System.Func`1"); funcConstructor = context.Assembly.MainModule.ImportReference(funcType.Methods.FirstOrDefault(x => x.Name == ".ctor")); // Pool type and it's constructor var poolTypeDefinition = siliconStudioCoreAssembly.MainModule.GetType("SiliconStudio.Core.Threading.ConcurrentPool`1"); poolType = context.Assembly.MainModule.ImportReference(poolTypeDefinition); poolConstructor = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == ".ctor")); poolAcquireMethod = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == "Acquire")); poolReleaseMethod = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == "Release")); // Interlocked (either from mscorlib.dll or System.Threading.dll) var interlockedTypeDefinition = mscorlibAssembly.MainModule.GetTypeResolved("System.Threading.Interlocked"); if (interlockedTypeDefinition == null) { var threadingAssembly = context.AssemblyResolver.Resolve(new AssemblyNameReference("System.Threading", null)); interlockedTypeDefinition = threadingAssembly.MainModule.GetTypeResolved("System.Threading.Interlocked"); } var interlockedType = context.Assembly.MainModule.ImportReference(interlockedTypeDefinition); // NOTE: We create method references manually, because ImportReference imports a different version of the runtime, causing interlockedIncrementMethod = new MethodReference("Increment", context.Assembly.MainModule.TypeSystem.Int32, interlockedType); interlockedIncrementMethod.Parameters.Add(new ParameterDefinition("", ParameterAttributes.None, context.Assembly.MainModule.TypeSystem.Int32.MakeByReferenceType())); //interlockedIncrementMethod = context.Assembly.MainModule.ImportReference(interlockedType.Methods.FirstOrDefault(x => x.Name == "Increment" && x.ReturnType.MetadataType == MetadataType.Int32)); interlockedDecrementMethod = new MethodReference("Decrement", context.Assembly.MainModule.TypeSystem.Int32, interlockedType); interlockedDecrementMethod.Parameters.Add(new ParameterDefinition("", ParameterAttributes.None, context.Assembly.MainModule.TypeSystem.Int32.MakeByReferenceType())); //interlockedDecrementMethod = context.Assembly.MainModule.ImportReference(interlockedType.Methods.FirstOrDefault(x => x.Name == "Decrement" && x.ReturnType.MetadataType == MetadataType.Int32)); isInitialized = true; }
public bool Process(AssemblyProcessorContext context) { this.assembly = context.Assembly; mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); if (mscorlibAssembly == null) { LogError("Missing mscorlib.dll from assembly {0}", assembly.FullName); throw new InvalidOperationException("Missing mscorlib.dll from assembly"); } // Import void* and int32 from assembly using mscorlib specific version (2.0 or 4.0 depending on assembly) voidType = mscorlibAssembly.MainModule.GetTypeResolved("System.Void"); voidPointerType = new PointerType(assembly.MainModule.Import(voidType)); intType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved("System.Int32")); // Remove CompilationRelaxationsAttribute if (context.Platform == PlatformType.WindowsStore || context.Platform == PlatformType.WindowsPhone) { for (int i = 0; i < assembly.CustomAttributes.Count; i++) { var customAttribute = assembly.CustomAttributes[i]; if (customAttribute.AttributeType.FullName == typeof(CompilationRelaxationsAttribute).FullName) { assembly.CustomAttributes.RemoveAt(i); i--; } } } Log("Patch for assembly [{0}]", assembly.FullName); foreach (var type in assembly.MainModule.Types) { PatchType(type); } // Remove All Interop classes foreach (var type in classToRemoveList) { assembly.MainModule.Types.Remove(type); } return(true); }
private static void RegisterDefaultSerializationProfile(IAssemblyResolver assemblyResolver, AssemblyDefinition assembly, ComplexSerializerCodeGenerator generator, TextWriter log) { var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); if (mscorlibAssembly == null) { log.WriteLine("Missing mscorlib.dll from assembly {0}", assembly.FullName); throw new InvalidOperationException("Missing mscorlib.dll from assembly"); } var coreSerializationAssembly = assemblyResolver.Resolve("SiliconStudio.Core"); // Register serializer factories (determine which type requires which serializer) generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(IList <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ListInterfaceSerializer`1"))); generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(List <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ListSerializer`1"))); generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(KeyValuePair <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.KeyValuePairSerializer`2"))); generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(IDictionary <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.DictionaryInterfaceSerializer`2"))); generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(Dictionary <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.DictionarySerializer`2"))); generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(Nullable <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.NullableSerializer`1"))); generator.SerializerFactories.Add(new CecilEnumSerializerFactory(coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.EnumSerializer`1"))); generator.SerializerFactories.Add(new CecilArraySerializerFactory(coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1"))); // Iterate over tuple size for (int i = 1; i <= 4; ++i) { generator.SerializerDependencies.Add(new CecilSerializerDependency( string.Format("System.Tuple`{0}", i), coreSerializationAssembly.MainModule.GetTypeResolved(string.Format("SiliconStudio.Core.Serialization.Serializers.TupleSerializer`{0}", i)))); generator.SerializerDependencies.Add(new CecilSerializerDependency(string.Format("SiliconStudio.Core.Serialization.Serializers.TupleSerializer`{0}", i))); } // Register serializer dependencies (determine which serializer serializes which sub-type) generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1")); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.KeyValuePairSerializer`2")); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ListSerializer`1")); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ListInterfaceSerializer`1")); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.NullableSerializer`1")); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.DictionarySerializer`2", mscorlibAssembly.MainModule.GetTypeResolved(typeof(KeyValuePair <,>).FullName))); generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.DictionaryInterfaceSerializer`2", mscorlibAssembly.MainModule.GetTypeResolved(typeof(KeyValuePair <,>).FullName))); }
public bool Run(ref AssemblyDefinition assemblyDefinition, ref bool readWriteSymbols, out bool modified) { modified = false; try { var assemblyResolver = (CustomAssemblyResolver)assemblyDefinition.MainModule.AssemblyResolver; // Register self assemblyResolver.Register(assemblyDefinition); var processors = new List <IAssemblyDefinitionProcessor>(); // We are no longer using it so we are deactivating it for now to avoid processing //if (AutoNotifyProperty) //{ // processors.Add(new NotifyPropertyProcessor()); //} processors.Add(new AddReferenceProcessor(ReferencesToAdd)); if (ParameterKey) { processors.Add(new ParameterKeyProcessor()); } if (NewAssemblyName != null) { processors.Add(new RenameAssemblyProcessor(NewAssemblyName)); } //processors.Add(new AsyncBridgeProcessor()); // Always applies the interop processor processors.Add(new InteropProcessor()); processors.Add(new AssemblyVersionProcessor()); if (DocumentationFile != null) { processors.Add(new GenerateUserDocumentationProcessor(DocumentationFile)); } var roslynExtraCodeProcessor = new RoslynExtraCodeProcessor(SignKeyFile, References, MemoryReferences, log); if (SerializationAssembly) { processors.Add(new SerializationProcessor(roslynExtraCodeProcessor.SourceCodes.Add)); } processors.Add(roslynExtraCodeProcessor); if (ModuleInitializer) { processors.Add(new ModuleInitializerProcessor()); } processors.Add(new InitLocalsProcessor()); processors.Add(new OpenSourceSignProcessor()); // Check if pdb was actually read readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader; // Check if there is already a AssemblyProcessedAttribute (in which case we can skip processing, it has already been done). // Note that we should probably also match the command line as well so that we throw an error if processing is different (need to rebuild). if (assemblyDefinition.CustomAttributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.AssemblyProcessedAttribute")) { OnInfoAction($"Assembly [{assemblyDefinition.Name}] has already been processed, skip it."); return(true); } // Register references so that our assembly resolver can use them foreach (var reference in References) { assemblyResolver.RegisterReference(reference); } if (SerializationAssembly) { // Resave a first version of assembly with [InteralsVisibleTo] for future serialization assembly. // It will be used by serialization assembly compilation. // It's recommended to do it in the original code to avoid this extra step. var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition); if (mscorlibAssembly == null) { OnErrorAction("Missing reference to mscorlib.dll or System.Runtime.dll in assembly!"); return(false); } var internalsVisibleToAttribute = mscorlibAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = assemblyDefinition.Name.Name + ".Serializers"; bool internalsVisibleAlreadyApplied = false; // Check if already applied foreach (var customAttribute in assemblyDefinition.CustomAttributes.Where(x => x.AttributeType.FullName == internalsVisibleToAttribute.FullName)) { var assemblyName = (string)customAttribute.ConstructorArguments[0].Value; int publicKeyIndex; if ((publicKeyIndex = assemblyName.IndexOf(", PublicKey=", StringComparison.InvariantCulture)) != -1 || (publicKeyIndex = assemblyName.IndexOf(",PublicKey=", StringComparison.InvariantCulture)) != -1) { assemblyName = assemblyName.Substring(0, publicKeyIndex); } if (assemblyName == serializationAssemblyName) { internalsVisibleAlreadyApplied = true; break; } } if (!internalsVisibleAlreadyApplied) { // Apply public key if (assemblyDefinition.Name.HasPublicKey) { serializationAssemblyName += ", PublicKey=" + ByteArrayToString(assemblyDefinition.Name.PublicKey); } // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = assemblyDefinition.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(assemblyDefinition.MainModule.TypeSystem.String, serializationAssemblyName) } }; assemblyDefinition.CustomAttributes.Add(internalsVisibleAttribute); var assemblyFilePath = assemblyDefinition.MainModule.FullyQualifiedName; if (string.IsNullOrEmpty(assemblyFilePath)) { assemblyFilePath = Path.ChangeExtension(Path.GetTempFileName(), ".dll"); } // Save updated file assemblyDefinition.Write(assemblyFilePath, new WriterParameters() { WriteSymbols = readWriteSymbols }); // Reread file (otherwise it seems Mono Cecil is buggy and generate invalid PDB) assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFilePath, new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols }); // Check if pdb was actually read readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader; } } var assemblyProcessorContext = new AssemblyProcessorContext(assemblyResolver, assemblyDefinition, Platform, log); foreach (var processor in processors) { modified = processor.Process(assemblyProcessorContext) || modified; } // Assembly might have been recreated (i.e. il-repack), so let's use it from now on assemblyDefinition = assemblyProcessorContext.Assembly; if (modified) { // In case assembly has been modified, // add AssemblyProcessedAttribute to assembly so that it doesn't get processed again var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition); if (mscorlibAssembly == null) { OnErrorAction("Missing reference to mscorlib.dll or System.Runtime.dll in assembly!"); return(false); } var attributeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Attribute).FullName); var attributeTypeRef = assemblyDefinition.MainModule.ImportReference(attributeType); var attributeCtorRef = assemblyDefinition.MainModule.ImportReference(attributeType.GetConstructors().Single(x => x.Parameters.Count == 0)); var voidType = assemblyDefinition.MainModule.TypeSystem.Void; // Create custom attribute var assemblyProcessedAttributeType = new TypeDefinition("SiliconStudio.Core", "AssemblyProcessedAttribute", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Public, attributeTypeRef); // Add constructor (call parent constructor) var assemblyProcessedAttributeConstructor = new MethodDefinition(".ctor", MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, voidType); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, attributeCtorRef)); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); assemblyProcessedAttributeType.Methods.Add(assemblyProcessedAttributeConstructor); // Add AssemblyProcessedAttribute to assembly assemblyDefinition.MainModule.Types.Add(assemblyProcessedAttributeType); assemblyDefinition.CustomAttributes.Add(new CustomAttribute(assemblyProcessedAttributeConstructor)); } } catch (Exception e) { OnErrorAction(null, e); return(false); } return(true); }
public bool Process(AssemblyProcessorContext context) { var assembly = context.Assembly; var fields = new List <FieldDefinition>(); var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); if (mscorlibAssembly == null) { throw new InvalidOperationException("Missing mscorlib.dll from assembly"); } MethodDefinition parameterKeysMergeMethod = null; TypeDefinition assemblyEffectKeysAttributeType = null; var getTypeFromHandleMethod = new Lazy <MethodReference>(() => { // Find Type.GetTypeFromHandle var typeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); return(assembly.MainModule.Import(typeType.Methods.First(x => x.Name == "GetTypeFromHandle"))); }); var effectKeysStaticConstructors = new List <MethodReference>(); foreach (var type in assembly.MainModule.GetTypes()) { fields.Clear(); foreach (var field in type.Fields.Where(x => x.IsStatic)) { var fieldBaseType = field.FieldType; while (fieldBaseType != null) { if (fieldBaseType.FullName == "SiliconStudio.Paradox.Effects.ParameterKey") { break; } var resolvedFieldBaseType = fieldBaseType.Resolve(); if (resolvedFieldBaseType == null) { fieldBaseType = null; break; } fieldBaseType = resolvedFieldBaseType.BaseType; } if (fieldBaseType == null) { continue; } fields.Add(field); } if (fields.Count == 0) { continue; } // ParameterKey present means we should have a static cctor. var cctor = type.GetStaticConstructor(); if (cctor == null) { continue; } // Load necessary SiliconStudio.Paradox methods/attributes if (parameterKeysMergeMethod == null) { AssemblyDefinition paradoxEngineAssembly; try { paradoxEngineAssembly = assembly.Name.Name == "SiliconStudio.Paradox" ? assembly : context.AssemblyResolver.Resolve("SiliconStudio.Paradox"); } catch (Exception) { Console.WriteLine("Error, cannot find [SiliconStudio.Paradox] assembly for processing ParameterKeyProcessor"); // We can't generate an exception, so we are just returning. It means that SiliconStudio.Paradox has not been generated so far. return(true); } var parameterKeysType = paradoxEngineAssembly.MainModule.GetTypes().First(x => x.Name == "ParameterKeys"); parameterKeysMergeMethod = parameterKeysType.Methods.First(x => x.Name == "Merge"); assemblyEffectKeysAttributeType = paradoxEngineAssembly.MainModule.GetTypes().First(x => x.Name == "AssemblyEffectKeysAttribute"); } var cctorIL = cctor.Body.GetILProcessor(); var cctorInstructions = cctor.Body.Instructions; var keyClassName = type.Name; if (keyClassName.EndsWith("Keys")) { keyClassName = keyClassName.Substring(0, keyClassName.Length - 4); } keyClassName += '.'; bool cctorModified = false; // Find field store instruction for (int i = 0; i < cctorInstructions.Count; ++i) { var fieldInstruction = cctorInstructions[i]; if (fieldInstruction.OpCode == OpCodes.Stsfld && fields.Contains(fieldInstruction.Operand)) { var activeField = (FieldReference)fieldInstruction.Operand; var nextInstruction = cctorInstructions[i + 1]; cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldsfld, activeField)); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldtoken, type)); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Call, getTypeFromHandleMethod.Value)); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldstr, keyClassName + activeField.Name)); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Call, assembly.MainModule.Import(parameterKeysMergeMethod))); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Castclass, activeField.FieldType)); cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Stsfld, activeField)); i = cctorInstructions.IndexOf(nextInstruction); cctorModified = true; } } if (cctorModified) { effectKeysStaticConstructors.Add(cctor); } } if (effectKeysStaticConstructors.Count > 0) { // Add [AssemblyEffectKeysAttribute] to the assembly assembly.CustomAttributes.Add(new CustomAttribute(assembly.MainModule.Import(assemblyEffectKeysAttributeType.GetConstructors().First(x => !x.HasParameters)))); // Get or create module static constructor var voidType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(void).FullName)); var moduleClass = assembly.MainModule.Types.First(t => t.Name == "<Module>"); var staticConstructor = moduleClass.GetStaticConstructor(); if (staticConstructor == null) { staticConstructor = new MethodDefinition(".cctor", MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, voidType); staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret)); moduleClass.Methods.Add(staticConstructor); } var il = staticConstructor.Body.GetILProcessor(); var returnInstruction = staticConstructor.Body.Instructions.Last(); var newReturnInstruction = Instruction.Create(returnInstruction.OpCode); newReturnInstruction.Operand = returnInstruction.Operand; returnInstruction.OpCode = OpCodes.Nop; returnInstruction.Operand = null; var typeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); var typeHandleProperty = typeType.Properties.First(x => x.Name == "TypeHandle"); var getTypeHandleMethod = assembly.MainModule.Import(typeHandleProperty.GetMethod); var runtimeHelpersType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(RuntimeHelpers).FullName); var runClassConstructorMethod = assembly.MainModule.Import(runtimeHelpersType.Methods.Single(x => x.IsPublic && x.Name == "RunClassConstructor" && x.Parameters.Count == 1 && x.Parameters[0].ParameterType.FullName == typeof(RuntimeTypeHandle).FullName)); // Call every key class static constructor from the module static constructor so that they are properly constructed (because accessing through reflection might cause problems) staticConstructor.Body.SimplifyMacros(); foreach (var effectKeysStaticConstructor in effectKeysStaticConstructors) { il.Append(Instruction.Create(OpCodes.Ldtoken, effectKeysStaticConstructor.DeclaringType)); il.Append(Instruction.Create(OpCodes.Call, getTypeFromHandleMethod.Value)); il.Append(Instruction.Create(OpCodes.Callvirt, getTypeHandleMethod)); il.Append(Instruction.Create(OpCodes.Call, runClassConstructorMethod)); } il.Append(newReturnInstruction); staticConstructor.Body.OptimizeMacros(); } return(true); }
public bool Run(ref AssemblyDefinition assemblyDefinition, ref bool readWriteSymbols, out bool modified) { modified = false; try { var assemblyResolver = (CustomAssemblyResolver)assemblyDefinition.MainModule.AssemblyResolver; var processors = new List <IAssemblyDefinitionProcessor>(); // We are no longer using it so we are deactivating it for now to avoid processing //if (AutoNotifyProperty) //{ // processors.Add(new NotifyPropertyProcessor()); //} if (ParameterKey) { processors.Add(new ParameterKeyProcessor()); } if (NewAssemblyName != null) { processors.Add(new RenameAssemblyProcessor(NewAssemblyName)); } //processors.Add(new AsyncBridgeProcessor()); // Always applies the interop processor processors.Add(new InteropProcessor()); processors.Add(new AssemblyVersionProcessor()); if (SerializationAssembly) { processors.Add(new SerializationProcessor(SignKeyFile, SerializationProjectReferences)); } if (GenerateUserDocumentation) { processors.Add(new GenerateUserDocumentationProcessor(assemblyDefinition.MainModule.FullyQualifiedName)); } if (ModuleInitializer) { processors.Add(new ModuleInitializerProcessor()); } processors.Add(new OpenSourceSignProcessor()); // Check if pdb was actually read readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader; // Check if there is already a AssemblyProcessedAttribute (in which case we can skip processing, it has already been done). // Note that we should probably also match the command line as well so that we throw an error if processing is different (need to rebuild). if (assemblyDefinition.CustomAttributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.AssemblyProcessedAttribute")) { OnInfoAction("Assembly has already been processed, skip it."); return(true); } var targetFrameworkAttribute = assemblyDefinition.CustomAttributes .FirstOrDefault(x => x.AttributeType.FullName == typeof(TargetFrameworkAttribute).FullName); var targetFramework = targetFrameworkAttribute != null ? (string)targetFrameworkAttribute.ConstructorArguments[0].Value : null; // Special handling for MonoAndroid // Default frameworkFolder var frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\"); switch (Platform) { case PlatformType.Android: { if (string.IsNullOrEmpty(TargetFramework)) { throw new InvalidOperationException("Expecting option target framework for Android"); } var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\MonoAndroid"); frameworkFolder = Path.Combine(monoAndroidPath, "v1.0"); var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework); assemblyResolver.AddSearchDirectory(additionalFrameworkFolder); assemblyResolver.AddSearchDirectory(frameworkFolder); break; } case PlatformType.iOS: { if (string.IsNullOrEmpty(TargetFramework)) { throw new InvalidOperationException("Expecting option target framework for iOS"); } var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\MonoTouch"); frameworkFolder = Path.Combine(monoAndroidPath, "v1.0"); var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework); assemblyResolver.AddSearchDirectory(additionalFrameworkFolder); assemblyResolver.AddSearchDirectory(frameworkFolder); break; } case PlatformType.WindowsStore: { if (string.IsNullOrEmpty(TargetFramework)) { throw new InvalidOperationException("Expecting option target framework for WindowsStore"); } frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\.NETCore", TargetFramework); assemblyResolver.AddSearchDirectory(frameworkFolder); // Add path to look for WinRT assemblies (Windows.winmd) var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Windows Kits\8.1\References\CommonConfiguration\Neutral\", "Windows.winmd"); var windowsAssembly = AssemblyDefinition.ReadAssembly(windowsAssemblyPath, new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = false }); assemblyResolver.Register(windowsAssembly); break; } case PlatformType.WindowsPhone: { if (string.IsNullOrEmpty(TargetFramework)) { throw new InvalidOperationException("Expecting option target framework for WindowsPhone"); } // Note: v8.1 is hardcoded because we currently receive v4.5.x as TargetFramework (different from TargetPlatformVersion) frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\WindowsPhoneApp", "v8.1"); assemblyResolver.AddSearchDirectory(frameworkFolder); // Add path to look for WinRT assemblies (Windows.winmd) var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Windows Phone Kits\8.1\References\CommonConfiguration\Neutral\", "Windows.winmd"); var windowsAssembly = AssemblyDefinition.ReadAssembly(windowsAssemblyPath, new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = false }); assemblyResolver.Register(windowsAssembly); break; } } if (SerializationAssembly) { // Resave a first version of assembly with [InteralsVisibleTo] for future serialization assembly. // It will be used by serialization assembly compilation. // It's recommended to do it in the original code to avoid this extra step. var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition); var stringType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(string).FullName); var internalsVisibleToAttribute = mscorlibAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = assemblyDefinition.Name.Name + ".Serializers"; bool internalsVisibleAlreadyApplied = false; // Check if already applied foreach (var customAttribute in assemblyDefinition.CustomAttributes.Where(x => x.AttributeType.FullName == internalsVisibleToAttribute.FullName)) { var assemblyName = (string)customAttribute.ConstructorArguments[0].Value; int publicKeyIndex; if ((publicKeyIndex = assemblyName.IndexOf(", PublicKey=", StringComparison.InvariantCulture)) != -1 || (publicKeyIndex = assemblyName.IndexOf(",PublicKey=", StringComparison.InvariantCulture)) != -1) { assemblyName = assemblyName.Substring(0, publicKeyIndex); } if (assemblyName == serializationAssemblyName) { internalsVisibleAlreadyApplied = true; break; } } if (!internalsVisibleAlreadyApplied) { // Apply public key if (assemblyDefinition.Name.HasPublicKey) { serializationAssemblyName += ", PublicKey=" + ByteArrayToString(assemblyDefinition.Name.PublicKey); } // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = assemblyDefinition.MainModule.Import(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(assemblyDefinition.MainModule.Import(stringType), serializationAssemblyName) } }; assemblyDefinition.CustomAttributes.Add(internalsVisibleAttribute); var assemblyFilePath = assemblyDefinition.MainModule.FullyQualifiedName; if (string.IsNullOrEmpty(assemblyFilePath)) { assemblyFilePath = Path.ChangeExtension(Path.GetTempFileName(), ".dll"); } // Save updated file assemblyDefinition.Write(assemblyFilePath, new WriterParameters() { WriteSymbols = readWriteSymbols }); // Reread file (otherwise it seems Mono Cecil is buggy and generate invalid PDB) assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFilePath, new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols }); // Check if pdb was actually read readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader; } } var assemblyProcessorContext = new AssemblyProcessorContext(assemblyResolver, assemblyDefinition, Platform); foreach (var processor in processors) { modified = processor.Process(assemblyProcessorContext) || modified; } // Assembly might have been recreated (i.e. il-repack), so let's use it from now on assemblyDefinition = assemblyProcessorContext.Assembly; if (modified) { // In case assembly has been modified, // add AssemblyProcessedAttribute to assembly so that it doesn't get processed again var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition); if (mscorlibAssembly == null) { OnErrorAction("Missing mscorlib.dll from assembly"); return(false); } var attributeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Attribute).FullName); var attributeTypeRef = assemblyDefinition.MainModule.Import(attributeType); var attributeCtorRef = assemblyDefinition.MainModule.Import(attributeType.GetConstructors().Single(x => x.Parameters.Count == 0)); var voidType = assemblyDefinition.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved("System.Void")); // Create custom attribute var assemblyProcessedAttributeType = new TypeDefinition("SiliconStudio.Core", "AssemblyProcessedAttribute", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Public, attributeTypeRef); // Add constructor (call parent constructor) var assemblyProcessedAttributeConstructor = new MethodDefinition(".ctor", MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, voidType); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, attributeCtorRef)); assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); assemblyProcessedAttributeType.Methods.Add(assemblyProcessedAttributeConstructor); // Add AssemblyProcessedAttribute to assembly assemblyDefinition.MainModule.Types.Add(assemblyProcessedAttributeType); assemblyDefinition.CustomAttributes.Add(new CustomAttribute(assemblyProcessedAttributeConstructor)); } } catch (Exception e) { OnErrorAction(e.Message, e); return(false); } return(true); }
public static AssemblyDefinition GenerateRoslynAssembly(CustomAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> references, List <AssemblyDefinition> memoryReferences, TextWriter log, IEnumerable <SourceCode> sourceCodes) { var sourceFolder = Path.GetDirectoryName(serializationAssemblyLocation); var syntaxTrees = sourceCodes.Select(x => { // It has a name, let's save it as a file string sourcePath = null; if (x.Name != null) { sourcePath = Path.Combine(sourceFolder, $"{x.Name}.cs"); File.WriteAllText(sourcePath, x.Code); } var result = CSharpSyntaxTree.ParseText(x.Code, null, sourcePath, Encoding.UTF8); return(result); }).ToArray(); var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default); // Sign the serialization assembly the same way the source was signed // TODO: Transmit over command line if (assembly.Name.HasPublicKey) { // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe? if (signKeyFile == null) { throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified."); } compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider()); if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned) { // Delay signed compilerOptions = compilerOptions.WithDelaySign(true); } } // Add references (files and in-memory PE data) var metadataReferences = new List <MetadataReference>(); foreach (var reference in assemblyResolver.References) { metadataReferences.Add(MetadataReference.CreateFromFile(reference)); } foreach (var reference in memoryReferences) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, reference)); } // typeof(Dictionary<,>) // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly)); var collectionAssembly = CecilExtensions.FindCollectionsAssembly(assembly); metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionAssembly)); metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly)); // In case SiliconStudio.Core was not referenced, let's add it. if (assembly.Name.Name != "SiliconStudio.Core" && !references.Any(x => string.Compare(Path.GetFileNameWithoutExtension(x), "SiliconStudio.Core", StringComparison.OrdinalIgnoreCase) == 0)) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core"))); } // Create roslyn compilation object var assemblyName = assembly.Name.Name + ".Serializers"; var compilation = CSharpCompilation.Create(assemblyName, syntaxTrees, metadataReferences, compilerOptions); // Do the actual compilation, and check errors using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write)) using (var pdbStream = new FileStream(Path.ChangeExtension(serializationAssemblyLocation, ".pdb"), FileMode.Create, FileAccess.Write)) { var compilationResult = compilation.Emit(peStream, pdbStream); if (!compilationResult.Success) { var errors = new StringBuilder(); errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error))); foreach (var error in compilationResult.Diagnostics) { if (error.Severity >= DiagnosticSeverity.Warning) { errors.AppendLine(error.ToString()); } } throw new InvalidOperationException(errors.ToString()); } } var repackOptions = new ILRepacking.RepackOptions(new string[0]) { OutputFile = assembly.MainModule.FullyQualifiedName, DebugInfo = true, CopyAttributes = true, AllowMultipleAssemblyLevelAttributes = true, XmlDocumentation = false, NoRepackRes = true, InputAssemblies = new[] { serializationAssemblyLocation }, SearchDirectories = assemblyResolver.GetSearchDirectories(), SearchAssemblies = references, }; // Run ILMerge var merge = new ILRepacking.ILRepack(repackOptions) { PrimaryAssemblyDefinition = assembly, MemoryOnly = true, //KeepFirstOfMultipleAssemblyLevelAttributes = true, //Log = true, //LogFile = "ilmerge.log", }; try { var consoleWriter = Console.Out; Console.SetOut(TextWriter.Null); try { merge.Repack(); } finally { Console.SetOut(consoleWriter); } } catch (Exception) { log.WriteLine($"Error while ILRepacking {assembly.Name.Name}"); throw; } // Copy name merge.TargetAssemblyDefinition.Name.Name = assembly.Name.Name; merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version; // Copy assembly characterics. This is necessary especially when targeting a windows app merge.TargetAssemblyMainModule.Characteristics = assembly.MainModule.Characteristics; // Add assembly signing info if (assembly.Name.HasPublicKey) { merge.TargetAssemblyDefinition.Name.PublicKey = assembly.Name.PublicKey; merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken; merge.TargetAssemblyDefinition.Name.Attributes |= AssemblyAttributes.PublicKey; if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned) { merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned; } } try { // Delete serializer dll File.Delete(serializationAssemblyLocation); var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb"); if (File.Exists(serializationAssemblyPdbFilePath)) { File.Delete(serializationAssemblyPdbFilePath); } } catch (IOException) { // Mute IOException } return(merge.TargetAssemblyDefinition); }
public void ProcessSerializers(CecilSerializerContext context) { var references = new HashSet <AssemblyDefinition>(); EnumerateReferences(references, context.Assembly); var coreAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly); // Only process assemblies depending on Xenko.Engine if (!references.Any(x => x.Name.Name == "SiliconStudio.Xenko.Engine")) { // Make sure Xenko.Engine.Serializers can access everything internally var internalsVisibleToAttribute = coreAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = "SiliconStudio.Xenko.Engine.Serializers"; // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = context.Assembly.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(context.Assembly.MainModule.ImportReference(context.Assembly.MainModule.TypeSystem.String), serializationAssemblyName) } }; context.Assembly.CustomAttributes.Add(internalsVisibleAttribute); return; } // Get or create method var updateEngineType = GetOrCreateUpdateType(context.Assembly, true); var mainPrepareMethod = new MethodDefinition("UpdateMain", MethodAttributes.HideBySig | MethodAttributes.Assembly | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); updateEngineType.Methods.Add(mainPrepareMethod); // Get some useful Cecil objects from SiliconStudio.Core var siliconStudioCoreAssembly = context.Assembly.Name.Name == "SiliconStudio.Core" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Core"); var siliconStudioCoreModule = siliconStudioCoreAssembly.MainModule; var siliconStudioXenkoEngineAssembly = context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Xenko.Engine"); var siliconStudioXenkoEngineModule = siliconStudioXenkoEngineAssembly.MainModule; // Generate IL for SiliconStudio.Core if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { ProcessXenkoEngineAssembly(context); } else { #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // We still process UpdatableProperty<T> since we had to revert it back when writing back Xenko.Engine (otherwise it crashes at AOT on iOS) new UpdatablePropertyCodeGenerator(siliconStudioXenkoEngineAssembly).GenerateUpdatablePropertyCode(); #endif } animationDataType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Animations.AnimationData`1"); var updatableFieldGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableField`1"); updatableFieldGenericCtor = updatableFieldGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); updatablePropertyGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableProperty`1"); updatablePropertyGenericCtor = updatablePropertyGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatablePropertyObjectGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatablePropertyObject`1"); updatablePropertyObjectGenericCtor = updatablePropertyObjectGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableListUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ListUpdateResolver`1"); updatableListUpdateResolverGenericCtor = updatableListUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableArrayUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ArrayUpdateResolver`1"); updatableArrayUpdateResolverGenericCtor = updatableArrayUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var registerMemberMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMember"); var pclVisitor = new PclFixupTypeVisitor(coreAssembly); pclVisitor.VisitMethod(registerMemberMethod); updateEngineRegisterMemberMethod = context.Assembly.MainModule.ImportReference(registerMemberMethod); var registerMemberResolverMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMemberResolver"); pclVisitor.VisitMethod(registerMemberResolverMethod); updateEngineRegisterMemberResolverMethod = context.Assembly.MainModule.ImportReference(registerMemberResolverMethod); var typeType = coreAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); getTypeFromHandleMethod = context.Assembly.MainModule.ImportReference(typeType.Methods.First(x => x.Name == "GetTypeFromHandle")); // Make sure it is called at module startup var moduleInitializerAttribute = siliconStudioCoreModule.GetType("SiliconStudio.Core.ModuleInitializerAttribute"); var ctorMethod = moduleInitializerAttribute.GetConstructors().Single(x => !x.IsStatic && !x.HasParameters); pclVisitor.VisitMethod(ctorMethod); mainPrepareMethod.CustomAttributes.Add(new CustomAttribute(context.Assembly.MainModule.ImportReference(ctorMethod))); // Emit serialization code for all the types we care about var processedTypes = new HashSet <TypeDefinition>(TypeReferenceEqualityComparer.Default); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes)) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } var typeDefinition = serializableType.Key as TypeDefinition; if (typeDefinition == null) { continue; } // Ignore already processed types if (!processedTypes.Add(typeDefinition)) { continue; } try { ProcessType(context, typeDefinition, mainPrepareMethod); } catch (Exception e) { throw new InvalidOperationException(string.Format("Error when generating update engine code for {0}", typeDefinition), e); } } // Force generic instantiations var il = mainPrepareMethod.Body.GetILProcessor(); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes).ToArray()) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } // Make sure AnimationData<T> is serializable //if (serializableType.Value.Mode == DataSerializerGenericMode.None) // context.GenerateSerializer(context.Assembly.MainModule.ImportReference(animationDataType).MakeGenericType(context.Assembly.MainModule.ImportReference(serializableType.Key))); // Try to find if original method definition was generated var typeDefinition = serializableType.Key.Resolve(); // If using List<T>, register this type in UpdateEngine var listInterfaceType = typeDefinition.Interfaces.OfType <GenericInstanceType>().FirstOrDefault(x => x.ElementType.FullName == typeof(IList <>).FullName); if (listInterfaceType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ListUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, listInterfaceType.GenericArguments[0]); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableListUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } // Same for arrays var arrayType = serializableType.Key as ArrayType; if (arrayType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ArrayUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, arrayType.ElementType); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableArrayUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } var genericInstanceType = serializableType.Key as GenericInstanceType; if (genericInstanceType != null) { var expectedUpdateMethodName = ComputeUpdateMethodName(typeDefinition); var updateMethod = GetOrCreateUpdateType(typeDefinition.Module.Assembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); // If nothing was found in main assembly, also look in SiliconStudio.Xenko.Engine assembly, just in case (it might defines some shared/corlib types -- currently not the case) if (updateMethod == null) { updateMethod = GetOrCreateUpdateType(siliconStudioXenkoEngineAssembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); } if (updateMethod != null) { // Emit call to update engine setup method with generic arguments of current type il.Emit(OpCodes.Call, context.Assembly.MainModule.ImportReference(updateMethod) .MakeGenericMethod(genericInstanceType.GenericArguments .Select(context.Assembly.MainModule.ImportReference) .Select(CecilExtensions.FixupValueType).ToArray())); } } } il.Emit(OpCodes.Ret); #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // Due to Xamarin iOS AOT limitation, we can't keep this type around because it fails compilation if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetStructAndUnbox")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetBlittable")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetStruct")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetBlittable")); } #endif }
public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> serializatonProjectReferencePaths) { // Make sure all assemblies in serializatonProjectReferencePaths are referenced (sometimes they might be optimized out if no direct references) foreach (var serializatonProjectReferencePath in serializatonProjectReferencePaths) { var shortAssemblyName = Path.GetFileNameWithoutExtension(serializatonProjectReferencePath); // Still in references (not optimized) if (assembly.MainModule.AssemblyReferences.Any(x => x.Name == shortAssemblyName)) { continue; } // For now, use AssemblyDefinition.ReadAssembly to compute full name -- maybe not very efficient but it shouldn't happen often anyway) var referencedAssembly = AssemblyDefinition.ReadAssembly(serializatonProjectReferencePath); assembly.MainModule.AssemblyReferences.Add(AssemblyNameReference.Parse(referencedAssembly.FullName)); } // Create the serializer code generator var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly); // Register default serialization profile (to help AOT generic instantiation of serializers) RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator); // Generate serializer code var serializerGeneratedCode = serializerGenerator.TransformText(); var syntaxTree = CSharpSyntaxTree.ParseText(serializerGeneratedCode); // Add reference from source assembly // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem. var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null"; var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true); // Sign the serialization assembly the same way the source was signed // TODO: Transmit over command line if (assembly.Name.HasPublicKey) { // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe? if (signKeyFile == null) { throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified."); } compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider()); if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned) { // Delay signed compilerOptions = compilerOptions.WithDelaySign(true); } } var metadataReferences = new List <MetadataReference>(); var assemblyLocations = new HashSet <string>(); foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences) { // We skip both Windows, and current assembly (AssemblyProcessor.Common, which might be added with an alias) if (referencedAssemblyName.FullName != skipWindows && referencedAssemblyName.FullName != typeof(ComplexSerializerGenerator).Assembly.FullName && referencedAssemblyName.FullName != "SiliconStudio.AssemblyProcessor") { if (assemblyLocations.Add(referencedAssemblyName.Name)) { //Console.WriteLine("Resolve Assembly for serialization [{0}]", referencedAssemblyName.FullName); metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve(referencedAssemblyName))); } } } // typeof(Dictionary<,>) // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly)); var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName); metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionType.Module.Assembly)); // Make sure System and System.Reflection are added // TODO: Maybe we should do that for .NETCore and PCL too? (instead of WinRT only) if (platformType == PlatformType.WindowsStore || platformType == PlatformType.WindowsPhone) { if (assemblyLocations.Add("System")) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("System"))); } if (assemblyLocations.Add("System.Reflection")) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("System.Reflection"))); } } metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly)); assemblyLocations.Add(assembly.Name.Name); // In case Paradox.Framework.Serialization was not referenced, let's add it. if (!assemblyLocations.Contains("SiliconStudio.Core")) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core"))); assemblyLocations.Add("SiliconStudio.Core"); } // Create roslyn compilation object var assemblyName = Path.GetFileNameWithoutExtension(serializationAssemblyLocation); var compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, metadataReferences, compilerOptions); // Do the actual compilation, and check errors using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write)) { var compilationResult = compilation.Emit(peStream); if (!compilationResult.Success) { var errors = new StringBuilder(); errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error))); foreach (var error in compilationResult.Diagnostics) { if (error.Severity >= DiagnosticSeverity.Warning) { errors.AppendLine(error.ToString()); } } throw new InvalidOperationException(errors.ToString()); } } // Run ILMerge var merge = new ILRepacking.ILRepack() { OutputFile = assembly.MainModule.FullyQualifiedName, DebugInfo = true, CopyAttributes = true, AllowMultipleAssemblyLevelAttributes = true, XmlDocumentation = false, NoRepackRes = true, PrimaryAssemblyDefinition = assembly, WriteToDisk = false, //KeepFirstOfMultipleAssemblyLevelAttributes = true, //Log = true, //LogFile = "ilmerge.log", }; merge.SetInputAssemblies(new string[] { serializationAssemblyLocation }); // Force to use the correct framework //merge.SetTargetPlatform("v4", frameworkFolder); merge.SetSearchDirectories(assemblyResolver.GetSearchDirectories()); merge.Merge(); // Copy name merge.TargetAssemblyDefinition.Name.Name = assembly.Name.Name; merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version; // Add assembly signing info if (assembly.Name.HasPublicKey) { merge.TargetAssemblyDefinition.Name.PublicKey = assembly.Name.PublicKey; merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken; merge.TargetAssemblyDefinition.Name.Attributes |= AssemblyAttributes.PublicKey; if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned) { merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned; } } try { // Delete serializer dll File.Delete(serializationAssemblyLocation); var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb"); if (File.Exists(serializationAssemblyPdbFilePath)) { File.Delete(serializationAssemblyPdbFilePath); } } catch (IOException) { // Mute IOException } return(merge.TargetAssemblyDefinition); }
public bool Process(AssemblyProcessorContext context) { var assembly = context.Assembly; var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); if (mscorlibAssembly == null) { throw new InvalidOperationException("Missing mscorlib.dll from assembly"); } // For now, use import, but this can cause mixed framework versions when processing an assembly with a different framework version. voidType = assembly.MainModule.TypeSystem.Void; stringType = assembly.MainModule.TypeSystem.String; objectType = assembly.MainModule.TypeSystem.Object; var propertyInfoType = assembly.MainModule.ImportReference(mscorlibAssembly.MainModule.GetTypeResolved(typeof(PropertyInfo).FullName)); var typeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); TypeDefinition propertyChangedExtendedEventArgsType; AssemblyDefinition siliconStudioCoreAssembly; try { siliconStudioCoreAssembly = assembly.Name.Name == "SiliconStudio.Core" ? assembly : context.AssemblyResolver.Resolve("SiliconStudio.Core"); } catch (Exception) { return(true); } propertyChangedExtendedEventArgsType = siliconStudioCoreAssembly.MainModule.GetTypes().First(x => x.Name == "PropertyChangedExtendedEventArgs").Resolve(); var typeTokenInfoEx = mscorlibAssembly.MainModule.GetType("System.Reflection.TypeInfo").Resolve(); var getPropertyMethod = typeTokenInfoEx.Methods.First(x => x.Name == "GetDeclaredProperty" && x.Parameters.Count == 1); var getTypeFromHandleMethod = typeType.Methods.First(x => x.Name == "GetTypeFromHandle"); var getTokenInfoExMethod = mscorlibAssembly.MainModule.GetType("System.Reflection.IntrospectionExtensions").Resolve().Methods.First(x => x.Name == "GetTypeInfo"); var propertyChangedExtendedEventArgsConstructor = assembly.MainModule.ImportReference(propertyChangedExtendedEventArgsType.Methods.First(x => x.IsConstructor)); bool modified = false; foreach (var type in assembly.MainModule.GetTypes()) { MethodReference getPropertyChangedMethod; getPropertyChangedMethod = GetGetPropertyChangedMethod(assembly, type); //var propertyChangedField = GetPropertyChangedField(type); //if (propertyChangedField == null) // continue; var propertyChangedField = GetPropertyChangedField(type); if (getPropertyChangedMethod == null && propertyChangedField == null) { continue; } TypeReference propertyChangedFieldType; if (getPropertyChangedMethod == null) { modified = true; getPropertyChangedMethod = GetOrCreateGetPropertyChangedMethod(assembly, type, propertyChangedField); } if (propertyChangedField != null) { propertyChangedField = assembly.MainModule.ImportReference(propertyChangedField); propertyChangedFieldType = propertyChangedField.FieldType; } else { propertyChangedFieldType = getPropertyChangedMethod.ReturnType; } // Add generic to declaring type if (getPropertyChangedMethod.DeclaringType.HasGenericParameters) { getPropertyChangedMethod = getPropertyChangedMethod.MakeGeneric(getPropertyChangedMethod.DeclaringType.GenericParameters.ToArray()); } var propertyChangedInvoke = assembly.MainModule.ImportReference(propertyChangedFieldType.Resolve().Methods.First(x => x.Name == "Invoke")); foreach (var property in type.Properties) { if (property.SetMethod == null || !property.HasThis) { continue; } MethodReference propertyGetMethod = property.GetMethod; // Only patch properties that have a public Getter var methodDefinition = propertyGetMethod.Resolve(); if ((methodDefinition.Attributes & MethodAttributes.Public) != MethodAttributes.Public) { continue; } // Add generic to declaring type if (propertyGetMethod.DeclaringType.HasGenericParameters) { propertyGetMethod = propertyGetMethod.MakeGeneric(propertyGetMethod.DeclaringType.GenericParameters.ToArray()); } //var versionableAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == typeof(VersionableAttribute).FullName); //if (versionableAttribute == null) // continue; modified = true; FieldReference staticField = new FieldDefinition(property.Name + "PropertyInfo", FieldAttributes.Static | FieldAttributes.Private | FieldAttributes.InitOnly, propertyInfoType); type.Fields.Add((FieldDefinition)staticField); // Add generic to declaring type if (staticField.DeclaringType.HasGenericParameters) { staticField = staticField.MakeGeneric(staticField.DeclaringType.GenericParameters.ToArray()); } // In static constructor, find PropertyInfo and store it in static field { var staticConstructor = type.GetStaticConstructor(); if (staticConstructor == null) { staticConstructor = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, voidType); staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret)); type.Methods.Add(staticConstructor); } VariableReference localTokenEx = null; int localTokenExIndex = 0; for (int i = 0; i < staticConstructor.Body.Variables.Count; i++) { var localVar = staticConstructor.Body.Variables[i]; if (localVar.VariableType.FullName == typeTokenInfoEx.FullName) { localTokenEx = localVar; localTokenExIndex = i; break; } } if (localTokenEx == null) { localTokenEx = new VariableDefinition(assembly.MainModule.ImportReference(typeTokenInfoEx)); staticConstructor.Body.Variables.Add((VariableDefinition)localTokenEx); localTokenExIndex = staticConstructor.Body.Variables.Count - 1; } var ilProcessor = staticConstructor.Body.GetILProcessor(); var returnInstruction = staticConstructor.Body.Instructions.Last(); var newReturnInstruction = Instruction.Create(returnInstruction.OpCode); newReturnInstruction.Operand = returnInstruction.Operand; returnInstruction.OpCode = OpCodes.Nop; returnInstruction.Operand = null; // Find PropertyInfo and store it in static field ilProcessor.Append(Instruction.Create(OpCodes.Ldtoken, type)); ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod))); ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getTokenInfoExMethod))); ilProcessor.Append(LocationToStloc(ilProcessor, localTokenExIndex)); ilProcessor.Append(ilProcessor.Create(OpCodes.Ldloca_S, (byte)localTokenExIndex)); ilProcessor.Append(Instruction.Create(OpCodes.Ldstr, property.Name)); ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getPropertyMethod))); ilProcessor.Append(Instruction.Create(OpCodes.Stsfld, staticField)); ilProcessor.Append(newReturnInstruction); } { var ilProcessor = property.SetMethod.Body.GetILProcessor(); var returnInstruction = property.SetMethod.Body.Instructions.Last(); var firstInstruction = property.SetMethod.Body.Instructions[0]; if (property.SetMethod.Body.Instructions[0].OpCode != OpCodes.Nop) { ilProcessor.InsertBefore(property.SetMethod.Body.Instructions[0], Instruction.Create(OpCodes.Nop)); } var newReturnInstruction = Instruction.Create(returnInstruction.OpCode); newReturnInstruction.Operand = returnInstruction.Operand; returnInstruction.OpCode = OpCodes.Nop; returnInstruction.Operand = null; var propertyChangedVariable = new VariableDefinition("propertyChanged", assembly.MainModule.ImportReference(propertyChangedFieldType)); property.SetMethod.Body.Variables.Add(propertyChangedVariable); var oldValueVariable = new VariableDefinition("oldValue", objectType); property.SetMethod.Body.Variables.Add(oldValueVariable); Instruction jump1, jump2; // Prepend: // var propertyChanged = GetPropertyChanged(); // var oldValue = propertyChanged != null ? (object)Property : null; property.SetMethod.Body.SimplifyMacros(); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldarg_0)); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, getPropertyChangedMethod)); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, propertyChangedVariable)); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldloc, propertyChangedVariable)); ilProcessor.InsertBefore(firstInstruction, jump1 = Instruction.Create(OpCodes.Brtrue, Instruction.Create(OpCodes.Nop))); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldnull)); ilProcessor.InsertBefore(firstInstruction, jump2 = Instruction.Create(OpCodes.Br, Instruction.Create(OpCodes.Nop))); ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump1.Operand = Instruction.Create(OpCodes.Ldarg_0))); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, propertyGetMethod)); if (property.PropertyType.IsValueType) { ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Box, property.PropertyType)); } ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump2.Operand = Instruction.Create(OpCodes.Nop))); ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, oldValueVariable)); // Append: // if (propertyChanged != null) // propertyChanged(this, new PropertyChangedExtendedEventArgs("Property", oldValue, Property)); ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable)); ilProcessor.Append(Instruction.Create(OpCodes.Ldnull)); ilProcessor.Append(Instruction.Create(OpCodes.Ceq)); ilProcessor.Append(Instruction.Create(OpCodes.Brtrue, newReturnInstruction)); ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable)); ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0)); ilProcessor.Append(Instruction.Create(OpCodes.Ldsfld, staticField)); ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, oldValueVariable)); ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0)); ilProcessor.Append(Instruction.Create(OpCodes.Call, propertyGetMethod)); if (property.PropertyType.IsValueType) { ilProcessor.Append(Instruction.Create(OpCodes.Box, property.PropertyType)); } ilProcessor.Append(Instruction.Create(OpCodes.Newobj, propertyChangedExtendedEventArgsConstructor)); ilProcessor.Append(Instruction.Create(OpCodes.Callvirt, propertyChangedInvoke)); ilProcessor.Append(Instruction.Create(OpCodes.Nop)); ilProcessor.Append(newReturnInstruction); property.SetMethod.Body.OptimizeMacros(); } } } return(modified); }
public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> references, List <AssemblyDefinition> memoryReferences, ILogger log) { // Create the serializer code generator var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly, log); // Register default serialization profile (to help AOT generic instantiation of serializers) RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator); // Generate serializer code var serializerGeneratedCode = serializerGenerator.TransformText(); var syntaxTree = CSharpSyntaxTree.ParseText(serializerGeneratedCode); // Add reference from source assembly // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem. var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null"; var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default); // Sign the serialization assembly the same way the source was signed // TODO: Transmit over command line if (assembly.Name.HasPublicKey) { // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe? if (signKeyFile == null) { throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified."); } compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider()); if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned) { // Delay signed compilerOptions = compilerOptions.WithDelaySign(true); } } // Add references (files and in-memory PE data) var metadataReferences = new List <MetadataReference>(); foreach (var reference in references) { metadataReferences.Add(MetadataReference.CreateFromFile(reference)); } foreach (var reference in memoryReferences) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, reference)); } // typeof(Dictionary<,>) // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly)); var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName); metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionType.Module.Assembly)); metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly)); // In case SiliconStudio.Core was not referenced, let's add it. if (assembly.Name.Name != "SiliconStudio.Core" && !references.Any(x => string.Compare(Path.GetFileNameWithoutExtension(x), "SiliconStudio.Core", StringComparison.OrdinalIgnoreCase) == 0)) { metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core"))); } // Create roslyn compilation object var assemblyName = assembly.Name.Name + ".Serializers"; var compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, metadataReferences, compilerOptions); // Do the actual compilation, and check errors using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write)) { var compilationResult = compilation.Emit(peStream); if (!compilationResult.Success) { var errors = new StringBuilder(); errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error))); foreach (var error in compilationResult.Diagnostics) { if (error.Severity >= DiagnosticSeverity.Warning) { errors.AppendLine(error.ToString()); } } throw new InvalidOperationException(errors.ToString()); } } var repackOptions = new ILRepacking.RepackOptions(new string[0]) { OutputFile = assembly.MainModule.FullyQualifiedName, DebugInfo = true, CopyAttributes = true, AllowMultipleAssemblyLevelAttributes = true, XmlDocumentation = false, NoRepackRes = true, InputAssemblies = new[] { serializationAssemblyLocation }, SearchDirectories = assemblyResolver.GetSearchDirectories(), SearchAssemblies = references, }; // Run ILMerge var merge = new ILRepacking.ILRepack(repackOptions) { PrimaryAssemblyDefinition = assembly, MemoryOnly = true, //KeepFirstOfMultipleAssemblyLevelAttributes = true, //Log = true, //LogFile = "ilmerge.log", }; try { merge.Repack(); } catch (Exception) { log.Log(new LogMessage("ILRepack", LogMessageType.Error, string.Format("Error while ILRepacking {0}", assembly.Name.Name))); throw; } // Copy name merge.TargetAssemblyDefinition.Name.Name = assembly.Name.Name; merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version; // Add assembly signing info if (assembly.Name.HasPublicKey) { merge.TargetAssemblyDefinition.Name.PublicKey = assembly.Name.PublicKey; merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken; merge.TargetAssemblyDefinition.Name.Attributes |= AssemblyAttributes.PublicKey; if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned) { merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned; } } try { // Delete serializer dll File.Delete(serializationAssemblyLocation); var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb"); if (File.Exists(serializationAssemblyPdbFilePath)) { File.Delete(serializationAssemblyPdbFilePath); } } catch (IOException) { // Mute IOException } return(merge.TargetAssemblyDefinition); }
public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile = null) { // Create the serializer code generator var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly); // Register default serialization profile (to help AOT generic instantiation of serializers) RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator); // Generate serializer code var serializerGeneratedCode = serializerGenerator.TransformText(); var compilerParameters = new CompilerParameters(); compilerParameters.IncludeDebugInformation = false; compilerParameters.GenerateInMemory = false; compilerParameters.CompilerOptions = "/nostdlib"; compilerParameters.TreatWarningsAsErrors = false; compilerParameters.TempFiles.KeepFiles = false; //Console.WriteLine("Generating {0}", serializationAssemblyLocation); // Add reference from source assembly // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem. var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null"; // Sign the serialization assembly the same way the source was signed // TODO: Transmit over command line if (assembly.Name.HasPublicKey) { // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe? if (signKeyFile == null) { throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified."); } var assemblyPath = Path.GetDirectoryName(assembly.MainModule.FullyQualifiedName); if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned) { // Strongly signed compilerParameters.CompilerOptions += string.Format(" /keyfile:\"{0}\"", signKeyFile); } else { // Delay signed compilerParameters.CompilerOptions += string.Format(" /delaysign+ /keyfile:\"{0}\"", signKeyFile); } } var assemblyLocations = new HashSet <string>(); foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences) { if (referencedAssemblyName.FullName != skipWindows) { if (assemblyLocations.Add(referencedAssemblyName.Name)) { //Console.WriteLine("Resolve Assembly for serialization [{0}]", referencedAssemblyName.FullName); compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve(referencedAssemblyName).MainModule.FullyQualifiedName); } } } // typeof(Dictionary<,>) // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly); compilerParameters.ReferencedAssemblies.Add(mscorlibAssembly.MainModule.FullyQualifiedName); var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName); compilerParameters.ReferencedAssemblies.Add(collectionType.Module.FullyQualifiedName); // Make sure System and System.Reflection are added // TODO: Maybe we should do that for .NETCore and PCL too? (instead of WinRT only) if (platformType == PlatformType.WindowsStore || platformType == PlatformType.WindowsPhone) { if (assemblyLocations.Add("System")) { compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("System").MainModule.FullyQualifiedName); } if (assemblyLocations.Add("System.Reflection")) { compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("System.Reflection").MainModule.FullyQualifiedName); } } compilerParameters.ReferencedAssemblies.Add(assembly.MainModule.FullyQualifiedName); assemblyLocations.Add(assembly.Name.Name); // In case Paradox.Framework.Serialization was not referenced, let's add it. if (!assemblyLocations.Contains("SiliconStudio.Core")) { compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("SiliconStudio.Core").MainModule.FullyQualifiedName); } compilerParameters.OutputAssembly = serializationAssemblyLocation; var compilerResults = codeDomProvider.CompileAssemblyFromSource(compilerParameters, serializerGeneratedCode); if (compilerResults.Errors.HasErrors) { var errors = new StringBuilder(); errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilerResults.Errors.Count)); foreach (var error in compilerResults.Errors) { errors.AppendLine(error.ToString()); } throw new InvalidOperationException(errors.ToString()); } // Run ILMerge var merge = new ILRepacking.ILRepack() { OutputFile = assembly.MainModule.FullyQualifiedName, DebugInfo = true, CopyAttributes = true, AllowMultipleAssemblyLevelAttributes = true, XmlDocumentation = false, NoRepackRes = true, PrimaryAssemblyDefinition = assembly, WriteToDisk = false, //KeepFirstOfMultipleAssemblyLevelAttributes = true, //Log = true, //LogFile = "ilmerge.log", }; merge.SetInputAssemblies(new string[] { serializationAssemblyLocation }); // Force to use the correct framework //merge.SetTargetPlatform("v4", frameworkFolder); merge.SetSearchDirectories(assemblyResolver.GetSearchDirectories()); merge.Merge(); // Add assembly signing info if (assembly.Name.HasPublicKey) { merge.TargetAssemblyDefinition.Name.PublicKey = assembly.Name.PublicKey; merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken; merge.TargetAssemblyDefinition.Name.Attributes |= AssemblyAttributes.PublicKey; if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned) { merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned; } } try { // Delete serializer dll File.Delete(serializationAssemblyLocation); var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb"); if (File.Exists(serializationAssemblyPdbFilePath)) { File.Delete(serializationAssemblyPdbFilePath); } } catch (IOException) { // Mute IOException } return(merge.TargetAssemblyDefinition); }