Example #1
0
        public void TestExecute()
        {
            var task = new ILRepacking.ILRepack();

            task.FakeBuildEngine = new FakeBuildEngine();
            task.Execute();
        }
Example #2
0
        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();
        }
Example #3
0
        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();
        }
Example #4
0
 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();
 }
Example #5
0
        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();
        }
Example #6
0
        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;
        }
Example #7
0
        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();
        }
Example #8
0
        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);
        }
Example #10
0
        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();
        }
Example #11
0
		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();
		}
Example #12
0
        /// <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;
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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;
        }
Example #18
0
        /// <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);
        }