private void ReadInputAssemblies() { MergedAssemblyFiles = Options.InputAssemblies.SelectMany(ResolveFile).Distinct().ToList(); OtherAssemblies = new List <AssemblyDefinition>(); // TODO: this could be parallelized to gain speed var primary = MergedAssemblyFiles.FirstOrDefault(); var debugSymbolsRead = false; foreach (string assembly in MergedAssemblyFiles) { var result = ReadInputAssembly(assembly, primary == assembly); if (result.IsPrimary) { PrimaryAssemblyDefinition = result.Definition; PrimaryAssemblyFile = result.Assembly; } else { OtherAssemblies.Add(result.Definition); } debugSymbolsRead |= result.SymbolsRead; } // prevent writing PDB if we haven't read any Options.DebugInfo = debugSymbolsRead; MergedAssemblies = new List <AssemblyDefinition>(OtherAssemblies); MergedAssemblies.Insert(0, PrimaryAssemblyDefinition); }
/// <summary> /// The actual repacking process, called by main after parsing arguments. /// When referencing this assembly, call this after setting the merge properties. /// </summary> public void Repack() { var timer = new Stopwatch(); timer.Start(); Options.Validate(); PrintRepackHeader(); var actualOutFile = Path.GetFullPath(Options.OutputFile); Options.OutputFile = actualOutFile; _reflectionHelper = new ReflectionHelper(this); ResolveSearchDirectories(); // Read input assemblies only after all properties are set. ReadInputAssemblies(); if (MergedAssemblyFiles.Any(m => string.Compare(m, actualOutFile, StringComparison.OrdinalIgnoreCase) == 0)) { Options.OutputFile = GetTempFile(Options.OutputFile); } _platformFixer = new PlatformFixer(this, PrimaryAssemblyMainModule.Runtime); _mappingHandler = new MappingHandler(); bool hadStrongName = PrimaryAssemblyDefinition.Name.HasPublicKey; ModuleKind kind = PrimaryAssemblyMainModule.Kind; if (Options.TargetKind.HasValue) { switch (Options.TargetKind.Value) { case Kind.Dll: kind = ModuleKind.Dll; break; case Kind.Exe: kind = ModuleKind.Console; break; case Kind.WinExe: kind = ModuleKind.Windows; break; } } TargetRuntime runtime = ParseTargetPlatform(); // change assembly's name to correspond to the file we create string mainModuleName = Options.UsePrimaryAssemblyName ? PrimaryAssemblyDefinition.Name.Name : Path.GetFileNameWithoutExtension(Options.OutputFile); if (TargetAssemblyDefinition == null) { AssemblyNameDefinition asmName = Clone(PrimaryAssemblyDefinition.Name); asmName.Name = mainModuleName; TargetAssemblyDefinition = AssemblyDefinition.CreateAssembly(asmName, mainModuleName, new ModuleParameters() { Kind = kind, Architecture = PrimaryAssemblyMainModule.Architecture, AssemblyResolver = GlobalAssemblyResolver, Runtime = runtime }); } else { // TODO: does this work or is there more to do? TargetAssemblyMainModule.Kind = kind; TargetAssemblyMainModule.Runtime = runtime; TargetAssemblyDefinition.Name.Name = mainModuleName; TargetAssemblyMainModule.Name = mainModuleName; } // set the main module attributes TargetAssemblyMainModule.Attributes = PrimaryAssemblyMainModule.Attributes; TargetAssemblyMainModule.Win32ResourceDirectory = MergeWin32Resources(PrimaryAssemblyMainModule.Win32ResourceDirectory); if (Options.Version != null) { TargetAssemblyDefinition.Name.Version = Options.Version; } _lineIndexer = new IKVMLineIndexer(this, Options.LineIndexation); var signingStep = new SigningStep(this, Options); var isUnixEnvironment = Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix; var isMonoRuntime = Type.GetType("Mono.Runtime") != null; using (var sourceServerDataStep = GetSourceServerDataStep(isUnixEnvironment)) { List <IRepackStep> repackSteps = new List <IRepackStep> { signingStep, new ReferencesRepackStep(Logger, this), new TypesRepackStep(Logger, this, _repackImporter, Options), new ResourcesRepackStep(Logger, this, Options), new AttributesRepackStep(Logger, this, _repackImporter, Options), new ReferencesFixStep(Logger, this, _repackImporter, Options), new XamlResourcePathPatcherStep(Logger, this), sourceServerDataStep }; foreach (var step in repackSteps) { step.Perform(); } var parameters = new WriterParameters { StrongNameKeyPair = signingStep.KeyInfo?.KeyPair, StrongNameKeyBlob = signingStep.KeyInfo?.KeyBlob, WriteSymbols = Options.DebugInfo && PrimaryAssemblyMainModule.SymbolReader != null, SymbolWriterProvider = PrimaryAssemblyMainModule.SymbolReader?.GetWriterProvider(), }; // create output directory if it does not exist var outputDir = Path.GetDirectoryName(Options.OutputFile); if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir)) { Logger.Info("Output directory does not exist. Creating output directory: " + outputDir); Directory.CreateDirectory(outputDir); } Logger.Info("Writing output assembly to disk"); TargetAssemblyDefinition.Write(Options.OutputFile, parameters); sourceServerDataStep.Write(); for (int i = 1; i < MergedAssemblies.Count; ++i) { MergedAssemblies[i].Dispose(); } TargetAssemblyDefinition.Dispose(); GlobalAssemblyResolver.Dispose(); if (Options.OutputFile != actualOutFile) { MoveTempFile(Options.OutputFile, actualOutFile); Options.OutputFile = actualOutFile; } // If this is an executable and we are on linux/osx we should copy file permissions from // the primary assembly if (isUnixEnvironment && isMonoRuntime) { Stat stat; Logger.Info("Copying permissions from " + PrimaryAssemblyFile); Syscall.stat(PrimaryAssemblyFile, out stat); Syscall.chmod(Options.OutputFile, stat.st_mode); } if (hadStrongName && !TargetAssemblyDefinition.Name.HasPublicKey) { Options.StrongNameLost = true; } // nice to have, merge .config (assembly configuration file) & .xml (assembly documentation) ConfigMerger.Process(this); if (Options.XmlDocumentation) { DocumentationMerger.Process(this); } } Logger.Info($"Finished in {timer.Elapsed}"); }