public override bool Execute() { Log.LogDebugMessage ("StripEmbeddedLibraries Task"); Log.LogDebugTaskItems (" Assemblies: ", Assemblies); var res = new DirectoryAssemblyResolver (Log.LogWarning, true); foreach (var assembly in Assemblies) res.Load (Path.GetFullPath (assembly.ItemSpec)); foreach (var assemblyName in Assemblies) { var suffix = assemblyName.ItemSpec.EndsWith (".dll") ? String.Empty : ".dll"; string hintPath = assemblyName.GetMetadata ("HintPath").Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string fileName = assemblyName.ItemSpec + suffix; if (!String.IsNullOrEmpty (hintPath) && !File.Exists (hintPath)) // ignore invalid HintPath hintPath = null; string assemblyPath = String.IsNullOrEmpty (hintPath) ? fileName : hintPath; if (MonoAndroidHelper.IsFrameworkAssembly (fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains (Path.GetFileName (fileName))) continue; var assembly = res.GetAssembly (assemblyPath); bool assembly_modified = false; foreach (var mod in assembly.Modules) { // embedded jars var resjars = mod.Resources.Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)).Select (r => (EmbeddedResource) r); foreach (var resjar in resjars.ToArray ()) { Log.LogDebugMessage (" Stripped {0}", resjar.Name); mod.Resources.Remove (resjar); assembly_modified = true; } // embedded AndroidNativeLibrary archive var nativezip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (nativezip != null) { Log.LogDebugMessage (" Stripped {0}", nativezip.Name); mod.Resources.Remove (nativezip); assembly_modified = true; } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { Log.LogDebugMessage (" Stripped {0}", reszip.Name); mod.Resources.Remove (reszip); assembly_modified = true; } } if (assembly_modified) { Log.LogDebugMessage (" The stripped library is saved as {0}", assemblyPath); // Output assembly needs to regenerate symbol file even if no IL/metadata was touched // because Cecil still rewrites all assembly types in Cecil order (type A, nested types of A, type B, etc) // and not in the original order causing symbols if original order doesn't match Cecil order var wp = new WriterParameters () { WriteSymbols = assembly.MainModule.HasSymbols }; assembly.Write (assemblyPath, wp); } } return true; }
public static bool NeedsMarshalMethod(this MethodDefinition md, DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, MethodInfo method, ref string name, ref string methodName, ref string signature) { var m = md; while (m != null) { if (CheckMethod(m, ref name, ref methodName, ref signature)) { return(true); } m = m.GetBaseDefinition(cache); if (m == md) { break; } md = m; } foreach (var iface in method.DeclaringType.GetInterfaces()) { if (iface.IsGenericType) { continue; } var ifaceMap = method.DeclaringType.GetInterfaceMap(iface); var ad = resolver.GetAssembly(iface.Assembly.Location); var id = ad.MainModule.GetType(iface.GetCecilName()); if (id == null) { App.Warning($"Couln't find iterface {iface.FullName}"); continue; } for (int i = 0; i < ifaceMap.TargetMethods.Length; i++) { if (ifaceMap.TargetMethods [i] == method) { var imd = id.GetMethodDefinition(ifaceMap.InterfaceMethods [i]); if (CheckMethod(imd, ref name, ref methodName, ref signature)) { return(true); } } } } return(false); }
void AddNativeLibrariesFromAssemblies(ZipArchiveEx apk, string supportedAbis) { int count = 0; var abis = supportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); using (var res = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) { foreach (var assembly in EmbeddedNativeLibraryAssemblies) { res.Load(assembly.ItemSpec); } foreach (var assemblyPath in EmbeddedNativeLibraryAssemblies) { var assembly = res.GetAssembly(assemblyPath.ItemSpec); foreach (var mod in assembly.Modules) { var ressozip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (ressozip == null) { continue; } var data = ressozip.GetResourceData(); using (var ms = new MemoryStream(data)) { using (var zip = ZipArchive.Open(ms)) { foreach (var e in zip.Where(x => abis.Any(a => x.FullName.Contains($"/{a}/")))) { if (e.IsDirectory) { continue; } var key = e.FullName.Replace("native_library_imports", "lib"); if (apk.Archive.Any(k => k.FullName == key)) { Log.LogCodedWarning("4301", "Apk already contains the item {0}; ignoring.", key); continue; } using (var s = new MemoryStream()) { e.Extract(s); s.Position = 0; apk.Archive.AddEntry(s.ToArray(), key); } } } } } count++; if (count == ZipArchiveEx.ZipFlushLimit) { apk.Flush(); count = 0; } } } }
void AddNativeLibrariesFromAssemblies(ZipArchive apk, string supportedAbis) { var abis = supportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var res = new DirectoryAssemblyResolver(Console.WriteLine, loadDebugSymbols: false); foreach (var assembly in EmbeddedNativeLibraryAssemblies) { res.Load(assembly.ItemSpec); } foreach (var assemblyPath in EmbeddedNativeLibraryAssemblies) { var assembly = res.GetAssembly(assemblyPath.ItemSpec); foreach (var mod in assembly.Modules) { var ressozip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (ressozip == null) { continue; } var data = ressozip.GetResourceData(); using (var ms = new MemoryStream(data)) { using (var zip = new ZipArchive(ms, ZipArchiveMode.Read)) { foreach (var e in zip.Entries.Where(x => abis.Any(a => x.FullName.Contains(a)))) { if (e.IsDirectory()) { continue; } var key = e.FullName.Replace("native_library_imports", "lib"); if (apk.ContainsEntry(key)) { Log.LogCodedWarning("4301", "Apk already contains the item {0}; ignoring.", key); continue; } using (var s = new MemoryStream()) { e.Extract(s); apk.AddEntry(key, s.ToArray()); } } } } } } }
IEnumerable <AssemblyDefinition> GetRetainAssemblies(DirectoryAssemblyResolver res) { List <AssemblyDefinition> retainList = null; foreach (var assembly in ResolvedAssemblies) { var filename = Path.GetFileName(assembly.ItemSpec); if (!MonoAndroidHelper.IsForceRetainedAssembly(filename)) { continue; } if (retainList == null) { retainList = new List <AssemblyDefinition> (); } retainList.Add(res.GetAssembly(assembly.ItemSpec)); } return(retainList); }
int ExtractApiLevel(ITaskItem ass) { Log.LogDebugMessage(ass.ItemSpec); foreach (var ca in res.GetAssembly(ass.ItemSpec).CustomAttributes) { switch (ca.AttributeType.FullName) { case "System.Runtime.Versioning.TargetFrameworkAttribute": foreach (var p in ca.ConstructorArguments) { var value = p.Value.ToString(); if (value.StartsWith("MonoAndroid")) { var values = value.Split('='); return(AndroidVersion.TryOSVersionToApiLevel(values[1])); } } break; } } return(0); }
void AddNativeLibrariesFromAssemblies(ZipFile apk, string supportedAbis) { var abis = supportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var res = new DirectoryAssemblyResolver (Console.WriteLine, loadDebugSymbols: false); foreach (var assembly in EmbeddedNativeLibraryAssemblies) res.Load (assembly.ItemSpec); foreach (var assemblyPath in EmbeddedNativeLibraryAssemblies) { var assembly = res.GetAssembly (assemblyPath.ItemSpec); foreach (var mod in assembly.Modules) { var ressozip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (ressozip == null) continue; var data = ressozip.GetResourceData (); using (var ms = new MemoryStream (data)) { using (var zip = ZipFile.Read (ms)) { foreach (var e in zip.Entries.Where (x => abis.Any (a => x.FileName.Contains (a)))) { if (e.IsDirectory) continue; var key = e.FileName.Replace ("native_library_imports", "lib"); if (apk.ContainsEntry (key)) { Log.LogCodedWarning ("4301", "Apk already contains the item {0}; ignoring.", key); continue; } using (var s = new MemoryStream ()) { e.Extract (s); apk.AddEntry (key, s.ToArray ()); } } } } } } }
public override bool RunTask() { if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var readerParameters = new ReaderParameters { ReadSymbols = true, }; var writerParameters = new WriterParameters { DeterministicMvid = Deterministic, }; using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) { // Add SearchDirectories with ResolvedAssemblies foreach (var assembly in ResolvedAssemblies) { var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec)); if (!resolver.SearchDirectories.Contains(path)) { resolver.SearchDirectories.Add(path); } } // Run the FixAbstractMethodsStep var step = new FixAbstractMethodsStep(resolver, Log); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; // Only run the step on "MonoAndroid" assemblies if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec)) { var assemblyDefinition = resolver.GetAssembly(source.ItemSpec); if (step.FixAbstractMethods(assemblyDefinition)) { Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; assemblyDefinition.Write(destination.ItemSpec, writerParameters); continue; } } if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec)) { Log.LogDebugMessage($"Copied: {destination.ItemSpec}"); } else { Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}"); // NOTE: We still need to update the timestamp on this file, or this target would run again File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow); } } } return(!Log.HasLoggedErrors); }
protected override AssemblyDefinition GetMonoAndroidAssembly() { return(resolver.GetAssembly("Mono.Android.dll")); }
bool Execute(DirectoryAssemblyResolver res) { // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); } var resolver = new AssemblyResolver(res.ToResolverCache()); // Set up for linking var options = new LinkerOptions(); options.MainAssembly = res.GetAssembly(MainAssembly); options.OutputDirectory = Path.GetFullPath(OutputDirectory); options.LinkSdkOnly = string.Compare(LinkMode, "SdkOnly", true) == 0; options.LinkNone = false; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray(); options.I18nAssemblies = Linker.ParseI18nAssemblies(I18nAssemblies); if (!options.LinkSdkOnly) { options.RetainAssemblies = GetRetainAssemblies(res); } options.DumpDependencies = DumpDependencies; options.HttpClientHandlerType = HttpClientHandlerType; options.TlsProvider = TlsProvider; options.PreserveJniMarshalMethods = PreserveJniMarshalMethods; options.DeterministicOutput = Deterministic; var skiplist = new List <string> (); if (string.Compare(UseSharedRuntime, "true", true) == 0) { skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a))); } // Add LinkSkip options if (!string.IsNullOrWhiteSpace(LinkSkip)) { skiplist.AddRange(LinkSkip.Split(',', ';')); } options.SkippedAssemblies = skiplist; if (EnableProguard) { options.ProguardConfiguration = ProguardConfiguration; } // Link! try { LinkContext link_context; Linker.Process(options, this, out link_context); foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName(assembly.ItemSpec); var assemblyDestination = Path.Combine(OutputDirectory, filename); if (!MonoAndroidHelper.IsForceRetainedAssembly(filename)) { continue; } MonoAndroidHelper.CopyAssemblyAndSymbols(copysrc, assemblyDestination); } } catch (ResolutionException ex) { Diagnostic.Error(2006, ex, "Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.", ex.Member, ex.Member.Module.Assembly, ex.Scope); } return(true); }
bool Execute(DirectoryAssemblyResolver res) { // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); } var resolver = new AssemblyResolver(res.ToResolverCache()); // Set up for linking var options = new LinkerOptions(); options.MainAssembly = res.GetAssembly(MainAssembly); options.OutputDirectory = Path.GetFullPath(OutputDirectory); options.LinkSdkOnly = string.Compare(LinkMode, "SdkOnly", true) == 0; options.LinkNone = string.Compare(LinkMode, "None", true) == 0; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray(); options.I18nAssemblies = Linker.ParseI18nAssemblies(I18nAssemblies); if (!options.LinkSdkOnly) { options.RetainAssemblies = GetRetainAssemblies(res); } options.DumpDependencies = DumpDependencies; options.HttpClientHandlerType = HttpClientHandlerType; options.TlsProvider = TlsProvider; options.PreserveJniMarshalMethods = PreserveJniMarshalMethods; var skiplist = new List <string> (); if (string.Compare(UseSharedRuntime, "true", true) == 0) { skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a))); } if (!string.IsNullOrWhiteSpace(LinkOnlyNewerThan) && File.Exists(LinkOnlyNewerThan)) { var newerThan = File.GetLastWriteTime(LinkOnlyNewerThan); var skipOldOnes = ResolvedAssemblies.Where(a => File.GetLastWriteTime(a.ItemSpec) < newerThan); foreach (var old in skipOldOnes) { Log.LogMessage(MBF.MessageImportance.Low, " Skip linking unchanged file: " + old.ItemSpec); } skiplist = skipOldOnes.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec)).Concat(skiplist).ToList(); } // Add LinkSkip options if (!string.IsNullOrWhiteSpace(LinkSkip)) { foreach (var assembly in LinkSkip.Split(',', ';')) { skiplist.Add(assembly); } } options.SkippedAssemblies = skiplist; if (EnableProguard) { options.ProguardConfiguration = ProguardConfiguration; } // Link! try { LinkContext link_context; Linker.Process(options, this, out link_context); var copydst = OptionalDestinationDirectory ?? OutputDirectory; foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName(assembly.ItemSpec); var assemblyDestination = Path.Combine(copydst, filename); if (options.LinkNone) { if (skiplist.Any(s => Path.GetFileNameWithoutExtension(filename) == s)) { // For skipped assemblies, skip if there is existing file in the destination. // We cannot just copy the linker output from *current* run output, because // it always renew the assemblies, in *different* binary values, whereas // the dll in the OptionalDestinationDirectory must retain old and unchanged. if (File.Exists(assemblyDestination)) { MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log); continue; } } else { // Prefer fixup assemblies if exists, otherwise just copy the original. copysrc = Path.Combine(OutputDirectory, filename); copysrc = File.Exists(copysrc) ? copysrc : assembly.ItemSpec; } } else if (!MonoAndroidHelper.IsForceRetainedAssembly(filename)) { continue; } if (MonoAndroidHelper.CopyIfChanged(copysrc, assemblyDestination)) { MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log); } try { var mdbDestination = assemblyDestination + ".mdb"; if (MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", mdbDestination)) { MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(mdbDestination, DateTime.UtcNow, Log); } } catch (Exception) { // skip it, mdb sometimes fails to read and it's optional } var pdb = Path.ChangeExtension(copysrc, "pdb"); if (File.Exists(pdb) && Files.IsPortablePdb(pdb)) { var pdbDestination = Path.ChangeExtension(Path.Combine(copydst, filename), "pdb"); if (MonoAndroidHelper.CopyIfChanged(pdb, pdbDestination)) { MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(pdbDestination, DateTime.UtcNow, Log); } } } } catch (ResolutionException ex) { Diagnostic.Error(2006, ex, "Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.", ex.Member, ex.Member.Module.Assembly, ex.Scope); } return(true); }
// Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] void Extract( ICollection<string> jars, ICollection<string> resolvedResourceDirectories, ICollection<string> resolvedAssetDirectories, ICollection<string> resolvedEnvironments) { var outdir = new DirectoryInfo (OutputImportDirectory); if (!outdir.Exists) outdir.Create (); var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false); foreach (var assembly in Assemblies) res.Load (assembly.ItemSpec); // FIXME: reorder references by import priority (not sure how to do that yet) foreach (var assemblyPath in Assemblies .Select (a => GetTargetAssembly (a)) .Where (a => a != null) .Distinct ()) { foreach (var imp in new string [] {imports_dir, "library_project_imports"}.Distinct ()) { string assemblyIdentName = Path.GetFileNameWithoutExtension (assemblyPath); if (UseShortFileNames) { assemblyIdentName = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly (assemblyIdentName); } string outDirForDll = Path.Combine (OutputImportDirectory, assemblyIdentName); string importsDir = Path.Combine (outDirForDll, imp); #if SEPARATE_CRUNCH // FIXME: review these binResDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. //string binResDir = Path.Combine (importsDir, "bin", "res"); //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets"); #endif string resDir = Path.Combine (importsDir, "res"); string assemblyDir = Path.Combine (importsDir, "assets"); // Skip already-extracted resources. var stamp = new FileInfo (Path.Combine (outdir.FullName, assemblyIdentName + ".stamp")); if (stamp.Exists && stamp.LastWriteTime > new FileInfo (assemblyPath).LastWriteTime) { Log.LogDebugMessage ("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists (binResDir)) resolvedResourceDirectories.Add (binResDir); if (Directory.Exists (binAssemblyDir)) resolvedAssetDirectories.Add (binAssemblyDir); #endif if (Directory.Exists (resDir)) resolvedResourceDirectories.Add (resDir); if (Directory.Exists (assemblyDir)) resolvedAssetDirectories.Add (assemblyDir); continue; } if (Directory.Exists (outDirForDll)) Directory.Delete (outDirForDll, true); Directory.CreateDirectory (importsDir); var assembly = res.GetAssembly (assemblyPath); foreach (var mod in assembly.Modules) { // android environment files foreach (var envtxt in mod.Resources .Where (r => r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) .Where (r => r is EmbeddedResource) .Cast<EmbeddedResource> ()) { if (!Directory.Exists (outDirForDll)) Directory.CreateDirectory (outDirForDll); var finfo = new FileInfo (Path.Combine (outDirForDll, envtxt.Name)); using (var fs = finfo.Create ()) { var data = envtxt.GetResourceData (); fs.Write (data, 0, data.Length); } resolvedEnvironments.Add (finfo.FullName); } // embedded jars (EmbeddedJar, EmbeddedReferenceJar) var resjars = mod.Resources .Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)) .Select (r => (EmbeddedResource) r); foreach (var resjar in resjars) { var data = resjar.GetResourceData (); using (var outfs = File.Create (Path.Combine (importsDir, resjar.Name))) outfs.Write (data, 0, data.Length); } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { if (!Directory.Exists (outDirForDll)) Directory.CreateDirectory (outDirForDll); var finfo = new FileInfo (Path.Combine (outDirForDll, reszip.Name)); using (var fs = finfo.Create ()) { var data = reszip.GetResourceData (); fs.Write (data, 0, data.Length); } // temporarily extracted directory will look like: // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin using (var zip = new ZipFile (finfo.FullName)) { Files.ExtractAll (zip, outDirForDll); } // We used to *copy* the resources to overwrite other resources, // which resulted in missing resource issue. // Here we replaced copy with use of '-S' option and made it to work. #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists (binResDir)) resolvedResourceDirectories.Add (binResDir); if (Directory.Exists (binAssemblyDir)) resolvedAssetDirectories.Add (binAssemblyDir); #endif if (Directory.Exists (resDir)) resolvedResourceDirectories.Add (resDir); if (Directory.Exists (assemblyDir)) resolvedAssetDirectories.Add (assemblyDir); finfo.Delete (); } } stamp.Create ().Close (); } } foreach (var f in outdir.GetFiles ("*.jar") .Select (fi => fi.FullName)) jars.Add (f); }
public override bool Execute() { // In Xamarin Studio, if the project name isn't a valid C# identifier // then $(RootNamespace) is not set, and the generated Activity is // placed into the "Application" namespace. VS just munges the project // name to be a valid C# identifier. // Use "Application" as the default namespace name to work with XS. Namespace = Namespace ?? "Application"; Log.LogDebugMessage ("GenerateResourceDesigner Task"); Log.LogDebugMessage (" NetResgenOutputFile: {0}", NetResgenOutputFile); Log.LogDebugMessage (" JavaResgenInputFile: {0}", JavaResgenInputFile); Log.LogDebugMessage (" Namespace: {0}", Namespace); Log.LogDebugMessage (" ResourceDirectory: {0}", ResourceDirectory); Log.LogDebugTaskItemsAndLogical (" AdditionalResourceDirectories:", AdditionalResourceDirectories); Log.LogDebugMessage (" IsApplication: {0}", IsApplication); Log.LogDebugTaskItemsAndLogical (" Resources:", Resources); Log.LogDebugTaskItemsAndLogical (" References:", References); if (!File.Exists (JavaResgenInputFile)) return true; // ResourceDirectory may be a relative path, and // we need to compare it to absolute paths ResourceDirectory = Path.GetFullPath (ResourceDirectory); // Create our capitalization maps so we can support mixed case resources foreach (var item in Resources) { if (!item.ItemSpec.StartsWith (ResourceDirectory)) continue; var name = item.ItemSpec.Substring (ResourceDirectory.Length); var logical_name = item.GetMetadata ("LogicalName"); AddRename (name.Replace ('/', Path.DirectorySeparatorChar), logical_name.Replace ('/', Path.DirectorySeparatorChar)); } if (AdditionalResourceDirectories != null) { foreach (var additionalDir in AdditionalResourceDirectories) { var file = Path.Combine (ProjectDir, Path.GetDirectoryName (additionalDir.ItemSpec), "__res_name_case_map.txt"); if (File.Exists (file)) { foreach (var line in File.ReadAllLines (file).Where (l => !string.IsNullOrEmpty (l))) { string [] tok = line.Split (';'); AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar)); } } } } // Parse out the resources from the R.java file JavaResourceParser.Log = Log; var resources = JavaResourceParser.Parse (JavaResgenInputFile, IsApplication, resource_fixup); var extension = Path.GetExtension (NetResgenOutputFile); var language = string.Compare (extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension (extension); bool isVB = string.Equals (extension, ".vb", StringComparison.OrdinalIgnoreCase); bool isFSharp = string.Equals (language, "F#", StringComparison.OrdinalIgnoreCase); bool isCSharp = string.Equals (language, "C#", StringComparison.OrdinalIgnoreCase); // Let VB put this in the default namespace if (isVB) Namespace = string.Empty; // Create static resource overwrite methods for each Resource class in libraries. var assemblyNames = new List<string> (); if (IsApplication && References != null && References.Any ()) { // FIXME: should this be unified to some better code with ResolveLibraryProjectImports? var resolver = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false); foreach (var assemblyName in References) { var suffix = assemblyName.ItemSpec.EndsWith (".dll") ? String.Empty : ".dll"; string hintPath = assemblyName.GetMetadata ("HintPath").Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string fileName = assemblyName.ItemSpec + suffix; resolver.Load (Path.GetFullPath (assemblyName.ItemSpec)); if (!String.IsNullOrEmpty (hintPath) && !File.Exists (hintPath)) // ignore invalid HintPath hintPath = null; string assemblyPath = String.IsNullOrEmpty (hintPath) ? fileName : hintPath; if (MonoAndroidHelper.IsFrameworkAssembly (fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains (Path.GetFileName (fileName))) continue; Log.LogDebugMessage ("Scan assembly {0} for resource generator", fileName); assemblyNames.Add (assemblyPath); } var assemblies = assemblyNames.Select (assembly => resolver.GetAssembly (assembly)); new ResourceDesignerImportGenerator (Namespace, resources) .CreateImportMethods (assemblies); } AdjustConstructor (isFSharp, resources); foreach (var member in resources.Members) if (member is CodeTypeDeclaration) AdjustConstructor (isFSharp, (CodeTypeDeclaration) member); // Write out our Resources.Designer.cs file WriteFile (NetResgenOutputFile, resources, language, isFSharp, isCSharp); return !Log.HasLoggedErrors; }
// Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] void Extract( DirectoryAssemblyResolver res, ICollection <string> jars, ICollection <string> resolvedResourceDirectories, ICollection <string> resolvedAssetDirectories, ICollection <string> resolvedEnvironments) { var outdir = new DirectoryInfo(OutputImportDirectory); if (!outdir.Exists) { outdir.Create(); } foreach (var assembly in Assemblies) { res.Load(assembly.ItemSpec); } // FIXME: reorder references by import priority (not sure how to do that yet) foreach (var assemblyPath in Assemblies .Select(a => GetTargetAssembly(a)) .Where(a => a != null) .Distinct()) { foreach (var imp in new string [] { imports_dir, "library_project_imports" }.Distinct()) { string assemblyIdentName = Path.GetFileNameWithoutExtension(assemblyPath); if (UseShortFileNames) { assemblyIdentName = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly(assemblyIdentName); } string outDirForDll = Path.Combine(OutputImportDirectory, assemblyIdentName); string importsDir = Path.Combine(outDirForDll, imp); #if SEPARATE_CRUNCH // FIXME: review these binResDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. //string binResDir = Path.Combine (importsDir, "bin", "res"); //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets"); #endif string resDir = Path.Combine(importsDir, "res"); string assemblyDir = Path.Combine(importsDir, "assets"); // Skip already-extracted resources. var stamp = new FileInfo(Path.Combine(outdir.FullName, assemblyIdentName + ".stamp")); if (stamp.Exists && stamp.LastWriteTime > new FileInfo(assemblyPath).LastWriteTime) { Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists(binResDir)) { resolvedResourceDirectories.Add(binResDir); } if (Directory.Exists(binAssemblyDir)) { resolvedAssetDirectories.Add(binAssemblyDir); } #endif if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(resDir); } if (Directory.Exists(assemblyDir)) { resolvedAssetDirectories.Add(assemblyDir); } continue; } if (Directory.Exists(outDirForDll)) { Directory.Delete(outDirForDll, true); } Directory.CreateDirectory(importsDir); var assembly = res.GetAssembly(assemblyPath); foreach (var mod in assembly.Modules) { // android environment files foreach (var envtxt in mod.Resources .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) .Where(r => r is EmbeddedResource) .Cast <EmbeddedResource> ()) { if (!Directory.Exists(outDirForDll)) { Directory.CreateDirectory(outDirForDll); } var finfo = new FileInfo(Path.Combine(outDirForDll, envtxt.Name)); using (var fs = finfo.Create()) { var data = envtxt.GetResourceData(); fs.Write(data, 0, data.Length); } resolvedEnvironments.Add(finfo.FullName); } // embedded jars (EmbeddedJar, EmbeddedReferenceJar) var resjars = mod.Resources .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase)) .Select(r => (EmbeddedResource)r); foreach (var resjar in resjars) { var data = resjar.GetResourceData(); using (var outfs = File.Create(Path.Combine(importsDir, resjar.Name))) outfs.Write(data, 0, data.Length); } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { if (!Directory.Exists(outDirForDll)) { Directory.CreateDirectory(outDirForDll); } var finfo = new FileInfo(Path.Combine(outDirForDll, reszip.Name)); using (var fs = finfo.Create()) { var data = reszip.GetResourceData(); fs.Write(data, 0, data.Length); } // temporarily extracted directory will look like: // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin using (var zip = MonoAndroidHelper.ReadZipFile(finfo.FullName)) Files.ExtractAll(zip, outDirForDll); // We used to *copy* the resources to overwrite other resources, // which resulted in missing resource issue. // Here we replaced copy with use of '-S' option and made it to work. #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists(binResDir)) { resolvedResourceDirectories.Add(binResDir); } if (Directory.Exists(binAssemblyDir)) { resolvedAssetDirectories.Add(binAssemblyDir); } #endif if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(resDir); } if (Directory.Exists(assemblyDir)) { resolvedAssetDirectories.Add(assemblyDir); } finfo.Delete(); } } stamp.Create().Close(); } } foreach (var f in outdir.GetFiles("*.jar") .Select(fi => fi.FullName)) { jars.Add(f); } }
bool Execute(DirectoryAssemblyResolver res) { // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); } var resolver = new AssemblyResolver(res.ToResolverCache()); // Set up for linking var options = new LinkerOptions(); options.MainAssembly = res.GetAssembly(MainAssembly); options.OutputDirectory = Path.GetFullPath(OutputDirectory); options.LinkSdkOnly = string.Compare(LinkMode, "SdkOnly", true) == 0; options.LinkNone = false; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray(); options.I18nAssemblies = Linker.ParseI18nAssemblies(I18nAssemblies); if (!options.LinkSdkOnly) { options.RetainAssemblies = GetRetainAssemblies(res); } options.DumpDependencies = DumpDependencies; options.HttpClientHandlerType = HttpClientHandlerType; options.TlsProvider = TlsProvider; options.AddKeepAlives = AddKeepAlives; options.PreserveJniMarshalMethods = PreserveJniMarshalMethods; options.DeterministicOutput = Deterministic; options.LinkResources = LinkResources; var skiplist = new List <string> (); // Add LinkSkip options if (!string.IsNullOrWhiteSpace(LinkSkip)) { skiplist.AddRange(LinkSkip.Split(',', ';')); } options.SkippedAssemblies = skiplist; if (EnableProguard) { options.ProguardConfiguration = ProguardConfiguration; } // Link! try { LinkContext link_context; Linker.Process(options, this, out link_context); foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName(assembly.ItemSpec); var assemblyDestination = Path.Combine(OutputDirectory, filename); if (!MonoAndroidHelper.IsForceRetainedAssembly(filename)) { continue; } MonoAndroidHelper.CopyAssemblyAndSymbols(copysrc, assemblyDestination); } } catch (ResolutionException ex) { Diagnostic.Error(2006, ex, Properties.Resources.XA2006, ex.Member, ex.Member.Module.Assembly, ex.Scope); } return(true); }
protected override AssemblyDefinition GetCorlibAssembly() { return(resolver.GetAssembly(hasSystemPrivateCoreLib ? "System.Private.CoreLib.dll" : "mscorlib.dll")); }
void CreateMarshalMethodAssembly(string path) { var assembly = Assembly.LoadFile(Path.GetFullPath(path)); var baseName = Path.GetFileNameWithoutExtension(path); var assemblyName = new AssemblyName(baseName + "-JniMarshalMethods"); var fileName = assemblyName.Name + ".dll"; var destDir = string.IsNullOrEmpty(outDirectory) ? Path.GetDirectoryName(path) : outDirectory; var builder = CreateExportedMemberBuilder(); var matchType = typeNameRegexes.Count > 0; if (Verbose) { ColorWriteLine($"Preparing marshal method assembly '{assemblyName}'", ConsoleColor.Cyan); } var da = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Save, destDir); var dm = da.DefineDynamicModule("<default>", fileName); var ad = resolver.GetAssembly(path); PrepareTypeMap(ad.MainModule); Type[] types = null; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException e) { types = e.Types; foreach (var le in e.LoaderExceptions) { Warning($"Type Load exception{Environment.NewLine}{le}"); } } foreach (var systemType in types) { if (systemType == null) { continue; } var type = systemType.GetTypeInfo(); if (matchType) { var matched = false; foreach (var r in typeNameRegexes) { matched |= r.IsMatch(type.FullName); } if (!matched) { continue; } } if (type.IsInterface || type.IsGenericType || type.IsGenericTypeDefinition) { continue; } var td = FindType(type); if (td == null) { if (Verbose) { Warning($"Unable to find cecil's TypeDefinition of type {type}"); } continue; } if (!td.ImplementsInterface("Java.Interop.IJavaPeerable", cache)) { continue; } var existingMarshalMethodsType = td.GetNestedType(TypeMover.NestedName); if (existingMarshalMethodsType != null && !forceRegeneration) { Warning($"Marshal methods type '{existingMarshalMethodsType.GetAssemblyQualifiedName (cache)}' already exists. Skipped generation of marshal methods in assembly '{assemblyName}'. Use -f to force regeneration when desired."); return; } if (Verbose) { ColorWriteLine($"Processing {type} type", ConsoleColor.Yellow); } var registrationElements = new List <Expression> (); var targetType = Expression.Variable(typeof(Type), "targetType"); TypeBuilder dt = null; var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; var methods = type.GetMethods(flags); Array.Sort(methods, new MethodsComparer(type, td)); addedMethods.Clear(); foreach (var method in methods) { // TODO: Constructors var export = method.GetCustomAttribute <JavaCallableAttribute> (); string signature = null; string name = null; string methodName = method.Name; if (export == null) { if (method.IsGenericMethod || method.ContainsGenericParameters || method.IsGenericMethodDefinition || method.ReturnType.IsGenericType) { continue; } if (method.DeclaringType != type) { continue; } var md = td.GetMethodDefinition(method); if (md == null) { if (Verbose) { Warning($"Unable to find cecil's MethodDefinition of method {method}"); } continue; } if (!md.NeedsMarshalMethod(resolver, cache, method, ref name, ref methodName, ref signature)) { continue; } } #if !_ALL_THE_ARGUMENTS if (method.GetParameters().Length > 14) { Warning($"Methods taking more than 14 parameters is not supported."); continue; } #endif // !_ALL_THE_ARGUMENTS if (dt == null) { dt = GetTypeBuilder(dm, type); } if (addedMethods.Contains(methodName)) { continue; } if (Verbose) { Console.Write("Adding marshal method for "); ColorWriteLine($"{method}", ConsoleColor.Green); } var mb = dt.DefineMethod( methodName, System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static); var lambda = builder.CreateMarshalToManagedExpression(method); lambda.CompileToMethod(mb); if (export != null) { name = export.Name; signature = export.Signature; } if (signature == null) { signature = builder.GetJniMethodSignature(method); } registrationElements.Add(CreateRegistration(name, signature, lambda, targetType, methodName)); addedMethods.Add(methodName); } if (dt != null) { AddRegisterNativeMembers(dt, targetType, registrationElements); } } foreach (var tb in definedTypes) { tb.Value.CreateType(); } da.Save(fileName); if (Verbose) { ColorWriteLine($"Marshal method assembly '{assemblyName}' created", ConsoleColor.Cyan); } resolver.SearchDirectories.Add(destDir); var dstAssembly = resolver.GetAssembly(fileName); if (!string.IsNullOrEmpty(outDirectory)) { path = Path.Combine(outDirectory, Path.GetFileName(path)); } var mover = new TypeMover(dstAssembly, ad, path, definedTypes, resolver, cache); mover.Move(); if (!keepTemporary) { FilesToDelete.Add(dstAssembly.MainModule.FileName); } }
public override bool Execute() { Log.LogDebugMessage("LinkAssemblies Task"); Log.LogDebugMessage(" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage(" MainAssembly: {0}", MainAssembly); Log.LogDebugMessage(" OutputDirectory: {0}", OutputDirectory); Log.LogDebugMessage(" OptionalDestinationDirectory: {0}", OptionalDestinationDirectory); Log.LogDebugMessage(" I18nAssemblies: {0}", I18nAssemblies); Log.LogDebugMessage(" LinkMode: {0}", LinkMode); Log.LogDebugMessage(" LinkSkip: {0}", LinkSkip); Log.LogDebugTaskItems(" LinkDescriptions:", LinkDescriptions); Log.LogDebugTaskItems(" ResolvedAssemblies:", ResolvedAssemblies); Log.LogDebugMessage(" EnableProguard: {0}", EnableProguard); Log.LogDebugMessage(" ProguardConfiguration: {0}", ProguardConfiguration); Log.LogDebugMessage(" DumpDependencies: {0}", DumpDependencies); Log.LogDebugMessage(" LinkOnlyNewerThan: {0}", LinkOnlyNewerThan); var res = new DirectoryAssemblyResolver(Log.LogWarning, loadDebugSymbols: false); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); } var resolver = new AssemblyResolver(res.ToResolverCache()); // Set up for linking var options = new LinkerOptions(); options.MainAssembly = res.GetAssembly(MainAssembly); options.OutputDirectory = Path.GetFullPath(OutputDirectory); options.LinkSdkOnly = string.Compare(LinkMode, "SdkOnly", true) == 0; options.LinkNone = string.Compare(LinkMode, "None", true) == 0; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray(); options.I18nAssemblies = Linker.ParseI18nAssemblies(I18nAssemblies); if (!options.LinkSdkOnly) { options.RetainAssemblies = GetRetainAssemblies(res); } options.DumpDependencies = DumpDependencies; var skiplist = new List <string> (); if (string.Compare(UseSharedRuntime, "true", true) == 0) { skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a))); } if (!string.IsNullOrWhiteSpace(LinkOnlyNewerThan) && File.Exists(LinkOnlyNewerThan)) { var newerThan = File.GetLastWriteTime(LinkOnlyNewerThan); var skipOldOnes = ResolvedAssemblies.Where(a => File.GetLastWriteTime(a.ItemSpec) < newerThan); foreach (var old in skipOldOnes) { Log.LogMessage(MessageImportance.Low, " Skip linking unchanged file: " + old.ItemSpec); } skiplist = skipOldOnes.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec)).Concat(skiplist).ToList(); } // Add LinkSkip options if (!string.IsNullOrWhiteSpace(LinkSkip)) { foreach (var assembly in LinkSkip.Split(',', ';')) { skiplist.Add(assembly); } } options.SkippedAssemblies = skiplist; if (EnableProguard) { options.ProguardConfiguration = ProguardConfiguration; } // Link! try { LinkContext link_context; Linker.Process(options, out link_context); var copydst = OptionalDestinationDirectory ?? OutputDirectory; foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName(assembly.ItemSpec); if (options.LinkNone) { if (skiplist.Any(s => Path.GetFileNameWithoutExtension(filename) == s)) { // For skipped assemblies, skip if there is existing file in the destination. // We cannot just copy the linker output from *current* run output, because // it always renew the assemblies, in *different* binary values, whereas // the dll in the OptionalDestinationDirectory must retain old and unchanged. if (File.Exists(Path.Combine(copydst, filename))) { continue; } copysrc = assembly.ItemSpec; } else { // Prefer fixup assemblies if exists, otherwise just copy the original. copysrc = Path.Combine(OutputDirectory, filename); copysrc = File.Exists(copysrc) ? copysrc : assembly.ItemSpec; } } else if (!MonoAndroidHelper.IsForceRetainedAssembly(filename)) { continue; } MonoAndroidHelper.CopyIfChanged(copysrc, Path.Combine(copydst, filename)); try { MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", Path.Combine(copydst, filename + ".mdb")); } catch (Exception) { // skip it, mdb sometimes fails to read and it's optional } } } catch (ResolutionException ex) { Diagnostic.Error(2006, ex, "Reference to metadata item '{0}' (defined in '{1}') from '{1}' could not be resolved.", ex.Member, ex.Member.Module.Assembly, ex.Scope); } return(true); }
void DoExecute() { LogDebugMessage("GetAdditionalResourcesFromAssemblies Task"); LogDebugMessage(" AndroidSdkDirectory: {0}", AndroidSdkDirectory); LogDebugMessage(" AndroidNdkDirectory: {0}", AndroidNdkDirectory); LogDebugMessage(" CacheFile: {0}", CacheFile); LogDebugTaskItems(" Assemblies: ", Assemblies); if (Environment.GetEnvironmentVariable("XA_DL_IGNORE_CERT_ERRROS") == "yesyesyes") { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; LogDebugMessage(" Disabling download certificate validation callback."); } var androidResources = new HashSet <string> (); var javaLibraries = new HashSet <string> (); var nativeLibraries = new HashSet <string> (); var assemblies = new HashSet <string> (); if (Assemblies == null) { return; } var cacheFileFullPath = CacheFile; if (!Path.IsPathRooted(cacheFileFullPath)) { cacheFileFullPath = Path.Combine(WorkingDirectory, cacheFileFullPath); } System.Threading.Tasks.Task.Run(() => { // The cache location can be overriden by the (to be documented) XAMARIN_CACHEPATH CachePath = Environment.ExpandEnvironmentVariables(CachePathEnvironmentVar); CachePath = CachePath != CachePathEnvironmentVar ? CachePath : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CacheBaseDir); using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) { foreach (var assemblyItem in Assemblies) { string fullPath = Path.GetFullPath(assemblyItem.ItemSpec); if (DesignTimeBuild && !File.Exists(fullPath)) { LogWarning("Failed to load '{0}'. Check the file exists or the project has been built.", fullPath); continue; } if (assemblies.Contains(fullPath)) { LogDebugMessage(" Skip assembly: {0}, it was already processed", fullPath); continue; } // don't try to even load mscorlib it will fail. if (string.Compare(Path.GetFileNameWithoutExtension(fullPath), "mscorlib", StringComparison.OrdinalIgnoreCase) == 0) { continue; } assemblies.Add(fullPath); resolver.Load(fullPath); // Append source file name (without the Xamarin. prefix or extension) to the base folder // This would help avoid potential collisions. foreach (var ca in resolver.GetAssembly(assemblyItem.ItemSpec).CustomAttributes) { switch (ca.AttributeType.FullName) { case "Android.IncludeAndroidResourcesFromAttribute": AddAttributeValue(androidResources, ca, "XA5206", "{0}. Android resource directory {1} doesn't exist.", true, fullPath); break; case "Java.Interop.JavaLibraryReferenceAttribute": AddAttributeValue(javaLibraries, ca, "XA5207", "{0}. Java library file {1} doesn't exist.", false, fullPath); break; case "Android.NativeLibraryReferenceAttribute": AddAttributeValue(nativeLibraries, ca, "XA5210", "{0}. Native library file {1} doesn't exist.", false, fullPath); break; } } } } }, Token).ContinueWith(Complete); var result = base.Execute(); if (!result || Log.HasLoggedErrors) { if (File.Exists(cacheFileFullPath)) { File.Delete(cacheFileFullPath); } return; } var AdditionalAndroidResourcePaths = androidResources.ToArray(); var AdditionalJavaLibraryReferences = javaLibraries.ToArray(); var AdditionalNativeLibraryReferences = nativeLibraries .Where(x => MonoAndroidHelper.GetNativeLibraryAbi(x) != null) .ToArray(); var document = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("Paths", new XElement("AdditionalAndroidResourcePaths", AdditionalAndroidResourcePaths.Select(e => new XElement("AdditionalAndroidResourcePath", e))), new XElement("AdditionalJavaLibraryReferences", AdditionalJavaLibraryReferences.Select(e => new XElement("AdditionalJavaLibraryReference", e))), new XElement("AdditionalNativeLibraryReferences", AdditionalNativeLibraryReferences.Select(e => new XElement("AdditionalNativeLibraryReference", e))) )); document.SaveIfChanged(cacheFileFullPath); LogDebugTaskItems(" AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths); LogDebugTaskItems(" AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences); LogDebugTaskItems(" AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences); }
public override bool Execute() { LogDebugMessage ("GetAdditionalResourcesFromAssemblies Task"); LogDebugMessage (" AndroidSdkDirectory: {0}", AndroidSdkDirectory); LogDebugMessage (" AndroidNdkDirectory: {0}", AndroidNdkDirectory); LogDebugTaskItems (" Assemblies: ", Assemblies); if (Environment.GetEnvironmentVariable ("XA_DL_IGNORE_CERT_ERRROS") == "yesyesyes") { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; LogDebugMessage (" Disabling download certificate validation callback."); } var androidResources = new HashSet<string> (); var javaLibraries = new HashSet<string> (); var nativeLibraries = new HashSet<string> (); var assemblies = new HashSet<string> (); if (Assemblies == null) return true; System.Threading.Tasks.Task.Run (() => { // The cache location can be overriden by the (to be documented) XAMARIN_CACHEPATH CachePath = Environment.ExpandEnvironmentVariables (CachePathEnvironmentVar); CachePath = CachePath != CachePathEnvironmentVar ? CachePath : Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), CacheBaseDir); var resolver = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false); foreach (var assemblyItem in Assemblies) { string fullPath = Path.GetFullPath (assemblyItem.ItemSpec); if (assemblies.Contains (fullPath)) { LogDebugMessage (" Skip assembly: {0}, it was already processed", fullPath); continue; } assemblies.Add (fullPath); resolver.Load (fullPath); // Append source file name (without the Xamarin. prefix or extension) to the base folder // This would help avoid potential collisions. foreach (var ca in resolver.GetAssembly (assemblyItem.ItemSpec).CustomAttributes) { switch (ca.AttributeType.FullName) { case "Android.IncludeAndroidResourcesFromAttribute": AddAttributeValue (androidResources, ca, "XA5206", "{0}. Android resource directory {1} doesn't exist.", true, fullPath); break; case "Java.Interop.JavaLibraryReferenceAttribute": AddAttributeValue (javaLibraries, ca, "XA5207", "{0}. Java library file {1} doesn't exist.", false, fullPath); break; case "Android.NativeLibraryReferenceAttribute": AddAttributeValue (nativeLibraries, ca, "XA5210", "{0}. Native library file {1} doesn't exist.", false, fullPath); break; } } } }).ContinueWith ((t) => { if (t.Exception != null) Log.LogErrorFromException (t.Exception.GetBaseException ()); Complete (); }); var result = base.Execute (); var AdditionalAndroidResourcePaths = androidResources.ToArray (); var AdditionalJavaLibraryReferences = javaLibraries.ToArray (); var AdditionalNativeLibraryReferences = nativeLibraries .Where (x => MonoAndroidHelper.GetNativeLibraryAbi (x) != null) .ToArray (); var document = new XDocument ( new XDeclaration ("1.0", "UTF-8", null), new XElement ("Paths", new XElement ("AdditionalAndroidResourcePaths", AdditionalAndroidResourcePaths.Select(e => new XElement ("AdditionalAndroidResourcePath", e))), new XElement ("AdditionalJavaLibraryReferences", AdditionalJavaLibraryReferences.Select(e => new XElement ("AdditionalJavaLibraryReference", e))), new XElement ("AdditionalNativeLibraryReferences", AdditionalNativeLibraryReferences.Select(e => new XElement ("AdditionalNativeLibraryReference", e))) )); document.Save (CacheFile); LogDebugTaskItems (" AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths); LogDebugTaskItems (" AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences); LogDebugTaskItems (" AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences); return result && !Log.HasLoggedErrors; }
public override bool RunTask() { if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var readerParameters = new ReaderParameters { ReadSymbols = true, }; var writerParameters = new WriterParameters { DeterministicMvid = Deterministic, }; using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) { // Add SearchDirectories with ResolvedAssemblies foreach (var assembly in ResolvedAssemblies) { var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec)); if (!resolver.SearchDirectories.Contains(path)) { resolver.SearchDirectories.Add(path); } } // Set up the FixAbstractMethodsStep var step1 = new FixAbstractMethodsStep(resolver, new TypeDefinitionCache(), Log); // Set up the AddKeepAlivesStep var step2 = new MonoDroid.Tuner.AddKeepAlivesStep(new TypeDefinitionCache()); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; AssemblyDefinition assemblyDefinition = null; var assemblyName = Path.GetFileNameWithoutExtension(source.ItemSpec); if (!MTProfile.IsSdkAssembly(assemblyName) && !MTProfile.IsProductAssembly(assemblyName)) { assemblyDefinition = resolver.GetAssembly(source.ItemSpec); step1.CheckAppDomainUsage(assemblyDefinition, (string msg) => Log.LogMessageFromText(msg, MessageImportance.High)); } // Only run the step on "MonoAndroid" assemblies if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec)) { if (assemblyDefinition == null) { assemblyDefinition = resolver.GetAssembly(source.ItemSpec); } if (step1.FixAbstractMethods(assemblyDefinition) || (AddKeepAlives && step2.AddKeepAlives(assemblyDefinition))) { Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; assemblyDefinition.Write(destination.ItemSpec, writerParameters); continue; } } if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec)) { Log.LogDebugMessage($"Copied: {destination.ItemSpec}"); } else { Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}"); // NOTE: We still need to update the timestamp on this file, or this target would run again File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow); } } } return(!Log.HasLoggedErrors); }
public override bool Execute() { LogDebugMessage("GetAdditionalResourcesFromAssemblies Task"); LogDebugMessage(" AndroidSdkDirectory: {0}", AndroidSdkDirectory); LogDebugMessage(" AndroidNdkDirectory: {0}", AndroidNdkDirectory); LogDebugTaskItems(" Assemblies: ", Assemblies); if (Environment.GetEnvironmentVariable("XA_DL_IGNORE_CERT_ERRROS") == "yesyesyes") { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; LogDebugMessage(" Disabling download certificate validation callback."); } var androidResources = new HashSet <string> (); var javaLibraries = new HashSet <string> (); var nativeLibraries = new HashSet <string> (); var assemblies = new HashSet <string> (); if (Assemblies == null) { return(true); } System.Threading.Tasks.Task.Run(() => { // The cache location can be overriden by the (to be documented) XAMARIN_CACHEPATH CachePath = Environment.ExpandEnvironmentVariables(CachePathEnvironmentVar); CachePath = CachePath != CachePathEnvironmentVar ? CachePath : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CacheBaseDir); var resolver = new DirectoryAssemblyResolver(Log.LogWarning, loadDebugSymbols: false); foreach (var assemblyItem in Assemblies) { string fullPath = Path.GetFullPath(assemblyItem.ItemSpec); if (assemblies.Contains(fullPath)) { LogDebugMessage(" Skip assembly: {0}, it was already processed", fullPath); continue; } assemblies.Add(fullPath); resolver.Load(fullPath); // Append source file name (without the Xamarin. prefix or extension) to the base folder // This would help avoid potential collisions. foreach (var ca in resolver.GetAssembly(assemblyItem.ItemSpec).CustomAttributes) { switch (ca.AttributeType.FullName) { case "Android.IncludeAndroidResourcesFromAttribute": AddAttributeValue(androidResources, ca, "XA5206", "{0}. Android resource directory {1} doesn't exist.", true, fullPath); break; case "Java.Interop.JavaLibraryReferenceAttribute": AddAttributeValue(javaLibraries, ca, "XA5207", "{0}. Java library file {1} doesn't exist.", false, fullPath); break; case "Android.NativeLibraryReferenceAttribute": AddAttributeValue(nativeLibraries, ca, "XA5210", "{0}. Native library file {1} doesn't exist.", false, fullPath); break; } } } }).ContinueWith((t) => { if (t.Exception != null) { Log.LogErrorFromException(t.Exception.GetBaseException()); } Complete(); }); var result = base.Execute(); var AdditionalAndroidResourcePaths = androidResources.ToArray(); var AdditionalJavaLibraryReferences = javaLibraries.ToArray(); var AdditionalNativeLibraryReferences = nativeLibraries .Where(x => MonoAndroidHelper.GetNativeLibraryAbi(x) != null) .ToArray(); var document = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("Paths", new XElement("AdditionalAndroidResourcePaths", AdditionalAndroidResourcePaths.Select(e => new XElement("AdditionalAndroidResourcePath", e))), new XElement("AdditionalJavaLibraryReferences", AdditionalJavaLibraryReferences.Select(e => new XElement("AdditionalJavaLibraryReference", e))), new XElement("AdditionalNativeLibraryReferences", AdditionalNativeLibraryReferences.Select(e => new XElement("AdditionalNativeLibraryReference", e))) )); document.Save(CacheFile); LogDebugTaskItems(" AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths); LogDebugTaskItems(" AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences); LogDebugTaskItems(" AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences); return(result && !Log.HasLoggedErrors); }
public override bool Execute() { Log.LogDebugMessage ("LinkAssemblies Task"); Log.LogDebugMessage (" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage (" MainAssembly: {0}", MainAssembly); Log.LogDebugMessage (" OutputDirectory: {0}", OutputDirectory); Log.LogDebugMessage (" OptionalDestinationDirectory: {0}", OptionalDestinationDirectory); Log.LogDebugMessage (" I18nAssemblies: {0}", I18nAssemblies); Log.LogDebugMessage (" LinkMode: {0}", LinkMode); Log.LogDebugMessage (" LinkSkip: {0}", LinkSkip); Log.LogDebugTaskItems (" LinkDescriptions:", LinkDescriptions); Log.LogDebugTaskItems (" ResolvedAssemblies:", ResolvedAssemblies); Log.LogDebugMessage (" EnableProguard: {0}", EnableProguard); Log.LogDebugMessage (" ProguardConfiguration: {0}", ProguardConfiguration); Log.LogDebugMessage (" DumpDependencies: {0}", DumpDependencies); Log.LogDebugMessage (" LinkOnlyNewerThan: {0}", LinkOnlyNewerThan); var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load (Path.GetFullPath (assembly.ItemSpec)); } var resolver = new AssemblyResolver (res.ToResolverCache ()); // Set up for linking var options = new LinkerOptions (); options.MainAssembly = res.GetAssembly (MainAssembly); options.OutputDirectory = Path.GetFullPath (OutputDirectory); options.LinkSdkOnly = string.Compare (LinkMode, "SdkOnly", true) == 0; options.LinkNone = string.Compare (LinkMode, "None", true) == 0; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select (item => Path.GetFullPath (item.ItemSpec)).ToArray (); options.I18nAssemblies = Linker.ParseI18nAssemblies (I18nAssemblies); if (!options.LinkSdkOnly) options.RetainAssemblies = GetRetainAssemblies (res); options.DumpDependencies = DumpDependencies; var skiplist = new List<string> (); if (string.Compare (UseSharedRuntime, "true", true) == 0) skiplist.AddRange (Profile.SharedRuntimeAssemblies.Where (a => a.EndsWith (".dll")).Select (a => Path.GetFileNameWithoutExtension (a))); if (!string.IsNullOrWhiteSpace (LinkOnlyNewerThan) && File.Exists (LinkOnlyNewerThan)) { var newerThan = File.GetLastWriteTime (LinkOnlyNewerThan); var skipOldOnes = ResolvedAssemblies.Where (a => File.GetLastWriteTime (a.ItemSpec) < newerThan); foreach (var old in skipOldOnes) Log.LogMessage (MessageImportance.Low, " Skip linking unchanged file: " + old.ItemSpec); skiplist = skipOldOnes.Select (a => Path.GetFileNameWithoutExtension (a.ItemSpec)).Concat (skiplist).ToList (); } // Add LinkSkip options if (!string.IsNullOrWhiteSpace (LinkSkip)) foreach (var assembly in LinkSkip.Split (',', ';')) skiplist.Add (assembly); options.SkippedAssemblies = skiplist; if (EnableProguard) options.ProguardConfiguration = ProguardConfiguration; // Link! try { LinkContext link_context; Linker.Process (options, out link_context); var copydst = OptionalDestinationDirectory ?? OutputDirectory; foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName (assembly.ItemSpec); if (options.LinkNone) { if (skiplist.Any (s => Path.GetFileNameWithoutExtension (filename) == s)) { // For skipped assemblies, skip if there is existing file in the destination. // We cannot just copy the linker output from *current* run output, because // it always renew the assemblies, in *different* binary values, whereas // the dll in the OptionalDestinationDirectory must retain old and unchanged. if (File.Exists (Path.Combine (copydst, filename))) continue; copysrc = assembly.ItemSpec; } else { // Prefer fixup assemblies if exists, otherwise just copy the original. copysrc = Path.Combine (OutputDirectory, filename); copysrc = File.Exists (copysrc) ? copysrc : assembly.ItemSpec; } } else if (!MonoAndroidHelper.IsForceRetainedAssembly (filename)) continue; MonoAndroidHelper.CopyIfChanged (copysrc, Path.Combine (copydst, filename)); try { MonoAndroidHelper.CopyIfChanged (assembly.ItemSpec + ".mdb", Path.Combine (copydst, filename + ".mdb")); } catch (Exception) { // skip it, mdb sometimes fails to read and it's optional } } } catch (ResolutionException ex) { Diagnostic.Error (2006, ex, "Reference to metadata item '{0}' (defined in '{1}') from '{1}' could not be resolved.", ex.Member, ex.Member.Module.Assembly, ex.Scope); } return true; }
public override bool Execute() { Log.LogDebugMessage("StripEmbeddedLibraries Task"); Log.LogDebugTaskItems(" Assemblies: ", Assemblies); var res = new DirectoryAssemblyResolver(Log.LogWarning, true); foreach (var assembly in Assemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); } foreach (var assemblyName in Assemblies) { var suffix = assemblyName.ItemSpec.EndsWith(".dll") ? String.Empty : ".dll"; string hintPath = assemblyName.GetMetadata("HintPath").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string fileName = assemblyName.ItemSpec + suffix; if (!String.IsNullOrEmpty(hintPath) && !File.Exists(hintPath)) // ignore invalid HintPath { hintPath = null; } string assemblyPath = String.IsNullOrEmpty(hintPath) ? fileName : hintPath; if (MonoAndroidHelper.IsFrameworkAssembly(fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(Path.GetFileName(fileName))) { continue; } var assembly = res.GetAssembly(assemblyPath); bool assembly_modified = false; foreach (var mod in assembly.Modules) { // embedded jars var resjars = mod.Resources.Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase)).Select(r => (EmbeddedResource)r); foreach (var resjar in resjars.ToArray()) { Log.LogDebugMessage(" Stripped {0}", resjar.Name); mod.Resources.Remove(resjar); assembly_modified = true; } // embedded AndroidNativeLibrary archive var nativezip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (nativezip != null) { Log.LogDebugMessage(" Stripped {0}", nativezip.Name); mod.Resources.Remove(nativezip); assembly_modified = true; } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { Log.LogDebugMessage(" Stripped {0}", reszip.Name); mod.Resources.Remove(reszip); assembly_modified = true; } } if (assembly_modified) { Log.LogDebugMessage(" The stripped library is saved as {0}", assemblyPath); // Output assembly needs to regenerate symbol file even if no IL/metadata was touched // because Cecil still rewrites all assembly types in Cecil order (type A, nested types of A, type B, etc) // and not in the original order causing symbols if original order doesn't match Cecil order var wp = new WriterParameters() { WriteSymbols = assembly.MainModule.HasSymbols }; assembly.Write(assemblyPath, wp); } } return(true); }
IEnumerable<AssemblyDefinition> GetRetainAssemblies(DirectoryAssemblyResolver res) { List<AssemblyDefinition> retainList = null; foreach (var assembly in ResolvedAssemblies) { var filename = Path.GetFileName (assembly.ItemSpec); if (!MonoAndroidHelper.IsForceRetainedAssembly (filename)) continue; if (retainList == null) retainList = new List<AssemblyDefinition> (); retainList.Add (res.GetAssembly (assembly.ItemSpec)); } return retainList; }
// Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*] void Extract( DirectoryAssemblyResolver res, IDictionary <string, ITaskItem> jars, ICollection <ITaskItem> resolvedResourceDirectories, ICollection <ITaskItem> resolvedAssetDirectories, ICollection <ITaskItem> resolvedEnvironments) { // lets "upgrade" the old directory. string oldPath = Path.GetFullPath(Path.Combine(OutputImportDirectory, "..", "__library_projects__")); if (!OutputImportDirectory.Contains("__library_projects__") && Directory.Exists(oldPath)) { MonoAndroidHelper.SetDirectoryWriteable(Path.Combine(oldPath, "..")); Directory.Delete(oldPath, recursive: true); } var outdir = Path.GetFullPath(OutputImportDirectory); Directory.CreateDirectory(outdir); foreach (var assembly in Assemblies) { res.Load(assembly.ItemSpec); } // FIXME: reorder references by import priority (not sure how to do that yet) foreach (var assemblyPath in Assemblies .Select(a => a.ItemSpec) .Distinct()) { var fileName = Path.GetFileName(assemblyPath); if (MonoAndroidHelper.IsFrameworkAssembly(fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(fileName) && !MonoAndroidHelper.FrameworkEmbeddedNativeLibraryAssemblies.Contains(fileName)) { Log.LogDebugMessage($"Skipping framework assembly '{fileName}'."); continue; } if (DesignTimeBuild && !File.Exists(assemblyPath)) { Log.LogDebugMessage($"Skipping non-existent dependency '{assemblyPath}' during a design-time build."); continue; } if (assembliestoSkipExtraction.Contains(assemblyPath)) { Log.LogDebugMessage("Skipping resource extraction for '{0}' .", assemblyPath); continue; } string assemblyFileName = Path.GetFileNameWithoutExtension(assemblyPath); string assemblyIdentName = assemblyFileName; if (UseShortFileNames) { assemblyIdentName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(assemblyFileName); } string outDirForDll = Path.Combine(OutputImportDirectory, assemblyIdentName); string importsDir = Path.Combine(outDirForDll, ImportsDirectory); string nativeimportsDir = Path.Combine(outDirForDll, NativeImportsDirectory); string resDir = Path.Combine(importsDir, "res"); string assetsDir = Path.Combine(importsDir, "assets"); // Skip already-extracted resources. bool updated = false; string assemblyHash = MonoAndroidHelper.HashFile(assemblyPath); string stamp = Path.Combine(outdir, assemblyIdentName + ".stamp"); string stampHash = File.Exists(stamp) ? File.ReadAllText(stamp) : null; if (assemblyHash == stampHash) { Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); if (Directory.Exists(importsDir)) { foreach (var file in Directory.EnumerateFiles(importsDir, "*.jar", SearchOption.AllDirectories)) { AddJar(jars, Path.GetFullPath(file)); } } if (Directory.Exists(resDir)) { var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> { { OriginalFile, assemblyPath }, }); if (assembliesToSkipCaseFixup.Contains(assemblyPath)) { taskItem.SetMetadata(AndroidSkipResourceProcessing, "True"); } resolvedResourceDirectories.Add(taskItem); } if (Directory.Exists(assetsDir)) { resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> { { OriginalFile, assemblyPath } })); } foreach (var env in Directory.EnumerateFiles(outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly)) { resolvedEnvironments.Add(new TaskItem(env, new Dictionary <string, string> { { OriginalFile, assemblyPath } })); } continue; } Log.LogDebugMessage($"Refreshing {assemblyFileName}.dll"); var assembly = res.GetAssembly(assemblyPath); foreach (var mod in assembly.Modules) { // android environment files foreach (var envtxt in mod.Resources .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) .Where(r => r is EmbeddedResource) .Cast <EmbeddedResource> ()) { var outFile = Path.Combine(outDirForDll, envtxt.Name); using (var stream = envtxt.GetResourceStream()) { updated |= MonoAndroidHelper.CopyIfStreamChanged(stream, outFile); } resolvedEnvironments.Add(new TaskItem(Path.GetFullPath(outFile), new Dictionary <string, string> { { OriginalFile, assemblyPath } })); } // embedded jars (EmbeddedJar, EmbeddedReferenceJar) var resjars = mod.Resources .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase)) .Select(r => (EmbeddedResource)r); foreach (var resjar in resjars) { using (var stream = resjar.GetResourceStream()) { AddJar(jars, importsDir, resjar.Name, assemblyPath); updated |= MonoAndroidHelper.CopyIfStreamChanged(stream, Path.Combine(importsDir, resjar.Name)); } } var libzip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource; if (libzip != null) { List <string> files = new List <string> (); using (var stream = libzip.GetResourceStream()) using (var zip = Xamarin.Tools.Zip.ZipArchive.Open(stream)) { try { updated |= Files.ExtractAll(zip, nativeimportsDir, modifyCallback: (entryFullName) => { files.Add(Path.GetFullPath(Path.Combine(nativeimportsDir, entryFullName))); return(entryFullName .Replace("native_library_imports\\", "") .Replace("native_library_imports/", "")); }, deleteCallback: (fileToDelete) => { return(!files.Contains(fileToDelete)); }); } catch (PathTooLongException ex) { Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}"); return; } catch (NotSupportedException ex) { Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}"); return; } } } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { // temporarily extracted directory will look like: // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin using (var stream = reszip.GetResourceStream()) using (var zip = Xamarin.Tools.Zip.ZipArchive.Open(stream)) { try { updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => { var path = entryFullName .Replace("library_project_imports\\", "") .Replace("library_project_imports/", ""); if (path.EndsWith(".jar", StringComparison.OrdinalIgnoreCase)) { AddJar(jars, importsDir, path, assemblyPath); } return(path); }, deleteCallback: (fileToDelete) => { return(!jars.ContainsKey(fileToDelete)); }); } catch (PathTooLongException ex) { Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}"); return; } catch (NotSupportedException ex) { Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}"); return; } } // We used to *copy* the resources to overwrite other resources, // which resulted in missing resource issue. // Here we replaced copy with use of '-S' option and made it to work. if (Directory.Exists(resDir)) { var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> { { OriginalFile, assemblyPath } }); if (assembliesToSkipCaseFixup.Contains(assemblyPath)) { taskItem.SetMetadata(AndroidSkipResourceProcessing, "True"); } resolvedResourceDirectories.Add(taskItem); } if (Directory.Exists(assetsDir)) { resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> { { OriginalFile, assemblyPath } })); } } } if (Directory.Exists(importsDir)) { // Delete unknown files in the top directory of importsDir foreach (var file in Directory.EnumerateFiles(importsDir, "*")) { var fullPath = Path.GetFullPath(file); if (file.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase) && !resolvedEnvironments.Any(x => x.ItemSpec == fullPath)) { Log.LogDebugMessage($"Deleting unknown AndroidEnvironment file: {Path.GetFileName (file)}"); File.Delete(fullPath); updated = true; } else if (file.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) && !jars.ContainsKey(fullPath)) { Log.LogDebugMessage($"Deleting unknown jar: {Path.GetFileName (file)}"); File.Delete(fullPath); updated = true; } } if (assemblyHash != stampHash) { Log.LogDebugMessage($"Saving hash to {stamp}, changes: {updated}"); //NOTE: if the hash is different we always want to write the file, but preserve the timestamp if no changes WriteAllText(stamp, assemblyHash, preserveTimestamp: !updated); } } } foreach (var aarFile in AarLibraries ?? new ITaskItem[0]) { if (!File.Exists(aarFile.ItemSpec)) { continue; } string aarIdentityName = Path.GetFileNameWithoutExtension(aarFile.ItemSpec); if (UseShortFileNames) { aarIdentityName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(aarIdentityName); } string outDirForDll = Path.Combine(OutputImportDirectory, aarIdentityName); string importsDir = Path.Combine(outDirForDll, ImportsDirectory); string resDir = Path.Combine(importsDir, "res"); string assetsDir = Path.Combine(importsDir, "assets"); bool updated = false; string aarHash = MonoAndroidHelper.HashFile(aarFile.ItemSpec); string stamp = Path.Combine(outdir, aarIdentityName + ".stamp"); string stampHash = File.Exists(stamp) ? File.ReadAllText(stamp) : null; var aarFullPath = Path.GetFullPath(aarFile.ItemSpec); if (aarHash == stampHash) { Log.LogDebugMessage("Skipped {0}: extracted files are up to date", aarFile.ItemSpec); if (Directory.Exists(importsDir)) { foreach (var file in Directory.EnumerateFiles(importsDir, "*.jar", SearchOption.AllDirectories)) { AddJar(jars, Path.GetFullPath(file)); } } if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> { { OriginalFile, Path.GetFullPath(aarFile.ItemSpec) }, { AndroidSkipResourceProcessing, "True" }, })); } if (Directory.Exists(assetsDir)) { resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> { { OriginalFile, aarFullPath }, })); } continue; } Log.LogDebugMessage($"Refreshing {aarFile.ItemSpec}"); // temporarily extracted directory will look like: // _lp_/[aarFile] using (var zip = MonoAndroidHelper.ReadZipFile(aarFile.ItemSpec)) { try { updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => { var entryFileName = Path.GetFileName(entryFullName); var entryPath = Path.GetDirectoryName(entryFullName); if (entryFileName.StartsWith("internal_impl", StringComparison.InvariantCulture)) { var hash = Files.HashString(entryFileName); var jar = Path.Combine(entryPath, $"internal_impl-{hash}.jar"); AddJar(jars, importsDir, jar, aarFullPath); return(jar); } if (entryFullName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase)) { AddJar(jars, importsDir, entryFullName, aarFullPath); } return(entryFullName); }, deleteCallback: (fileToDelete) => { return(!jars.ContainsKey(fileToDelete)); }); if (Directory.Exists(importsDir) && aarHash != stampHash) { Log.LogDebugMessage($"Saving hash to {stamp}, changes: {updated}"); //NOTE: if the hash is different we always want to write the file, but preserve the timestamp if no changes WriteAllText(stamp, aarHash, preserveTimestamp: !updated); } } catch (PathTooLongException ex) { Log.LogErrorFromException(new PathTooLongException($"Error extracting resources from \"{aarFile.ItemSpec}\"", ex)); } } if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> { { OriginalFile, aarFullPath }, { AndroidSkipResourceProcessing, "True" }, })); } if (Directory.Exists(assetsDir)) { resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> { { OriginalFile, aarFullPath }, })); } } }
// Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*] void Extract( DirectoryAssemblyResolver res, ICollection <string> jars, ICollection <string> resolvedResourceDirectories, ICollection <string> resolvedAssetDirectories, ICollection <string> resolvedEnvironments) { // lets "upgrade" the old directory. string oldPath = Path.GetFullPath(Path.Combine(OutputImportDirectory, "..", "__library_projects__")); if (!OutputImportDirectory.Contains("__library_projects__") && Directory.Exists(oldPath)) { MonoAndroidHelper.SetDirectoryWriteable(Path.Combine(oldPath, "..")); Directory.Delete(oldPath, recursive: true); } var outdir = new DirectoryInfo(OutputImportDirectory); if (!outdir.Exists) { outdir.Create(); } foreach (var assembly in Assemblies) { res.Load(assembly.ItemSpec); } // FIXME: reorder references by import priority (not sure how to do that yet) foreach (var assemblyPath in Assemblies .Select(a => GetTargetAssembly(a)) .Where(a => a != null) .Distinct()) { string assemblyIdentName = Path.GetFileNameWithoutExtension(assemblyPath); if (UseShortFileNames) { assemblyIdentName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(assemblyIdentName); } string outDirForDll = Path.Combine(OutputImportDirectory, assemblyIdentName); string importsDir = Path.Combine(outDirForDll, ImportsDirectory); #if SEPARATE_CRUNCH // FIXME: review these binResDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. //string binResDir = Path.Combine (importsDir, "bin", "res"); //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets"); #endif string resDir = Path.Combine(importsDir, "res"); string assemblyDir = Path.Combine(importsDir, "assets"); // Skip already-extracted resources. var stamp = new FileInfo(Path.Combine(outdir.FullName, assemblyIdentName + ".stamp")); if (stamp.Exists && stamp.LastWriteTimeUtc > new FileInfo(assemblyPath).LastWriteTimeUtc) { Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists(binResDir)) { resolvedResourceDirectories.Add(binResDir); } if (Directory.Exists(binAssemblyDir)) { resolvedAssetDirectories.Add(binAssemblyDir); } #endif if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(resDir); } if (Directory.Exists(assemblyDir)) { resolvedAssetDirectories.Add(assemblyDir); } foreach (var env in Directory.EnumerateFiles(outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly)) { resolvedEnvironments.Add(env); } continue; } Log.LogDebugMessage("Refreshing {0}", assemblyPath); Directory.CreateDirectory(importsDir); var assembly = res.GetAssembly(assemblyPath); var assemblyLastWrite = new FileInfo(assemblyPath).LastWriteTimeUtc; bool updated = false; foreach (var mod in assembly.Modules) { // android environment files foreach (var envtxt in mod.Resources .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) .Where(r => r is EmbeddedResource) .Cast <EmbeddedResource> ()) { if (!Directory.Exists(outDirForDll)) { Directory.CreateDirectory(outDirForDll); } var finfo = new FileInfo(Path.Combine(outDirForDll, envtxt.Name)); if (!finfo.Exists || finfo.LastWriteTimeUtc > assemblyLastWrite) { using (var fs = finfo.Create()) { var data = envtxt.GetResourceData(); fs.Write(data, 0, data.Length); } updated = true; } resolvedEnvironments.Add(finfo.FullName); } // embedded jars (EmbeddedJar, EmbeddedReferenceJar) var resjars = mod.Resources .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase)) .Select(r => (EmbeddedResource)r); foreach (var resjar in resjars) { var outjarFile = Path.Combine(importsDir, resjar.Name); var fi = new FileInfo(outjarFile); if (!fi.Exists || fi.LastWriteTimeUtc > assemblyLastWrite) { var data = resjar.GetResourceData(); using (var outfs = File.Create(outjarFile)) outfs.Write(data, 0, data.Length); updated = true; } jars.Add(outjarFile); } // embedded AndroidResourceLibrary archive var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; if (reszip != null) { if (!Directory.Exists(outDirForDll)) { Directory.CreateDirectory(outDirForDll); } var finfo = new FileInfo(Path.Combine(outDirForDll, reszip.Name)); using (var fs = finfo.Create()) { var data = reszip.GetResourceData(); fs.Write(data, 0, data.Length); } // temporarily extracted directory will look like: // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin using (var zip = MonoAndroidHelper.ReadZipFile(finfo.FullName)) { try { updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => { return(entryFullName .Replace("library_project_imports\\", "") .Replace("library_project_imports/", "")); }, deleteCallback: (fileToDelete) => { return(!jars.Contains(fileToDelete)); }, forceUpdate: false); } catch (PathTooLongException ex) { Log.LogErrorFromException(new PathTooLongException($"Error extracting resources from \"{assemblyPath}\"", ex)); } } // We used to *copy* the resources to overwrite other resources, // which resulted in missing resource issue. // Here we replaced copy with use of '-S' option and made it to work. #if SEPARATE_CRUNCH // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. // Enabling these blindly causes build failure on ActionBarSherlock. if (Directory.Exists(binResDir)) { resolvedResourceDirectories.Add(binResDir); } if (Directory.Exists(binAssemblyDir)) { resolvedAssetDirectories.Add(binAssemblyDir); } #endif if (Directory.Exists(resDir)) { resolvedResourceDirectories.Add(resDir); } if (Directory.Exists(assemblyDir)) { resolvedAssetDirectories.Add(assemblyDir); } finfo.Delete(); } } if (Directory.Exists(importsDir) && (updated || !stamp.Exists)) { Log.LogDebugMessage("Touch {0}", stamp.FullName); stamp.Create().Close(); } } foreach (var f in outdir.GetFiles("*.jar", SearchOption.AllDirectories) .Select(fi => fi.FullName)) { if (jars.Contains(f)) { continue; } jars.Add(f); } }
public override bool Execute() { // In Xamarin Studio, if the project name isn't a valid C# identifier // then $(RootNamespace) is not set, and the generated Activity is // placed into the "Application" namespace. VS just munges the project // name to be a valid C# identifier. // Use "Application" as the default namespace name to work with XS. Namespace = Namespace ?? "Application"; Log.LogDebugMessage("GenerateResourceDesigner Task"); Log.LogDebugMessage(" NetResgenOutputFile: {0}", NetResgenOutputFile); Log.LogDebugMessage(" JavaResgenInputFile: {0}", JavaResgenInputFile); Log.LogDebugMessage(" Namespace: {0}", Namespace); Log.LogDebugMessage(" ResourceDirectory: {0}", ResourceDirectory); Log.LogDebugTaskItemsAndLogical(" AdditionalResourceDirectories:", AdditionalResourceDirectories); Log.LogDebugMessage(" IsApplication: {0}", IsApplication); Log.LogDebugMessage(" UseManagedResourceGenerator: {0}", UseManagedResourceGenerator); Log.LogDebugTaskItemsAndLogical(" Resources:", Resources); Log.LogDebugTaskItemsAndLogical(" References:", References); if (!File.Exists(JavaResgenInputFile) && !UseManagedResourceGenerator) { return(true); } // ResourceDirectory may be a relative path, and // we need to compare it to absolute paths ResourceDirectory = Path.GetFullPath(ResourceDirectory); // Create our capitalization maps so we can support mixed case resources foreach (var item in Resources) { if (!item.ItemSpec.StartsWith(ResourceDirectory)) { continue; } var name = item.ItemSpec.Substring(ResourceDirectory.Length); var logical_name = item.GetMetadata("LogicalName").Replace('\\', '/'); AddRename(name.Replace('/', Path.DirectorySeparatorChar), logical_name.Replace('/', Path.DirectorySeparatorChar)); } if (AdditionalResourceDirectories != null) { foreach (var additionalDir in AdditionalResourceDirectories) { var file = Path.Combine(ProjectDir, Path.GetDirectoryName(additionalDir.ItemSpec), "__res_name_case_map.txt"); if (File.Exists(file)) { foreach (var line in File.ReadAllLines(file).Where(l => !string.IsNullOrEmpty(l))) { string [] tok = line.Split(';'); AddRename(tok [1].Replace('/', Path.DirectorySeparatorChar), tok [0].Replace('/', Path.DirectorySeparatorChar)); } } } } // Parse out the resources from the R.java file CodeTypeDeclaration resources; if (UseManagedResourceGenerator) { var parser = new ManagedResourceParser() { Log = Log }; resources = parser.Parse(ResourceDirectory, AdditionalResourceDirectories?.Select(x => x.ItemSpec), IsApplication, resource_fixup); } else { var parser = new JavaResourceParser() { Log = Log }; resources = parser.Parse(JavaResgenInputFile, IsApplication, resource_fixup); } var extension = Path.GetExtension(NetResgenOutputFile); var language = string.Compare(extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension(extension); bool isVB = string.Equals(extension, ".vb", StringComparison.OrdinalIgnoreCase); bool isFSharp = string.Equals(language, "F#", StringComparison.OrdinalIgnoreCase); bool isCSharp = string.Equals(language, "C#", StringComparison.OrdinalIgnoreCase); // Let VB put this in the default namespace if (isVB) { Namespace = string.Empty; } // Create static resource overwrite methods for each Resource class in libraries. var assemblyNames = new List <string> (); if (IsApplication && References != null && References.Any()) { // FIXME: should this be unified to some better code with ResolveLibraryProjectImports? using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) { foreach (var assemblyName in References) { var suffix = assemblyName.ItemSpec.EndsWith(".dll") ? String.Empty : ".dll"; string hintPath = assemblyName.GetMetadata("HintPath").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string fileName = assemblyName.ItemSpec + suffix; string fullPath = Path.GetFullPath(assemblyName.ItemSpec); // Skip non existing files in DesignTimeBuild if (!File.Exists(fullPath) && DesignTimeBuild) { Log.LogDebugMessage("Skipping non existant dependancy '{0}' due to design time build.", fullPath); continue; } resolver.Load(fullPath); if (!String.IsNullOrEmpty(hintPath) && !File.Exists(hintPath)) // ignore invalid HintPath { hintPath = null; } string assemblyPath = String.IsNullOrEmpty(hintPath) ? fileName : hintPath; if (MonoAndroidHelper.IsFrameworkAssembly(fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(Path.GetFileName(fileName))) { continue; } Log.LogDebugMessage("Scan assembly {0} for resource generator", fileName); assemblyNames.Add(assemblyPath); } var assemblies = assemblyNames.Select(assembly => resolver.GetAssembly(assembly)); new ResourceDesignerImportGenerator(Namespace, resources, Log) .CreateImportMethods(assemblies); } } AdjustConstructor(isFSharp, resources); foreach (var member in resources.Members) { if (member is CodeTypeDeclaration) { AdjustConstructor(isFSharp, (CodeTypeDeclaration)member); } } // Write out our Resources.Designer.cs file WriteFile(NetResgenOutputFile, resources, language, isFSharp, isCSharp); return(!Log.HasLoggedErrors); }
void CreateMarshalMethodAssembly(string path) { var assembly = Assembly.LoadFile(path); var baseName = Path.GetFileNameWithoutExtension(path); var assemblyName = new AssemblyName(baseName + "-JniMarshalMethods"); var destPath = assemblyName.Name + ".dll"; var builder = CreateExportedMemberBuilder(); var matchType = typeNameRegexes.Count > 0; if (Verbose) { ColorWriteLine($"Preparing marshal method assembly '{assemblyName}'", ConsoleColor.Cyan); } var da = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Save, Path.GetDirectoryName(path)); var dm = da.DefineDynamicModule("<default>", destPath); var ad = resolver.GetAssembly(path); foreach (var type in assembly.DefinedTypes) { if (matchType) { var matched = false; foreach (var r in typeNameRegexes) { matched |= r.IsMatch(type.FullName); } if (!matched) { continue; } } if (type.IsGenericType || type.IsGenericTypeDefinition) { continue; } var td = ad.MainModule.FindType(type); if (td == null) { if (Verbose) { Warning($"Unable to find cecil's TypeDefinition of type {type}"); } continue; } if (!td.ImplementsInterface("Java.Interop.IJavaPeerable")) { continue; } var existingMarshalMethodsType = td.GetNestedType(TypeMover.NestedName); if (existingMarshalMethodsType != null && !forceRegeneration) { Warning($"Marshal methods type '{existingMarshalMethodsType.GetAssemblyQualifiedName ()}' already exists. Skipped generation of marshal methods. Use -f to force regeneration when desired."); continue; } var registrationElements = new List <Expression> (); var targetType = Expression.Variable(typeof(Type), "targetType"); TypeBuilder dt = null; var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; foreach (var method in type.GetMethods(flags)) { // TODO: Constructors var export = method.GetCustomAttribute <JavaCallableAttribute> (); string signature = null; string name = null; string methodName = method.Name; if (export == null) { if (method.IsGenericMethod || method.ContainsGenericParameters || method.IsGenericMethodDefinition || method.ReturnType.IsGenericType) { continue; } if (method.DeclaringType != type) { continue; } var md = td.GetMethodDefinition(method); if (md == null) { if (Verbose) { Warning($"Unable to find cecil's MethodDefinition of method {method}"); } continue; } if (!md.NeedsMarshalMethod(resolver, method, ref name, ref methodName, ref signature)) { continue; } } if (dt == null) { dt = GetTypeBuilder(dm, type); } if (Verbose) { Console.Write("Adding marshal method for "); ColorWriteLine($"{method}", ConsoleColor.Green); } var mb = dt.DefineMethod( methodName, System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static); var lambda = builder.CreateMarshalToManagedExpression(method); lambda.CompileToMethod(mb); if (export != null) { name = export.Name; signature = export.Signature; } if (signature == null) { signature = builder.GetJniMethodSignature(method); } registrationElements.Add(CreateRegistration(name, signature, lambda, targetType, methodName)); } if (dt != null) { AddRegisterNativeMembers(dt, targetType, registrationElements); } } foreach (var tb in definedTypes) { tb.Value.CreateType(); } da.Save(destPath); if (Verbose) { ColorWriteLine($"Marshal method assembly '{assemblyName}' created", ConsoleColor.Cyan); } var dstAssembly = resolver.GetAssembly(destPath); var mover = new TypeMover(dstAssembly, ad, definedTypes, resolver); mover.Move(); if (!keepTemporary) { FilesToDelete.Add(dstAssembly.MainModule.FileName); } definedTypes.Clear(); }