public override bool Execute(out IList <Exception> thrownExceptions)
        {
            thrownExceptions = null;
            LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Preparing debug code for xamlc, assembly: {Assembly}");

            var resolver = new DefaultAssemblyResolver();

            if (!string.IsNullOrEmpty(DependencyPaths))
            {
                foreach (var dep in DependencyPaths.Split(';'))
                {
                    LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {dep}");
                    resolver.AddSearchDirectory(dep);
                }
            }
            if (!string.IsNullOrEmpty(ReferencePath))
            {
                var paths = ReferencePath.Replace("//", "/").Split(';');
                foreach (var p in paths)
                {
                    var searchpath = IOPath.GetDirectoryName(p);
                    LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
                    resolver.AddSearchDirectory(searchpath);
                }
            }

            var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");

            using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly, new ReaderParameters {
                ReadWrite = true,
                ReadSymbols = debug,
                AssemblyResolver = resolver
            })) {
                foreach (var module in assemblyDefinition.Modules)
                {
                    LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
                    foreach (var resource in module.Resources.OfType <EmbeddedResource>())
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
                        if (!resource.IsXaml(module, out var classname))
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
                            continue;
                        }
                        TypeDefinition typeDef = module.GetType(classname);
                        if (typeDef == null)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
                            continue;
                        }

                        var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
                        if (initComp == null)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
                            continue;
                        }
                        var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
                        if (initCompRuntime == null)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
                            initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
                            initCompRuntime.Body.InitLocals = true;
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
                            initCompRuntime.Body = new MethodBody(initCompRuntime);
                            var iCRIl = initCompRuntime.Body.GetILProcessor();
                            foreach (var instr in initComp.Body.Instructions)
                            {
                                iCRIl.Append(instr);
                            }
                            initComp.Body.Instructions.Clear();
                            initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
                            typeDef.Methods.Add(initCompRuntime);
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                        }

//						IL_0000:  ldarg.0
//						IL_0001:  callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ContentPage::'.ctor'()
//
//						IL_0006:  nop
//						IL_0007:  ldarg.1
//						IL_0008:  brfalse IL_0018
//
//						IL_000d:  ldarg.0
//						IL_000e:  callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitializeComponent()
//						IL_0013:  br IL_001e
//
//						IL_0018:  ldarg.0
//						IL_0019:  callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::__InitComponentRuntime()
//						IL_001e:  ret

                        var altCtor = typeDef.Methods.FirstOrDefault(md => md.IsConstructor &&
                                                                     md.Parameters.Count == 1 &&
                                                                     md.Parameters[0].ParameterType == module.TypeSystem.Boolean);
                        if (altCtor != null)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing body of {typeDef.Name}.{typeDef.Name} (bool {altCtor.Parameters[0].Name})");
                        }
                        else
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Adding {typeDef.Name}.{typeDef.Name} (bool useCompiledXaml)");
                            altCtor = new MethodDefinition(".ctor",
                                                           MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
                                                           MethodAttributes.RTSpecialName, module.TypeSystem.Void);
                            altCtor.Parameters.Add(new ParameterDefinition("useCompiledXaml", ParameterAttributes.None,
                                                                           module.TypeSystem.Boolean));
                        }

                        var body = new MethodBody(altCtor)
                        {
                            InitLocals = true
                        };
                        var il  = body.GetILProcessor();
                        var br2 = Instruction.Create(OpCodes.Ldarg_0);
                        var ret = Instruction.Create(OpCodes.Ret);
                        il.Emit(OpCodes.Ldarg_0);
                        MethodReference baseCtor;
                        if (typeDef.BaseType.Resolve().GetConstructors().FirstOrDefault(c => c.HasParameters && c.Parameters.Count == 1 && c.Parameters[0].Name == "useCompiledXaml") is MethodDefinition baseCtorDef)
                        {
                            baseCtor = module.ImportReference(baseCtorDef);
                            baseCtor = module.ImportReference(baseCtor.ResolveGenericParameters(typeDef.BaseType, module));
                            il.Emit(OpCodes.Ldarg_1);
                        }
                        else
                        {
                            baseCtor = module.ImportReference(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false));
                            baseCtor = module.ImportReference(baseCtor.ResolveGenericParameters(typeDef.BaseType, module));
                        }
                        il.Emit(OpCodes.Callvirt, baseCtor);

                        il.Emit(OpCodes.Nop);
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Brfalse, br2);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, initComp);
                        il.Emit(OpCodes.Br, ret);

                        il.Append(br2);
                        il.Emit(OpCodes.Callvirt, initCompRuntime);
                        il.Append(ret);

                        altCtor.Body = body;
                        if (!typeDef.Methods.Contains(altCtor))
                        {
                            typeDef.Methods.Add(altCtor);
                        }
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                    }
                }
                LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Writing the assembly.");
                assemblyDefinition.Write(new WriterParameters {
                    WriteSymbols = debug
                });
            }
            LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}done.");

            return(true);
        }
