public ILRepack(RepackOptions options, ILogger logger) { Options = options; Logger = logger; _repackImporter = new RepackImporter(Logger, Options, this, _aspOffsets); }
public static void DoRepackForCmd(IEnumerable<string> args) { var repackOptions = new RepackOptions(args.Concat(new[] { "/log" })); var repack = new ILRepacking.ILRepack(repackOptions); repack.Repack(); ReloadAndCheckReferences(repackOptions); }
public RepackLogger(RepackOptions options) { ShouldLogVerbose = options.LogVerbose; if (Open(options.LogFile)) { options.Log = true; } }
private static void ReloadAndCheckReferences(RepackOptions repackOptions) { var outputFile = AssemblyDefinition.ReadAssembly(repackOptions.OutputFile, new ReaderParameters(ReadingMode.Immediate)); var mergedFiles = repackOptions.ResolveFiles().Select(f => AssemblyDefinition.ReadAssembly(f, new ReaderParameters(ReadingMode.Deferred))); foreach (var a in outputFile.MainModule.AssemblyReferences.Where(x => mergedFiles.Any(y => repackOptions.KeepOtherVersionReferences ? x.FullName == y.FullName : x.Name == y.Name.Name))) { Assert.Fail($"Merged assembly retains a reference to one (or more) of the merged files: ${a.FullName}"); } }
public ILRepack(RepackOptions options, ILogger logger) { Options = options; Logger = logger; logger.ShouldLogVerbose = options.LogVerbose; _repackImporter = new RepackImporter(Logger, Options, this, _aspOffsets); }
public RepackImporter( ILogger logger, RepackOptions options, IRepackContext repackContext, Dictionary <AssemblyDefinition, int> aspOffsets) { _logger = logger; _options = options; _repackContext = repackContext; _aspOffsets = aspOffsets; }
static int Main(string[] args) { ICommandLine commandLine = new CommandLine(args); ILogger logger = new RepackLogger(); IFile file = new FileWrapper(); RepackOptions options = new RepackOptions(commandLine, logger, file); int returnCode = -1; try { if (options.ShouldShowUsage()) { Usage(); Exit(2); } options.Parse(); //TODO: Open the Logger before the parse if (logger.Open(options.LogFile)) { options.Log = true; logger.ShouldLogVerbose = options.LogVerbose; } ILRepack repack = new ILRepack(options, logger); repack.Repack(); returnCode = 0; } catch (RepackOptions.InvalidTargetKindException e) { Console.WriteLine(e.Message); Usage(); Exit(2); } catch (Exception e) { logger.Log(e); returnCode = 1; } finally { logger.Close(); if (options.PauseBeforeExit) { Console.WriteLine("Press Any Key To Continue"); Console.ReadKey(true); } } return(returnCode); }
static int Main(string[] args) { RepackLogger logger = new RepackLogger(); RepackOptions options = new RepackOptions(args); int returnCode = -1; try { if (options.ShouldShowUsage) { Usage(); Exit(2); } logger.ShouldLogVerbose = options.LogVerbose; //TODO: Open the Logger before the parse if (logger.Open(options.LogFile)) { options.Log = true; } ILRepack repack = new ILRepack(options, logger); repack.Repack(); returnCode = 0; } catch (RepackOptions.InvalidTargetKindException e) { Console.WriteLine(e.Message); Usage(); Exit(2); } catch (Exception e) { logger.Log(e); returnCode = 1; } finally { logger.Close(); if (options.PauseBeforeExit) { Console.WriteLine("Press Any Key To Continue"); Console.ReadKey(true); } } return returnCode; }
static int Main(string[] args) { RepackOptions options = new RepackOptions(args); var logger = new RepackLogger(options); int returnCode = -1; try { if (options.ShouldShowUsage) { Usage(); Exit(2); } ILRepack repack = new ILRepack(options, logger); repack.Repack(); repack.Dispose(); returnCode = 0; } catch (RepackOptions.InvalidTargetKindException e) { Console.WriteLine(e.Message); Usage(); Exit(2); } catch (Exception e) { logger.Log(e); returnCode = 1; } finally { logger.Dispose(); if (options.PauseBeforeExit) { Console.WriteLine("Press Any Key To Continue"); Console.ReadKey(true); } } return(returnCode); }
public ILRepack(RepackOptions options) : this(options, new RepackLogger()) { }
void Parse() { options = new RepackOptions(commandLine.Object, file.Object); }
/// <summary> /// Merges the proxy and the target assemblies. /// </summary> /// <param name="outputPath">The path of the resulting assembly.</param> private void Merge(string outputPath) { Contract.Requires(outputPath != null); var options = new RepackOptions { InputAssemblies = new[] { this.Pair.Target.FilePath, this.Pair.Proxy.FilePath }, OutputFile = outputPath, TargetKind = ILRepack.Kind.Dll, SearchDirectories = new[] { this.Pair.Target.FilePath, this.Pair.Proxy.FilePath }.Select(Path.GetDirectoryName), KeyFile = Path.Combine(this.CurrentDirectoryPath, "MockEverything.snk"), }; // The `Log` property of `RepackOptions` being gracefully ignored by the library (see ILRepack/RepackLogger.cs, l. 16), the only way to get rid of the logging is to create a logger which does nothing. new ILRepack(options, new NullLogger()).Repack(); }
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)); // Open file currently being processed using FileShare.ReadWrite using (var stream = File.Open(assembly.MainModule.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) metadataReferences.Add(MetadataReference.CreateFromStream(stream, filePath: assembly.MainModule.FileName)); // 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(new AssemblyNameReference("SiliconStudio.Core", null)))); } // 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()); } } // Make sure every instruction in the primary assembly has offset up to date // Ideally, we should do it manually only on method whose instructions changed so far foreach (var type in assembly.MainModule.Types) { GenerateOffsetForMethodsOfType(type); } var repackOptions = new ILRepacking.RepackOptions(new string[0]) { OutputFile = assembly.MainModule.FileName, DebugInfo = true, CopyAttributes = true, AllowMultipleAssemblyLevelAttributes = true, XmlDocumentation = false, NoRepackRes = true, InputAssemblies = new[] { serializationAssemblyLocation }, SearchDirectories = new string[0], }; // Run ILMerge var merge = new ILRepacking.ILRepack(repackOptions) { GlobalAssemblyResolver = new RepackAssemblyResolverAdapter(assemblyResolver), 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; } } // Dispose old assembly assembly.Dispose(); 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); }
private static void ProcessRedirects(DataSet set, HashSet <string> mergedAssemblies, HashSet <string> redirectedAssemblies, RepackOptions repackOptions) { if (repackOptions.KeepOtherVersionReferences) { return; } var table = set.Tables["assemblyIdentity"]; var parentRelation = table?.ParentRelations["dependentAssembly_assemblyIdentity"]; if (parentRelation == null) { return; } var nameCol = table.Columns["name"]; foreach (var row in table.Select()) { var name = row[nameCol] as string; if (name == null) { continue; } var parent = row.GetParentRow(parentRelation); if (!mergedAssemblies.Contains(name) && !redirectedAssemblies.Contains(name)) { redirectedAssemblies.Add(name); continue; } parent.Delete(); } set.AcceptChanges(); var bindingTable = set.Tables["assemblyBinding"]; var childRelation = bindingTable?.ChildRelations["assemblyBinding_dependentAssembly"]; if (childRelation == null) { return; } foreach (var binding in bindingTable.Select()) { var children = binding.GetChildRows(childRelation); if (children.Length == 0) { binding.Delete(); } } set.AcceptChanges(); }