public void TestExecute() { var task = new ILRepacking.ILRepack(); task.FakeBuildEngine = new FakeBuildEngine(); task.Execute(); }
private static void MergeAssemblies(bool delaySign, string keyFile, params string[] inputAssemblies) { var repack = new ILRepacking.ILRepack(); repack.DebugInfo = true; repack.DelaySign = delaySign; repack.KeyFile = keyFile; repack.NoRepackRes = true; repack.InputAssemblies = inputAssemblies; repack.OutputFile = inputAssemblies[0]; repack.Repack(); }
protected void PackAssemblies() { tempPackedOutput = Path.GetTempFileName() + ".dll"; var options = new ILRepacking.RepackOptions() { //Get the list of input assemblies for merging, ensuring our source //assembly is first in the list so it can be granted as the target assembly. InputAssemblies = new[] { tempSourceOutput } //Add the modifications for merging .Concat(Modifications.Select(x => x.SourceDefinitionFilePath)) .ToArray(), OutputFile = tempPackedOutput, TargetKind = ILRepacking.ILRepack.Kind.Dll, //Setup where ILRepack can look for assemblies SearchDirectories = GlobModificationAssemblies() //Translate full path files found via the glob mechanism //into a directory name .Select(x => Path.GetDirectoryName(x)) //Additionally we may have resolved libraries using NuGet, //so we also append the directory of each assembly as well .Concat(resolvedAssemblies.Select(x => Path.GetDirectoryName(x))) //ILRepack rolls is own silly cecil version, keeps the namespace and hides //custom assembly resolvers. We have to explicitly add in cecil or it wont //be found .Concat(new[] { Path.GetDirectoryName(typeof(Mono.Cecil.AssemblyDefinition).Assembly.Location) }) .Distinct() .ToArray(), Parallel = true, //Version = this.SourceAssembly., //perhaps check an option for this. if changed it should not allow repatching CopyAttributes = true, XmlDocumentation = true, UnionMerge = true, #if DEBUG DebugInfo = true #endif }; //Generate the allow list of types from our modifications AllowDuplicateModificationTypes(options.AllowedDuplicateTypes); var repacker = new ILRepacking.ILRepack(options); repacker.Repack(); }
public static void MergeAssemblies(string outfileName, Version version, params string[] sources) { var repack = new ILRepacking.ILRepack(new ILRepacking.RepackOptions { InputAssemblies = sources, OutputFile = outfileName, Version = version, SearchDirectories = new List<string>(), XmlDocumentation = false, DebugInfo = true }); repack.Repack(); }
public static void MergeAssemblies(string outfileName, Version version, params string[] sources) { var repack = new ILRepacking.ILRepack(new ILRepacking.RepackOptions { InputAssemblies = sources, OutputFile = outfileName, Version = version, SearchDirectories = new List <string>(), XmlDocumentation = false, DebugInfo = true }); repack.Repack(); }
public static AssemblyDefinition GenerateRoslynAssembly(BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List<string> references, List<AssemblyDefinition> memoryReferences, ILogger log, IEnumerable<string> sourceCodes) { var syntaxTrees = sourceCodes.Select(x => CSharpSyntaxTree.ParseText(x)); 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, syntaxTrees, 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 { var consoleWriter = Console.Out; Console.SetOut(TextWriter.Null); try { merge.Repack(); } finally { Console.SetOut(consoleWriter); } } 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 void Main(String[] args) { string sourceAsm = null; string modificationGlob = null; string outputPath = null; List <string> mergeInputs = new List <string>(); string mergeOutput = null; Console.WriteLine("Open Terraria API v2.0"); if (args.Length == 0) { #if SLN_CLIENT args = new[] { @"-in=../../../wrap/Terraria/Terraria.exe", @"-mod=../../../OTAPI.Modifications/OTAPI.**/bin/Debug/OTAPI.**.dll", @"-o=../../../OTAPI.dll" }; #else args = new[] { @"-pre-merge-in=../../../wrap/TerrariaServer/TerrariaServer.exe", @"-pre-merge-in=../../../wrap/TerrariaServer/ReLogic.dll", @"-pre-merge-out=../../../TerrariaServer.dll", @"-in=../../../TerrariaServer.dll", #if DEBUG @"-mod=../../../OTAPI.Modifications/OTAPI.Modifications.*/bin/Debug/OTAPI.*.dll", #else @"-mod=../../../OTAPI.Modifications/OTAPI.Modifications.*/bin/Release/OTAPI.*.dll", #endif @"-o=../../../OTAPI.dll" }; #endif } options = new OptionSet(); options.Add("in=|source=", "specifies the source assembly to patch", op => sourceAsm = op); options.Add("mod=|modifications=", "Glob specifying the path to modification assemblies that will run against the target assembly.", op => modificationGlob = op); options.Add("o=|output=", "Specifies the output assembly that has had all modifications applied.", op => outputPath = op); options.Add("pre-merge-in=", "Specifies an assembly to be combined before any modifications are applied", op => mergeInputs.Add(op)); options.Add("pre-merge-out=", "Specifies the output file of combined assemblies before any modifications are applied", op => mergeOutput = op); options.Parse(args); if (string.IsNullOrEmpty(sourceAsm) == true || string.IsNullOrEmpty(modificationGlob) == true) { options.WriteOptionDescriptions(Console.Out); return; } if (mergeInputs.Count > 0) { var extractedReferences = new List <String>(); // extract embedded resources so that ilrepack can find additional references foreach (var input in mergeInputs) { var info = new FileInfo(input); if (info.Exists) { var ext = new Engine.Framework.EmbeddedResourceExtractor(input) { Extensions = new[] { ".dll", ".exe" } }; extractedReferences.AddRange(ext.Extract()); } } // rename resources to match their assembly names foreach (var input in extractedReferences) { var asm = Assembly.LoadFrom(input); var dest = Path.Combine(Path.GetDirectoryName(input), asm.GetName().Name + Path.GetExtension(input)); if (File.Exists(dest)) { File.Delete(dest); } File.Move(input, dest); } var roptions = new ILRepacking.RepackOptions() { //Get the list of input assemblies for merging InputAssemblies = mergeInputs.ToArray(), OutputFile = mergeOutput, TargetKind = ILRepacking.ILRepack.Kind.Dll, //Setup where ILRepack can look for assemblies SearchDirectories = mergeInputs .Select(x => Path.GetDirectoryName(x)) .Concat(new[] { Environment.CurrentDirectory }) .Distinct() .ToArray(), Parallel = true, CopyAttributes = true, XmlDocumentation = true, UnionMerge = true, DebugInfo = true }; var repacker = new ILRepacking.ILRepack(roptions); repacker.Repack(); } patcher = new Engine.Patcher(sourceAsm, new[] { modificationGlob }, outputPath); patcher.Run(); }
public static void Main(String[] args) { string sourceAsm = null; string modificationGlob = null; string outputPath = null; List <string> mergeInputs = new List <string>(); string mergeOutput = null; Console.WriteLine("Open Terraria API v2.0"); if (args.Length == 0) { #if SLN_CLIENT args = new[] { @"-in=../../../wrap/Terraria/Terraria.exe", @"-mod=../../../OTAPI.Modifications/OTAPI.**/bin/Debug/OTAPI.**.dll", @"-o=../../../OTAPI.dll" }; #else args = new[] { @"-pre-merge-in=../../../wrap/TerrariaServer/TerrariaServer.exe", @"-pre-merge-in=../../../wrap/TerrariaServer/ReLogic.dll", @"-pre-merge-out=../../../TerrariaServer.dll", @"-in=../../../TerrariaServer.dll", @"-mod=../../../OTAPI.Modifications/OTAPI.Modifications.*/bin/Debug/OTAPI.*.dll", @"-o=../../../OTAPI.dll" }; #endif } options = new OptionSet(); options.Add("in=|source=", "specifies the source assembly to patch", op => sourceAsm = op); options.Add("mod=|modifications=", "Glob specifying the path to modification assemblies that will run against the target assembly.", op => modificationGlob = op); options.Add("o=|output=", "Specifies the output assembly that has had all modifications applied.", op => outputPath = op); options.Add("pre-merge-in=", "Specifies an assembly to be combined before any modifications are applied", op => mergeInputs.Add(op)); options.Add("pre-merge-out=", "Specifies the output file of combined assemblies before any modifications are applied", op => mergeOutput = op); options.Parse(args); if (string.IsNullOrEmpty(sourceAsm) == true || string.IsNullOrEmpty(modificationGlob) == true) { options.WriteOptionDescriptions(Console.Out); return; } if (mergeInputs.Count > 0) { var roptions = new ILRepacking.RepackOptions() { //Get the list of input assemblies for merging InputAssemblies = mergeInputs.ToArray(), OutputFile = mergeOutput, TargetKind = ILRepacking.ILRepack.Kind.Dll, //Setup where ILRepack can look for assemblies SearchDirectories = mergeInputs .Select(x => Path.GetDirectoryName(x)) .Concat(new[] { Environment.CurrentDirectory }) .Distinct() .ToArray(), Parallel = true, CopyAttributes = true, XmlDocumentation = true, UnionMerge = true, #if DEBUG DebugInfo = true #endif }; var repacker = new ILRepacking.ILRepack(roptions); repacker.Repack(); } patcher = new Engine.Patcher(sourceAsm, new[] { modificationGlob }, outputPath); patcher.Run(); }
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 static void Main(String[] args) { string sourceAsm = null; string outputPath = null; List <string> mergeInputs = new List <string>(); List <string> modificationGlobs = new List <string>(); string mergeOutput = null; Console.WriteLine("Open Terraria API v2.0"); if (args.Length == 0) { #if SLN_CLIENT args = new[] { @"-in=../../../wrap/Terraria/Terraria.exe", @"-mod=../../../OTAPI.Modifications/OTAPI.**/bin/Debug/OTAPI.**.dll", @"-o=../../../OTAPI.dll" }; #else args = new[] { @"-pre-merge-in=../../../wrap/TerrariaServer/TerrariaServer.exe", #if DEBUG @"-pre-merge-in=../../../OTAPI.Modifications/SteelSeriesEngineWrapper/bin/Debug/SteelSeriesEngineWrapper.dll", #else @"-pre-merge-in=../../../OTAPI.Modifications/SteelSeriesEngineWrapper/bin/Release/SteelSeriesEngineWrapper.dll", #endif @"-pre-merge-in=../../../wrap/TerrariaServer/ReLogic.dll", @"-pre-merge-in=../../../wrap/TerrariaServer/CsvHelper.dll", @"-pre-merge-out=../../../TerrariaServer.dll", @"-in=../../../TerrariaServer.dll", #if DEBUG @"-mod=../../../OTAPI.Modifications/OTAPI.Modifications.*/bin/Debug/OTAPI.*.dll", #else @"-mod=../../../OTAPI.Modifications/OTAPI.Modifications.*/bin/Release/OTAPI.*.dll", #endif @"-o=../../../OTAPI.dll" }; #endif } options = new OptionSet(); options.Add("in=|source=", "specifies the source assembly to patch", op => sourceAsm = op); options.Add("mod=|modifications=", "Glob specifying the path to modification assemblies that will run against the target assembly.", op => modificationGlobs.Add(op)); options.Add("o=|output=", "Specifies the output assembly that has had all modifications applied.", op => outputPath = op); options.Add("pre-merge-in=", "Specifies an assembly to be combined before any modifications are applied", op => mergeInputs.Add(op)); options.Add("pre-merge-out=", "Specifies the output file of combined assemblies before any modifications are applied", op => mergeOutput = op); options.Parse(args); modificationGlobs.RemoveAll(x => string.IsNullOrEmpty(x)); if (String.IsNullOrEmpty(sourceAsm) == true || !modificationGlobs.Any()) { options.WriteOptionDescriptions(Console.Out); return; } patcher = new Engine.Patcher(sourceAsm, modificationGlobs, outputPath); if (mergeInputs.Count > 0) { var extractedReferences = new List <String>(); // extract embedded resources so that ilrepack can find additional references foreach (var input in mergeInputs) { var info = new FileInfo(input); if (info.Exists) { var ext = new Engine.Framework.EmbeddedResourceExtractor(input) { Extensions = new[] { ".dll", ".exe" } }; extractedReferences.AddRange(ext.Extract()); } } // rename resources to match their assembly names foreach (var input in extractedReferences) { var asm = Assembly.LoadFrom(input); var dest = Path.Combine(Path.GetDirectoryName(input), asm.GetName().Name + Path.GetExtension(input)); if (File.Exists(dest)) { File.Delete(dest); } File.Move(input, dest); patcher.AddReference(dest); } // shims #if DEBUG var path_shims = "../../../OTAPI.Modifications/OTAPI.Modifications.Xna/bin/Debug/OTAPI.Modifications.Xna.dll"; #else var path_shims = "../../../OTAPI.Modifications/OTAPI.Modifications.Xna/bin/Release/OTAPI.Modifications.Xna.dll"; #endif mergeInputs.Add(path_shims); var asm_shims = patcher.AddReference(path_shims); for (var i = 0; i < mergeInputs.Count(); i++) { var input = mergeInputs.ElementAt(i); var asm = patcher.AddReference(input); var xnaFramework = asm.MainModule.AssemblyReferences .Where(x => x.Name.StartsWith("Microsoft.Xna.Framework")) .ToArray(); for (var x = 0; x < xnaFramework.Length; x++) { xnaFramework[x].Name = "OTAPI.Modifications.Xna"; //TODO: Fix me, ILRepack is adding .dll to the asm name Context.OTAPI.Assembly.Name.Name; xnaFramework[x].PublicKey = asm_shims.Name.PublicKey; xnaFramework[x].PublicKeyToken = asm_shims.Name.PublicKeyToken; xnaFramework[x].Version = asm_shims.Name.Version; } var outputFile = $"{input}.shim"; if (File.Exists(outputFile)) { File.Delete(outputFile); } asm.Write(outputFile); mergeInputs[i] = outputFile; } var roptions = new ILRepacking.RepackOptions() { //Get the list of input assemblies for merging InputAssemblies = mergeInputs.ToArray(), OutputFile = mergeOutput, TargetKind = ILRepacking.ILRepack.Kind.Dll, //Setup where ILRepack can look for assemblies SearchDirectories = mergeInputs .Select(x => Path.GetDirectoryName(x)) .Concat(new[] { Environment.CurrentDirectory }) .Distinct() .ToArray(), Parallel = true, CopyAttributes = true, XmlDocumentation = true, UnionMerge = true, DebugInfo = true }; Console.WriteLine($"Saving premerge run as {mergeOutput}..."); var repacker = new ILRepacking.ILRepack(roptions); repacker.Repack(); } patcher.Run(); }
protected void PackAssemblies() { tempPackedOutput = Path.GetTempFileName() + ".dll"; var options = new ILRepacking.RepackOptions() { //Get the list of input assemblies for merging, ensuring our source //assembly is first in the list so it can be granted as the target assembly. InputAssemblies = new[] { tempSourceOutput } //Add the modifications for merging .Concat(Modifications.Select(x => x.SourceDefinitionFilePath)) .ToArray(), OutputFile = tempPackedOutput, TargetKind = ILRepacking.ILRepack.Kind.Dll, //Setup where ILRepack can look for assemblies SearchDirectories = GlobModificationAssemblies() //Translate full path files found via the glob mechanism //into a directory name .Select(x => Path.GetDirectoryName(x)) //Additionally we may have resolved libraries using NuGet, //so we also append the directory of each assembly as well .Concat(resolvedAssemblies.Select(x => Path.GetDirectoryName(x))) //ILRepack rolls is own silly cecil version, keeps the namespace and hides //custom assembly resolvers. We have to explicitly add in cecil or it wont //be found .Concat(new[] { Path.GetDirectoryName(typeof(Mono.Cecil.AssemblyDefinition).Assembly.Location) }) .Distinct() .ToArray(), Parallel = true, //Version = this.SourceAssembly., //perhaps check an option for this. if changed it should not allow repatching CopyAttributes = true, XmlDocumentation = true, UnionMerge = true, #if DEBUG DebugInfo = true #endif }; //Generate the allow list of types from our modifications AllowDuplicateModificationTypes(options.AllowedDuplicateTypes); var repacker = new ILRepacking.ILRepack(options); repacker.Repack(); }
/// <summary> /// /// </summary> /// <returns></returns> public override bool Execute() { _ilMerger = new ILRepacking.ILRepack { KeyFile = _keyFile, LogFile = _logFile, Log = !string.IsNullOrEmpty(_logFile), LogVerbose = Verbose, UnionMerge = Union, DebugInfo = DebugInfo, CopyAttributes = CopyAttributes, AttributeFile = AttributeFile, AllowMultipleAssemblyLevelAttributes = AllowMultiple, TargetKind = _targetKind, TargetPlatformVersion = TargetPlatformVersion, XmlDocumentation = XmlDocumentation, Internalize = Internalize, DelaySign = DelaySign, AllowDuplicateResources = AllowDuplicateResources, AllowZeroPeKind = ZeroPeKind, Parallel = Parallel, PauseBeforeExit = PauseBeforeExit, OutputFile = _outputFile, PrimaryAssemblyFile = PrimaryAssemblyFile, AllowWildCards = Wildcards, }; // Attempt to create output directory if it does not exist. var outputPath = Path.GetDirectoryName(OutputFile); if (outputPath != null && !Directory.Exists(outputPath)) { try { Directory.CreateDirectory(outputPath); } catch (Exception ex) { Log.LogErrorFromException(ex); return false; } } // Assemblies to be merged var assemblies = new string[_assemblies.Length]; for (int i = 0; i < _assemblies.Length; i++) { assemblies[i] = _assemblies[i].ItemSpec; if (string.IsNullOrEmpty(assemblies[i])) { throw new Exception("Invalid assembly path on item index " + i); } if (!File.Exists(assemblies[i]) && !File.Exists(BuildPath(assemblies[i]))) { throw new Exception(string.Format("Unable to resolve assembly '{0}'", assemblies[i])); } Log.LogMessage(MessageImportance.Normal, "Added assembly {0}", assemblies[i]); } // List of assemblies that should not be internalized if (InternalizeExclude != null) { var internalizeExclude = new string[InternalizeExclude.Length]; if (Internalize) { for (int i = 0; i < InternalizeExclude.Length; i++) { internalizeExclude[i] = InternalizeExclude[i].ItemSpec; if (string.IsNullOrEmpty(internalizeExclude[i])) { throw new Exception("Invalid assembly internalize" + " exclude path on item index " + i); } if (!File.Exists(assemblies[i]) && !File.Exists(BuildPath(assemblies[i]))) { throw new Exception(string.Format("Unable to resolve assembly '{0}'", assemblies[i])); } Log.LogMessage(MessageImportance.Normal, "Excluding assembly {0} from being internalized.", internalizeExclude[i]); } // Create a temporary file with a list of assemblies that // should not be internalized. _excludeFileTmpPath = Path.GetTempFileName(); File.WriteAllLines(_excludeFileTmpPath, internalizeExclude); _ilMerger.ExcludeFile = _excludeFileTmpPath; } } _ilMerger.SetInputAssemblies(assemblies); // Path that will be used when searching for assemblies to merge var searchPath = new List<string> {"."}; searchPath.AddRange(LibraryPath.Select(iti => BuildPath(iti.ItemSpec))); _ilMerger.SetSearchDirectories(searchPath.ToArray()); // Attempt to merge assemblies try { Log.LogMessage(MessageImportance.Normal, "Merging {0} assemb{1} to '{2}'.", _assemblies.Length, (_assemblies.Length != 1) ? "ies" : "y", _outputFile); _ilMerger.Merge(); } catch (Exception e) { Log.LogErrorFromException(e); return false; } return true; }
public override bool Execute() { ILMerger = new ILM(); ILMerger.AttributeFile = m_attributeFile; ILMerger.Closed = m_closed; ILMerger.CopyAttributes = m_copyAttributes; ILMerger.DebugInfo = m_debugInfo; ILMerger.ExcludeFile = m_excludeFile; ILMerger.Internalize = m_internalize; ILMerger.LogFile = m_logFile; ILMerger.Log = m_log; ILMerger.OutputFile = m_outputFile; ILMerger.KeyFile = m_keyFile; ILMerger.TargetKind = m_targetKind; string[] assemblies = new string[m_assemblies.Length]; for (int i = 0; i < assemblies.Length; i++) { assemblies[i] = m_assemblies[i].ItemSpec; } ILMerger.SetInputAssemblies(assemblies); List<string> searchPath = new List<string>(); searchPath.Add("."); foreach (ITaskItem iti in LibraryPath) { searchPath.Add(BuildPath(iti.ItemSpec)); } ILMerger.SetSearchDirectories(searchPath.ToArray()); try { Log.LogMessage(MessageImportance.Normal, "Merging {0} assembl{1} to '{2}'.", this.m_assemblies.Length, (this.m_assemblies.Length != 1) ? "ies" : "y", this.m_outputFile); ILMerger.Merge(); } catch (Exception e) { Log.LogErrorFromException(e); return false; } return true; }
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); }
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 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, 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); } } 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; }
/// <summary> /// /// </summary> /// <returns></returns> public override bool Execute() { _ilMerger = new ILRepacking.ILRepack { KeyFile = _keyFile, LogFile = _logFile, Log = !string.IsNullOrEmpty(_logFile), LogVerbose = Verbose, UnionMerge = Union, DebugInfo = DebugInfo, CopyAttributes = CopyAttributes, AttributeFile = AttributeFile, AllowMultipleAssemblyLevelAttributes = AllowMultiple, TargetKind = _targetKind, TargetPlatformVersion = TargetPlatformVersion, XmlDocumentation = XmlDocumentation, Internalize = Internalize, DelaySign = DelaySign, AllowDuplicateResources = AllowDuplicateResources, AllowZeroPeKind = ZeroPeKind, Parallel = Parallel, PauseBeforeExit = PauseBeforeExit, OutputFile = _outputFile, PrimaryAssemblyFile = PrimaryAssemblyFile, AllowWildCards = Wildcards, }; // Attempt to create output directory if it does not exist. var outputPath = Path.GetDirectoryName(OutputFile); if (outputPath != null && !Directory.Exists(outputPath)) { try { Directory.CreateDirectory(outputPath); } catch (Exception ex) { Log.LogErrorFromException(ex); return(false); } } // Assemblies to be merged var assemblies = new string[_assemblies.Length]; for (int i = 0; i < _assemblies.Length; i++) { assemblies[i] = _assemblies[i].ItemSpec; if (string.IsNullOrEmpty(assemblies[i])) { throw new Exception("Invalid assembly path on item index " + i); } if (!File.Exists(assemblies[i]) && !File.Exists(BuildPath(assemblies[i]))) { throw new Exception(string.Format("Unable to resolve assembly '{0}'", assemblies[i])); } Log.LogMessage(MessageImportance.Normal, "Added assembly {0}", assemblies[i]); } // List of assemblies that should not be internalized if (InternalizeExclude != null) { var internalizeExclude = new string[InternalizeExclude.Length]; if (Internalize) { for (int i = 0; i < InternalizeExclude.Length; i++) { internalizeExclude[i] = InternalizeExclude[i].ItemSpec; if (string.IsNullOrEmpty(internalizeExclude[i])) { throw new Exception("Invalid assembly internalize" + " exclude path on item index " + i); } if (!File.Exists(assemblies[i]) && !File.Exists(BuildPath(assemblies[i]))) { throw new Exception(string.Format("Unable to resolve assembly '{0}'", assemblies[i])); } Log.LogMessage(MessageImportance.Normal, "Excluding assembly {0} from being internalized.", internalizeExclude[i]); } // Create a temporary file with a list of assemblies that // should not be internalized. _excludeFileTmpPath = Path.GetTempFileName(); File.WriteAllLines(_excludeFileTmpPath, internalizeExclude); _ilMerger.ExcludeFile = _excludeFileTmpPath; } } _ilMerger.SetInputAssemblies(assemblies); // Path that will be used when searching for assemblies to merge var searchPath = new List <string> { "." }; searchPath.AddRange(LibraryPath.Select(iti => BuildPath(iti.ItemSpec))); _ilMerger.SetSearchDirectories(searchPath.ToArray()); // Attempt to merge assemblies try { Log.LogMessage(MessageImportance.Normal, "Merging {0} assemb{1} to '{2}'.", _assemblies.Length, (_assemblies.Length != 1) ? "ies" : "y", _outputFile); _ilMerger.Merge(); } catch (Exception e) { Log.LogErrorFromException(e); return(false); } return(true); }