Beispiel #2
0
        public override bool Execute(out IList <Exception> thrownExceptions)
        {
            thrownExceptions = null;
            Logger           = Logger ?? new Logger(null, Verbosity);
            Logger.LogLine(1, "Compiling Xaml");
            Logger.LogLine(1, "\nAssembly: {0}", Assembly);
            if (!string.IsNullOrEmpty(DependencyPaths))
            {
                Logger.LogLine(1, "DependencyPaths: \t{0}", DependencyPaths);
            }
            if (!string.IsNullOrEmpty(ReferencePath))
            {
                Logger.LogLine(1, "ReferencePath: \t{0}", ReferencePath.Replace("//", "/"));
            }
            Logger.LogLine(3, "DebugSymbols:\"{0}\"", DebugSymbols);
            Logger.LogLine(3, "DebugType:\"{0}\"", DebugType);
            var  skipassembly = true;            //change this to false to enable XamlC by default
            bool success      = true;

            if (!File.Exists(Assembly))
            {
                Logger.LogLine(1, "Assembly file not found. Skipping XamlC.");
                return(true);
            }

            var resolver = new XamlCAssemblyResolver();

            if (!string.IsNullOrEmpty(DependencyPaths))
            {
                foreach (var dep in DependencyPaths.Split(';'))
                {
                    Logger.LogLine(3, "Adding searchpath {0}", dep);
                    resolver.AddSearchDirectory(dep);
                }
            }

            if (!string.IsNullOrEmpty(ReferencePath))
            {
                var paths = ReferencePath.Replace("//", "/").Split(';');
                foreach (var p in paths)
                {
                    var searchpath = Path.GetDirectoryName(p);
                    Logger.LogLine(3, "Adding searchpath {0}", searchpath);
                    resolver.AddSearchDirectory(searchpath);
                }
            }

            var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");

            var readerParameters = new ReaderParameters {
                AssemblyResolver = resolver,
                ReadWrite        = !ReadOnly,
                ReadSymbols      = debug,
            };

            using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), readerParameters)) {
                CustomAttribute xamlcAttr;
                if (assemblyDefinition.HasCustomAttributes &&
                    (xamlcAttr =
                         assemblyDefinition.CustomAttributes.FirstOrDefault(
                             ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                {
                    var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                    if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                    {
                        skipassembly = true;
                    }
                    if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                    {
                        skipassembly = false;
                    }
                }

                foreach (var module in assemblyDefinition.Modules)
                {
                    var skipmodule = skipassembly;
                    if (module.HasCustomAttributes &&
                        (xamlcAttr =
                             module.CustomAttributes.FirstOrDefault(
                                 ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                    {
                        var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                        if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                        {
                            skipmodule = true;
                        }
                        if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                        {
                            skipmodule = false;
                        }
                    }

                    Logger.LogLine(2, " Module: {0}", module.Name);
                    var resourcesToPrune = new List <EmbeddedResource>();
                    foreach (var resource in module.Resources.OfType <EmbeddedResource>())
                    {
                        Logger.LogString(2, "  Resource: {0}... ", resource.Name);
                        string classname;
                        if (!resource.IsXaml(out classname))
                        {
                            Logger.LogLine(2, "skipped.");
                            continue;
                        }
                        TypeDefinition typeDef = module.GetType(classname);
                        if (typeDef == null)
                        {
                            Logger.LogLine(2, "no type found... skipped.");
                            continue;
                        }
                        var skiptype = skipmodule;
                        if (typeDef.HasCustomAttributes &&
                            (xamlcAttr =
                                 typeDef.CustomAttributes.FirstOrDefault(
                                     ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                        {
                            var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                            if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                            {
                                skiptype = true;
                            }
                            if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                            {
                                skiptype = false;
                            }
                        }

                        if (Type != null)
                        {
                            skiptype = !(Type == classname);
                        }

                        if (skiptype)
                        {
                            Logger.LogLine(2, "Has XamlCompilationAttribute set to Skip and not Compile... skipped");
                            continue;
                        }

                        var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
                        if (initComp == null)
                        {
                            Logger.LogLine(2, "no InitializeComponent found... skipped.");
                            continue;
                        }
                        Logger.LogLine(2, "");

                        CustomAttribute xamlFilePathAttr;
                        var             xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlFilePathAttribute")) != null ?
                                                       (string)xamlFilePathAttr.ConstructorArguments[0].Value :
                                                       resource.Name;

                        var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
                        if (initCompRuntime != null)
                        {
                            Logger.LogLine(2, "   __InitComponentRuntime already exists... not creating");
                        }
                        else
                        {
                            Logger.LogString(2, "   Creating empty {0}.__InitComponentRuntime ...", typeDef.Name);
                            initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
                            initCompRuntime.Body.InitLocals = true;
                            Logger.LogLine(2, "done.");
                            Logger.LogString(2, "   Copying body of InitializeComponent to __InitComponentRuntime ...", typeDef.Name);
                            initCompRuntime.Body = new MethodBody(initCompRuntime);
                            var iCRIl = initCompRuntime.Body.GetILProcessor();
                            foreach (var instr in initComp.Body.Instructions)
                            {
                                iCRIl.Append(instr);
                            }
                            initComp.Body.Instructions.Clear();
                            initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
                            initComp.Body.InitLocals = true;
                            typeDef.Methods.Add(initCompRuntime);
                            Logger.LogLine(2, "done.");
                        }

                        Logger.LogString(2, "   Parsing Xaml... ");
                        var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
                        if (rootnode == null)
                        {
                            Logger.LogLine(2, "failed.");
                            continue;
                        }
                        Logger.LogLine(2, "done.");

                        hasCompiledXamlResources = true;

                        Logger.LogString(2, "   Replacing {0}.InitializeComponent ()... ", typeDef.Name);
                        Exception e;
                        if (!TryCoreCompile(initComp, initCompRuntime, rootnode, resource.Name, out e))
                        {
                            success = false;
                            Logger.LogLine(2, "failed.");
                            (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                            Logger.LogException(null, null, null, xamlFilePath, e);
                            Logger.LogLine(4, e.StackTrace);
                            continue;
                        }
                        if (Type != null)
                        {
                            InitCompForType = initComp;
                        }

                        Logger.LogLine(2, "done.");

                        if (OptimizeIL)
                        {
                            Logger.LogString(2, "   Optimizing IL... ");
                            initComp.Body.Optimize();
                            Logger.LogLine(2, "done");
                        }

                        Logger.LogLine(2, "");

#pragma warning disable 0618
                        if (OutputGeneratedILAsCode)
                        {
                            Logger.LogLine(2, "   Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated");
                        }
#pragma warning restore 0618
                        resourcesToPrune.Add(resource);
                    }
                    if (!KeepXamlResources)
                    {
                        if (resourcesToPrune.Any())
                        {
                            Logger.LogLine(2, "  Removing compiled xaml resources");
                        }
                        foreach (var resource in resourcesToPrune)
                        {
                            Logger.LogString(2, "   Removing {0}... ", resource.Name);
                            module.Resources.Remove(resource);
                            Logger.LogLine(2, "done");
                        }
                    }

                    Logger.LogLine(2, "");
                }

                if (!hasCompiledXamlResources)
                {
                    Logger.LogLine(1, "No compiled resources. Skipping writing assembly.");
                    return(success);
                }

                if (ReadOnly)
                {
                    return(success);
                }

                Logger.LogString(1, "Writing the assembly... ");
                try {
                    assemblyDefinition.Write(new WriterParameters {
                        WriteSymbols = debug,
                    });
                    Logger.LogLine(1, "done.");
                } catch (Exception e) {
                    Logger.LogLine(1, "failed.");
                    Logger.LogException(null, null, null, null, e);
                    (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                    Logger.LogLine(4, e.StackTrace);
                    success = false;
                }
            }
            return(success);
        }
Beispiel #3
0
        public override bool Execute(out IList <Exception> thrownExceptions)
        {
            thrownExceptions = null;
            LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Compiling Xaml, assembly: {Assembly}");
            var  skipassembly = !CompileByDefault;
            bool success      = true;

            if (!File.Exists(Assembly))
            {
                LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}Assembly file not found. Skipping XamlC.");
                return(true);
            }

            using (var fallbackResolver = DefaultAssemblyResolver == null ? new XamlCAssemblyResolver() : null) {
                var resolver = DefaultAssemblyResolver ?? fallbackResolver;
                if (resolver is XamlCAssemblyResolver xamlCResolver)
                {
                    if (!string.IsNullOrEmpty(DependencyPaths))
                    {
                        foreach (var dep in DependencyPaths.Split(';').Distinct())
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {dep}");
                            xamlCResolver.AddSearchDirectory(dep);
                        }
                    }

                    if (!string.IsNullOrEmpty(ReferencePath))
                    {
                        var paths = ReferencePath.Replace("//", "/").Split(';').Distinct();
                        foreach (var p in paths)
                        {
                            var searchpath = Path.GetDirectoryName(p);
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
                            xamlCResolver.AddSearchDirectory(searchpath);
                        }
                    }
                }
                else
                {
                    LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Ignoring dependency and reference paths due to an unsupported resolver");
                }

                var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");

                var readerParameters = new ReaderParameters {
                    AssemblyResolver = resolver,
                    ReadWrite        = !ValidateOnly,
                    ReadSymbols      = debug && !ValidateOnly,                // We don't need symbols for ValidateOnly, since we won't be writing
                };

                using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), readerParameters)) {
                    CustomAttribute xamlcAttr;
                    if (assemblyDefinition.HasCustomAttributes &&
                        (xamlcAttr =
                             assemblyDefinition.CustomAttributes.FirstOrDefault(
                                 ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                    {
                        var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                        if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                        {
                            skipassembly = true;
                        }
                        if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                        {
                            skipassembly = false;
                        }
                    }

                    foreach (var module in assemblyDefinition.Modules)
                    {
                        var skipmodule = skipassembly;
                        if (module.HasCustomAttributes &&
                            (xamlcAttr =
                                 module.CustomAttributes.FirstOrDefault(
                                     ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                        {
                            var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                            if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                            {
                                skipmodule = true;
                            }
                            if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                            {
                                skipmodule = false;
                            }
                        }

                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
                        var resourcesToPrune = new List <EmbeddedResource>();
                        foreach (var resource in module.Resources.OfType <EmbeddedResource>())
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
                            string classname;
                            if (!resource.IsXaml(module, out classname))
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
                                continue;
                            }
                            TypeDefinition typeDef = module.GetType(classname);
                            if (typeDef == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
                                continue;
                            }
                            var skiptype = skipmodule;
                            if (typeDef.HasCustomAttributes &&
                                (xamlcAttr =
                                     typeDef.CustomAttributes.FirstOrDefault(
                                         ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null)
                            {
                                var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                                if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                                {
                                    skiptype = true;
                                }
                                if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                                {
                                    skiptype = false;
                                }
                            }

                            if (Type != null)
                            {
                                skiptype = !(Type == classname);
                            }

                            if (skiptype && !ForceCompile)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}has XamlCompilationAttribute set to Skip and not Compile... skipped.");
                                continue;
                            }

                            var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
                            if (initComp == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
                                continue;
                            }

                            CustomAttribute xamlFilePathAttr;
                            var             xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlFilePathAttribute")) != null ?
                                                           (string)xamlFilePathAttr.ConstructorArguments[0].Value :
                                                           resource.Name;

                            MethodDefinition initCompRuntime = null;
                            if (!ValidateOnly)
                            {
                                initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
                                if (initCompRuntime != null)
                                {
                                    LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
                                }
                                else
                                {
                                    LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
                                    initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
                                    initCompRuntime.Body.InitLocals = true;
                                    LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                                    LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
                                    initCompRuntime.Body = new MethodBody(initCompRuntime);
                                    var iCRIl = initCompRuntime.Body.GetILProcessor();
                                    foreach (var instr in initComp.Body.Instructions)
                                    {
                                        iCRIl.Append(instr);
                                    }
                                    initComp.Body.Instructions.Clear();
                                    initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
                                    initComp.Body.InitLocals = true;
                                    typeDef.Methods.Add(initCompRuntime);
                                    LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                                }
                            }

                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
                            var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
                            if (rootnode == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
                                continue;
                            }
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");

                            hasCompiledXamlResources = true;

                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
                            Exception e;
                            if (!TryCoreCompile(initComp, initCompRuntime, rootnode, xamlFilePath, out e))
                            {
                                success = false;
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
                                (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                                if (e is XamlParseException xpe)
                                {
                                    LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
                                }
                                else if (e is XmlException xe)
                                {
                                    LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
                                }
                                else
                                {
                                    LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
                                }
                                LoggingHelper.LogMessage(Low, e.StackTrace);
                                continue;
                            }
                            if (Type != null)
                            {
                                InitCompForType = initComp;
                            }

                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");

                            if (ValidateOnly)
                            {
                                continue;
                            }

                            if (OptimizeIL)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
                                initComp.Body.Optimize();
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                            }

#pragma warning disable 0618
                            if (OutputGeneratedILAsCode)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated");
                            }
#pragma warning restore 0618
                            resourcesToPrune.Add(resource);
                        }
                        if (hasCompiledXamlResources)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Changing the module MVID");
                            module.Mvid = Guid.NewGuid();
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}done.");
                        }
                        if (!KeepXamlResources)
                        {
                            if (resourcesToPrune.Any())
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Removing compiled xaml resources");
                            }
                            foreach (var resource in resourcesToPrune)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Removing {resource.Name}");
                                module.Resources.Remove(resource);
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                            }
                        }
                    }
                    if (ValidateOnly)
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}ValidateOnly=True. Skipping writing assembly.");
                        return(success);
                    }
                    if (!hasCompiledXamlResources)
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}No compiled resources. Skipping writing assembly.");
                        return(success);
                    }

                    LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}Writing the assembly");
                    try {
                        assemblyDefinition.Write(new WriterParameters {
                            WriteSymbols = debug,
                        });
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}done.");
                    } catch (Exception e) {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}failed.");
                        LoggingHelper.LogErrorFromException(e);
                        (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                        LoggingHelper.LogMessage(Low, e.StackTrace);
                        success = false;
                    }
                }
            }
            return(success);
        }
