public void CompileIfRequired(ilspy::Mono.Cecil.AssemblyDefinition assembly, bool stopBeforeGeneratingCode = false) { if (_compiler != null && _previousAssembly == assembly && (_isFullyCompiled || stopBeforeGeneratingCode)) return; CompilationErrors = null; _compiler = null; #if DEBUG var framework = Frameworks.Instance.GetBySdkVersion(15); #else var framework = Frameworks.Instance.GetNewestVersion(); #endif string frameworkFolder = framework.Folder; var refFolders = new List<string> { frameworkFolder }; var module = new XModule(); var classLoader = new AssemblyClassLoader(module.OnClassLoaded); var resolver = new AssemblyResolver(refFolders, classLoader, module.OnAssemblyLoaded); var parameter = new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = resolver,ReadSymbols = true}; var assemblies = new[] { resolver.Load(assembly.MainModule.FullyQualifiedName, parameter) }.ToList(); List<AssemblyDefinition> references = new List<AssemblyDefinition>(); if(assembly.MainModule.Name != "dot42.dll") references = new[] { resolver.Load(AssemblyConstants.SdkAssemblyName, parameter) }.ToList(); foreach (var a in assemblies) references.Remove(a); var c = new AssemblyCompiler(CompilationMode.All, assemblies, references, new Table("pkg.name"), new NameConverter("pkg.name", ""), true, new AssemblyClassLoader(file => { }), definition => null, new DexMethodBodyCompilerCache(), new HashSet<string>(), module, _generateSetNextInstructionCode); c.StopCompilationBeforeGeneratingCode = stopBeforeGeneratingCode; c.StopAtFirstError = false; try { c.Compile(); } catch (AggregateException ex) { CompilationErrors = ex.Flatten().InnerExceptions.Select(e => e.Message.Replace(": ", "\n// ").Replace("; ", "\n// & ")).ToList(); } if (c.MapFile != null) { c.MapFile.Optimize(); MapFile = new MapFileLookup(c.MapFile); } _compiler = c; _previousAssembly = assembly; _isFullyCompiled = !stopBeforeGeneratingCode; }
/// <summary> /// Default ctor /// </summary> private ManifestBuilder(string assemblyFile, IEnumerable<string> referenceFolders, string packageName, NameConverter nsConverter, bool debuggable, List<string> appWidgetProviderCodeFiles, string targetSdkVersion) { #if DEBUG //Debugger.Launch(); #endif module = new XModule(); this.packageName = packageName; this.nsConverter = nsConverter; this.debuggable = debuggable; this.appWidgetProviderCodeFiles = appWidgetProviderCodeFiles; this.targetSdkVersion = targetSdkVersion; // Load assembly file if (!File.Exists(assemblyFile)) throw new ArgumentException(string.Format("Assembly {0} not found", assemblyFile)); var assemblyResolver = new AssemblyResolver(referenceFolders, null, module.OnAssemblyLoaded); var parameters = new ReaderParameters { AssemblyResolver = assemblyResolver}; assembly = assemblyResolver.Load(assemblyFile, parameters); }
/// <summary> /// Compile an assembly into a dex file. /// </summary> private static void CompileAssembly(CommandLineOptions options, NameConverter nsConverter) { // Load resource type usage info file var usedTypeNames = LoadResourceTypeUsageInformation(options); // Load assemblies var assemblies = new List<AssemblyDefinition>(); var module = new XModule(); var classLoader = new AssemblyClassLoader(module.OnClassLoaded); var resolver = new AssemblyResolver(options.ReferenceFolders, classLoader, module.OnAssemblyLoaded); var readerParameters = new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = resolver, SymbolReaderProvider = new SafeSymbolReaderProvider(), ReadSymbols = true }; foreach (var asmPath in options.Assemblies) { var asm = resolver.Load(asmPath, readerParameters); module.OnAssemblyLoaded(asm); classLoader.LoadAssembly(asm); assemblies.Add(asm); } // Load references var references = new List<AssemblyDefinition>(); foreach (var refPath in options.References) { var asm = resolver.Load(refPath, readerParameters); module.OnAssemblyLoaded(asm); classLoader.LoadAssembly(asm); references.Add(asm); } // Load resources Table table; using (var stream = new FileStream(options.InputResources, FileMode.Open, FileAccess.Read)) { table = new Table(stream); } // Create compiler var compiler = new AssemblyCompiler(options.CompilationMode, assemblies, references, table, nsConverter, options.DebugInfo, classLoader, usedTypeNames, module); compiler.Compile(); compiler.Save(options.OutputFolder, options.FreeAppsKeyPath); }
/// <summary> /// Compile an assembly into a dex file. /// </summary> private static void CompileAssembly(CommandLineOptions options, NameConverter nsConverter) { // Load resource type usage info file var usedTypeNames = LoadResourceTypeUsageInformation(options); // Load assemblies List<AssemblyDefinition> assemblies = new List<AssemblyDefinition>(); List<AssemblyDefinition> references= new List<AssemblyDefinition>(); var dxJarCompiler = options.EnableDxJarCompilation ? new DxClassfileMethodBodyCompiler(options.OutputFolder, options.DebugInfo) : null; Action<ClassSource> jarLoaded = dxJarCompiler != null ? dxJarCompiler.PreloadJar : (Action<ClassSource>)null; var module = new XModule(); var classLoader = new AssemblyClassLoader(module.OnClassLoaded); var resolver = new AssemblyResolver(options.ReferenceFolders, classLoader, module.OnAssemblyLoaded); // initialize compiler cache in background. var ccache = options.EnableCompilerCache ? new DexMethodBodyCompilerCache(options.OutputFolder, resolver.GetFileName) : new DexMethodBodyCompilerCache(); var readerParameters = new ReaderParameters { AssemblyResolver = resolver, SymbolReaderProvider = new SafeSymbolReaderProvider(), ReadSymbols = true, ReadingMode = ReadingMode.Immediate }; // load assemblies var toLoad = options.Assemblies.Select(path => new {path, target = assemblies}) .Concat(options.References.Select(path => new {path, target = references})) // Some micro optimizations... // Our startup is IO bound until we have loaded first assembly from disk. // So just load from smallest to largest. .Select(load => new { load.path, load.target, length = new FileInfo(resolver.ResolvePath(load.path)).Length}) .OrderBy(load=>load.length) .ToList(); using (AssemblyCompiler.Profile("for loading assemblies")) { toLoad.AsParallel().ForAll( //toLoad.ForEach( load => { var assm = resolver.Load(load.path, readerParameters); lock (load.target) load.target.Add(assm); }); } // Load resources Table table; using (var stream = new FileStream(options.InputResources, FileMode.Open, FileAccess.Read)) { table = new Table(stream); } // Create compiler var compiler = new AssemblyCompiler(options.CompilationMode, assemblies, references, table, nsConverter, options.DebugInfo, classLoader, resolver.GetFileName, ccache, usedTypeNames, module, options.GenerateSetNextInstructionCode); compiler.DxClassfileMethodBodyCompiler = dxJarCompiler; using (AssemblyCompiler.Profile("total compilation time", true)) compiler.Compile(); ccache.PrintStatistics(); using (AssemblyCompiler.Profile("saving results")) compiler.Save(options.OutputFolder, options.FreeAppsKeyPath); }
/// <summary> /// Program main code /// </summary> /// <returns>true on success, false on usage due to invalid options</returns> internal static bool MainCode(CommandLineOptions options) { if (options.ShowHelp) { return false; } // Detect target var target = Locations.SetTarget(options.Target); // Build APK/BAR? if (!string.IsNullOrEmpty(options.PackagePath)) { #if DEBUG //Debugger.Launch(); #endif // Build APK first var apkPath = options.PackagePath; if (target == Targets.BlackBerry) { // Put APK in TEMP folder apkPath = Path.GetTempFileName() + ".apk"; } var apkBuilder = new ApkBuilder.ApkBuilder(apkPath); apkBuilder.MapFilePath = Path.ChangeExtension(options.PackagePath, ".d42map"); apkBuilder.ManifestPath = options.ManifestFile; apkBuilder.DexFiles.AddRange(options.DexFiles); apkBuilder.MapFiles.AddRange(options.MapFiles); if (options.Assemblies.Any()) { apkBuilder.Assemblies.AddRange(options.Assemblies); } apkBuilder.ResourcesFolder = options.ResourcesFolder; apkBuilder.PfxFile = options.PfxFile; apkBuilder.PfxPassword = options.PfxPassword; apkBuilder.CertificateThumbprint = options.CertificateThumbprint; apkBuilder.FreeAppsKeyPath = options.FreeAppsKeyPath; apkBuilder.PackageName = options.PackageName; apkBuilder.NativeCodeLibraries.AddRange(options.NativeCodeLibs); apkBuilder.Build(); if (target == Targets.BlackBerry) { // Now build BAR var barBuilder = new BarBuilder.BarBuilder(options.PackagePath); barBuilder.ApkPath = apkPath; barBuilder.DebugTokenPath = options.DebugToken; barBuilder.Build(); } } else if (!string.IsNullOrEmpty(options.JarFile)) // Import jar file? { var module = new XModule(); var resolver = new AssemblyResolver(options.ReferenceFolders, new AssemblyClassLoader(module.OnClassLoaded), module.OnAssemblyLoaded); var jarImporter = new JarImporter(options.JarFile, options.LibName, options.ImportStubsOnly, false/*true*/, options.GeneratedCodeFolder, resolver, options.ExcludedPackages, options.UseAutoExcludedPackages); foreach (var path in options.References) { jarImporter.ImportAssembly(path); } jarImporter.ImportAssembliesCompleted(); jarImporter.Import(); } else if (options.WcfProxyInputAssemblies.Any()) // Generate WCF Proxy { var resolver = new AssemblyResolver(options.ReferenceFolders, null, null); var readerParameters = new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = resolver, SymbolReaderProvider = new SafeSymbolReaderProvider(), ReadSymbols = true }; var assemblies = options.WcfProxyInputAssemblies.Select(x => resolver.Load(x, readerParameters)).ToList(); var proxyTool = new ProxyBuilderTool(assemblies, options.GeneratedProxySourcePath); proxyTool.Build(); } else { // Create namespace converter var nsConverter = new NameConverter(options.PackageName, options.RootNamespace); // Create manifest file? if (options.CreateManifest) { ManifestBuilder.CreateManifest(target, options.Assemblies.First(), options.ReferenceFolders, options.PackageName, nsConverter, options.DebugInfo, options.AppWidgetProviders, options.TargetSdkVersion, options.OutputFolder); } else { // Code compilation? if (options.Assemblies.Any()) { #if DEBUG //Debugger.Launch(); #endif using (AssemblyCompiler.Profile("total processing time", true)) CompileAssembly(options, nsConverter); } } // Xml compilation if (options.CompileResources) { if (!CompileResources(options)) return false; } } return true; }
/// <summary> /// Extract resources out of library project references /// </summary> private void ExtractLibraryProjectResources(string folder, string referencePath, AssemblyResolver resolver) { #if DEBUG //Debugger.Launch(); #endif var parameters = new ReaderParameters { AssemblyResolver = resolver }; var assembly = resolver.Load(referencePath, parameters); // Go over all LibraryProjectReference attributes. foreach (var attr in assembly.CustomAttributes.Where(x => (x.AttributeType.Name == AttributeConstants.LibraryProjectReferenceAttributeName) && (x.AttributeType.Namespace == AttributeConstants.Dot42AttributeNamespace))) { var libPackageName = (string)attr.ConstructorArguments[0].Value; var prefix = libPackageName + ".res."; foreach (var resource in assembly.MainModule.Resources.OfType<EmbeddedResource>().Where(x => x.Name.StartsWith(prefix))) { var name = resource.Name.Substring(prefix.Length); var parts = name.Split(new[] { '.' }, 2); if (parts.Length == 2) { // Export resource to disk var targetPath = Path.Combine(Path.Combine(folder, parts[0]), parts[1]); var outputFolder = Path.GetDirectoryName(targetPath); if (!Directory.Exists(outputFolder)) Directory.CreateDirectory(outputFolder); File.WriteAllBytes(targetPath, resource.GetResourceData()); // Post process var xmlName = parts[0].Split(new[] { '-' }, 2)[0]; var resourceType = ResourceExtensions.GetResourceTypeFromXmlName(xmlName); ProcessResource(targetPath, resourceType); } } } }