Beispiel #4
0
        bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, string xamlFilePath, out Exception exception)
        {
            try
            {
                var body   = new MethodBody(initComp);
                var module = body.Method.Module;
                body.InitLocals = true;
                var il           = body.GetILProcessor();
                var resourcePath = GetPathForType(module, initComp.DeclaringType);

                il.Emit(Nop);

                var visitorContext = new ILContext(il, body, module)
                {
                    DefineDebug  = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none"),
                    XamlFilePath = xamlFilePath
                };


                rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
                rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
                rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
                rootnode.Accept(new CreateObjectVisitor(visitorContext), null);
                rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null);
                rootnode.Accept(new SetFieldVisitor(visitorContext), null);
                rootnode.Accept(new SetResourcesVisitor(visitorContext), null);
                rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null);

                il.Emit(Ret);
                initComp.Body = body;
                exception     = null;
                return(true);
            }
            catch (Exception e)
            {
                exception = e;
                return(false);
            }
        }
        public override bool Execute(out IList <Exception> thrownExceptions)
        {
            thrownExceptions = null;
            Logger           = Logger ?? new Logger(null, Verbosity);
            Logger.LogLine(1, "Preparing debug code for xamlc");
            Logger.LogLine(1, "\nAssembly: {0}", Assembly);

            var resolver = new DefaultAssemblyResolver();

            if (!string.IsNullOrEmpty(DependencyPaths))
            {
                foreach (var dep in DependencyPaths.Split(';'))
                {
                    Logger.LogLine(3, "Adding searchpath {0}", dep);
                    resolver.AddSearchDirectory(dep);
                }
            }
            if (!string.IsNullOrEmpty(ReferencePath))
            {
                var paths = ReferencePath.Replace("//", "/").Split(';');
                foreach (var p in paths)
                {
                    var searchpath = Path.GetDirectoryName(p);
                    Logger.LogLine(3, "Adding searchpath {0}", searchpath);
                    resolver.AddSearchDirectory(searchpath);
                    //					LogLine (3, "Referencing {0}", p);
                    //					resolver.AddAssembly (p);
                }
            }

            var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");

            using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly, new ReaderParameters {
                ReadWrite = true,
                ReadSymbols = debug,
                AssemblyResolver = resolver
            })) {
                foreach (var module in assemblyDefinition.Modules)
                {
                    Logger.LogLine(2, " Module: {0}", module.Name);
                    foreach (var resource in module.Resources.OfType <EmbeddedResource>())
                    {
                        Logger.LogString(2, "  Resource: {0}... ", resource.Name);
                        string classname;
                        if (!resource.IsXaml(module, out classname))
                        {
                            Logger.LogLine(2, "skipped.");
                            continue;
                        }
                        else
                        {
                            Logger.LogLine(2, "");
                        }
                        TypeDefinition typeDef = module.GetType(classname);
                        if (typeDef == null)
                        {
                            Logger.LogLine(2, "no type found... skipped.");
                            continue;
                        }

                        var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
                        if (initComp == null)
                        {
                            Logger.LogLine(2, "no InitializeComponent found... skipped.");
                            continue;
                        }
                        var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
                        if (initCompRuntime == null)
                        {
                            Logger.LogString(2, "   Creating empty {0}.__InitComponentRuntime ...", typeDef.Name);
                            initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
                            initCompRuntime.Body.InitLocals = true;
                            Logger.LogLine(2, "done.");
                            Logger.LogString(2, "   Copying body of InitializeComponent to __InitComponentRuntime ...", typeDef.Name);
                            initCompRuntime.Body = new MethodBody(initCompRuntime);
                            var iCRIl = initCompRuntime.Body.GetILProcessor();
                            foreach (var instr in initComp.Body.Instructions)
                            {
                                iCRIl.Append(instr);
                            }
                            initComp.Body.Instructions.Clear();
                            initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
                            typeDef.Methods.Add(initCompRuntime);
                            Logger.LogLine(2, "done.");
                        }

//						IL_0000:  ldarg.0
//						IL_0001:  callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ContentPage::'.ctor'()
//
//						IL_0006:  nop
//						IL_0007:  ldarg.1
//						IL_0008:  brfalse IL_0018
//
//						IL_000d:  ldarg.0
//						IL_000e:  callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitializeComponent()
//						IL_0013:  br IL_001e
//
//						IL_0018:  ldarg.0
//						IL_0019:  callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::__InitComponentRuntime()
//						IL_001e:  ret

                        var altCtor =
                            typeDef.Methods.Where(
                                md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType == module.TypeSystem.Boolean)
                            .FirstOrDefault();
                        if (altCtor != null)
                        {
                            Logger.LogString(2, "   Replacing body of {0}.{0} (bool {1}) ... ", typeDef.Name, altCtor.Parameters[0].Name);
                        }
                        else
                        {
                            Logger.LogString(2, "   Adding {0}.{0} (bool useCompiledXaml) ... ", typeDef.Name);
                            altCtor = new MethodDefinition(".ctor",
                                                           MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
                                                           MethodAttributes.RTSpecialName, module.TypeSystem.Void);
                            altCtor.Parameters.Add(new ParameterDefinition("useCompiledXaml", ParameterAttributes.None,
                                                                           module.TypeSystem.Boolean));
                        }

                        var body = new MethodBody(altCtor);
                        body.InitLocals = true;
                        var il  = body.GetILProcessor();
                        var br2 = Instruction.Create(OpCodes.Ldarg_0);
                        var ret = Instruction.Create(OpCodes.Ret);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt,
                                module.ImportReference(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false)));

                        il.Emit(OpCodes.Nop);
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Brfalse, br2);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, initComp);
                        il.Emit(OpCodes.Br, ret);

                        il.Append(br2);
                        il.Emit(OpCodes.Callvirt, initCompRuntime);
                        il.Append(ret);

                        altCtor.Body = body;
                        if (!typeDef.Methods.Contains(altCtor))
                        {
                            typeDef.Methods.Add(altCtor);
                        }
                        Logger.LogLine(2, "done.");
                    }

                    Logger.LogLine(2, "");
                }
                Logger.LogString(1, "Writing the assembly... ");
                assemblyDefinition.Write(new WriterParameters {
                    WriteSymbols = debug
                });
            }
            Logger.LogLine(1, "done.");

            return(true);
        }
Beispiel #6
0
        public override bool Execute(out IList <Exception> thrownExceptions)
        {
            thrownExceptions = null;
            LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Compiling Xaml, assembly: {Assembly}");
            var  skipassembly = !DefaultCompile;
            bool success      = true;

            if (!File.Exists(Assembly))
            {
                LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}Assembly file not found. Skipping XamlC.");
                return(true);
            }

            using (var fallbackResolver = DefaultAssemblyResolver == null ? new XamlCAssemblyResolver() : null)
            {
                var resolver = DefaultAssemblyResolver ?? fallbackResolver;
                if (resolver is XamlCAssemblyResolver xamlCResolver)
                {
                    if (ReferencePath != null)
                    {
                        var paths = ReferencePath.Select(p => IOPath.GetDirectoryName(p.Replace("//", "/"))).Distinct();
                        foreach (var searchpath in paths)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
                            xamlCResolver.AddSearchDirectory(searchpath);
                        }
                    }
                }
                else
                {
                    LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Ignoring dependency and reference paths due to an unsupported resolver");
                }

                var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");

                var readerParameters = new ReaderParameters
                {
                    AssemblyResolver = resolver,
                    ReadWrite        = !ValidateOnly,
                    ReadSymbols      = debug && !ValidateOnly,                // We don't need symbols for ValidateOnly, since we won't be writing
                };

                using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(IOPath.GetFullPath(Assembly), readerParameters))
                {
                    CustomAttribute xamlcAttr;
                    if (assemblyDefinition.HasCustomAttributes &&
                        (xamlcAttr =
                             assemblyDefinition.CustomAttributes.FirstOrDefault(
                                 ca => ca.AttributeType.FullName == "Microsoft.Maui.Controls.Xaml.XamlCompilationAttribute")) != null)
                    {
                        var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                        if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                        {
                            skipassembly = true;
                        }
                        if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                        {
                            skipassembly = false;
                        }
                    }

                    foreach (var module in assemblyDefinition.Modules)
                    {
                        var skipmodule = skipassembly;
                        if (module.HasCustomAttributes &&
                            (xamlcAttr =
                                 module.CustomAttributes.FirstOrDefault(
                                     ca => ca.AttributeType.FullName == "Microsoft.Maui.Controls.Xaml.XamlCompilationAttribute")) != null)
                        {
                            var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                            if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                            {
                                skipmodule = true;
                            }
                            if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                            {
                                skipmodule = false;
                            }
                        }

                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
                        var resourcesToPrune = new List <EmbeddedResource>();
                        foreach (var resource in module.Resources.OfType <EmbeddedResource>())
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
                            string classname;
                            if (!resource.IsXaml(module, out classname))
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
                                continue;
                            }
                            TypeDefinition typeDef = module.GetType(classname);
                            if (typeDef == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
                                continue;
                            }
                            var skiptype = skipmodule;
                            if (typeDef.HasCustomAttributes &&
                                (xamlcAttr =
                                     typeDef.CustomAttributes.FirstOrDefault(
                                         ca => ca.AttributeType.FullName == "Microsoft.Maui.Controls.Xaml.XamlCompilationAttribute")) != null)
                            {
                                var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
                                if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
                                {
                                    skiptype = true;
                                }
                                if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
                                {
                                    skiptype = false;
                                }
                            }

                            if (Type != null)
                            {
                                skiptype = !(Type == classname);
                            }

                            if (skiptype && !ForceCompile)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}has XamlCompilationAttribute set to Skip and not Compile... skipped.");
                                continue;
                            }

                            var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
                            if (initComp == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
                                continue;
                            }

                            CustomAttribute xamlFilePathAttr;
                            var             xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Microsoft.Maui.Controls.Xaml.XamlFilePathAttribute")) != null ?
                                                           (string)xamlFilePathAttr.ConstructorArguments[0].Value :
                                                           resource.Name;


                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
                            var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
                            if (rootnode == null)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
                                continue;
                            }
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");

                            hasCompiledXamlResources = true;

                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
                            Exception e;
                            if (!TryCoreCompile(initComp, rootnode, xamlFilePath, LoggingHelper, out e))
                            {
                                success = false;
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
                                (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                                if (e is BuildException be)
                                {
                                    LoggingHelper.LogError("XamlC", be.Code.Code, be.HelpLink, xamlFilePath, be.XmlInfo?.LineNumber ?? 0, be.XmlInfo?.LinePosition ?? 0, 0, 0, ErrorMessages.ResourceManager.GetString(be.Code.ErrorMessageKey), be.MessageArgs);
                                }
                                else if (e is XamlParseException xpe)                                 //shouldn't happen anymore
                                {
                                    LoggingHelper.LogError("XamlC", null, xpe.HelpLink, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message);
                                }
                                else if (e is XmlException xe)
                                {
                                    LoggingHelper.LogError("XamlC", null, xe.HelpLink, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message);
                                }
                                else
                                {
                                    LoggingHelper.LogError("XamlC", null, e.HelpLink, xamlFilePath, 0, 0, 0, 0, e.Message);
                                }
                                LoggingHelper.LogMessage(Low, e.StackTrace);
                                continue;
                            }
                            if (Type != null)
                            {
                                InitCompForType = initComp;
                            }

                            LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");

                            if (ValidateOnly)
                            {
                                continue;
                            }

                            if (OptimizeIL)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
                                initComp.Body.Optimize();
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                            }
                            resourcesToPrune.Add(resource);
                        }
                        if (hasCompiledXamlResources)
                        {
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Changing the module MVID");
                            module.Mvid = Guid.NewGuid();
                            LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}done.");
                        }
                        if (!KeepXamlResources)
                        {
                            if (resourcesToPrune.Any())
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Removing compiled xaml resources");
                            }
                            foreach (var resource in resourcesToPrune)
                            {
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Removing {resource.Name}");
                                module.Resources.Remove(resource);
                                LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
                            }
                        }
                    }
                    if (ValidateOnly)
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}ValidateOnly=True. Skipping writing assembly.");
                        return(success);
                    }
                    if (!hasCompiledXamlResources)
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}No compiled resources. Skipping writing assembly.");
                        return(success);
                    }

                    LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}Writing the assembly");
                    try
                    {
                        assemblyDefinition.Write(new WriterParameters
                        {
                            WriteSymbols = debug,
                        });
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}done.");
                    }
                    catch (Exception e)
                    {
                        LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}failed.");
                        LoggingHelper.LogErrorFromException(e);
                        (thrownExceptions = thrownExceptions ?? new List <Exception>()).Add(e);
                        LoggingHelper.LogMessage(Low, e.StackTrace);
                        success = false;
                    }
                }
            }
            return(success);
        }