diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index f98b1fe4f4..51cb04a3a1 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -37,14 +37,14 @@
EmbeddedResources="@(EmbeddedResources)"/>
+ Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:BuildProjectReferences=false"/>
@@ -61,10 +61,11 @@
AssemblyFile="@(IntermediateAssembly)"
ReferencesFilePath="$(AvaloniaXamlReferencesTemporaryFilePath)"
OriginalCopyPath="$(AvaloniaXamlOriginalCopyFilePath)"
+ ProjectDirectory="$(MSBuildProjectDirectory)"
/>
+ Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:BuildProjectReferences=false"/>
diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml
index fea55bcb07..8534c022f8 100644
--- a/samples/ControlCatalog/SideBar.xaml
+++ b/samples/ControlCatalog/SideBar.xaml
@@ -1,6 +1,6 @@
+>
diff --git a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
index 028643f7c0..54db830f2f 100644
--- a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
+++ b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
@@ -21,12 +21,15 @@ namespace Avalonia.Build.Tasks
File.Delete(AssemblyFile);
}
- var data = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
- File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray());
- if(data == null)
+ var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
+ File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
+ ProjectDirectory);
+ if (!res.Success)
+ return false;
+ if (res.Data == null)
File.Copy(input, OutputPath);
else
- File.WriteAllBytes(OutputPath, data);
+ File.WriteAllBytes(OutputPath, res.Data);
return true;
}
@@ -39,6 +42,8 @@ namespace Avalonia.Build.Tasks
public string ReferencesFilePath { get; set; }
[Required]
public string OriginalCopyPath { get; set; }
+ [Required]
+ public string ProjectDirectory { get; set; }
public string OutputPath { get; set; }
diff --git a/src/Avalonia.Build.Tasks/Program.cs b/src/Avalonia.Build.Tasks/Program.cs
index 2f206acf2a..c2d0950264 100644
--- a/src/Avalonia.Build.Tasks/Program.cs
+++ b/src/Avalonia.Build.Tasks/Program.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections;
+using System.IO;
using Microsoft.Build.Framework;
namespace Avalonia.Build.Tasks
@@ -19,7 +20,8 @@ namespace Avalonia.Build.Tasks
AssemblyFile = args[0],
ReferencesFilePath = args[1],
OutputPath = args[2],
- BuildEngine = new ConsoleBuildEngine()
+ BuildEngine = new ConsoleBuildEngine(),
+ ProjectDirectory = Directory.GetCurrentDirectory()
}.Execute() ?
0 :
2;
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index acaa80b608..5addf939eb 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -10,6 +10,8 @@ using Mono.Cecil;
using XamlIl.TypeSystem;
using Avalonia.Utilities;
using Mono.Cecil.Rocks;
+using XamlIl;
+using XamlIl.Ast;
using XamlIl.Parsers;
using XamlIl.Transform;
using TypeAttributes = Mono.Cecil.TypeAttributes;
@@ -47,7 +49,19 @@ namespace Avalonia.Build.Tasks
return rv;
}
- public static byte[] Compile(IBuildEngine engine, string input, string[] references)
+ public class CompileResult
+ {
+ public bool Success { get; set; }
+ public byte[] Data { get; set; }
+
+ public CompileResult(bool success, byte[] data = null)
+ {
+ Success = success;
+ Data = data;
+ }
+ }
+
+ public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory)
{
var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input);
var asm = typeSystem.TargetAssemblyDefinition;
@@ -55,7 +69,7 @@ namespace Avalonia.Build.Tasks
var avares = ReadAvaloniaXamlResources(asm);
if (avares.Count == 0 && emres.Count == 0)
// Nothing to do
- return null;
+ return new CompileResult(true);
var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem);
var compilerConfig = new XamlIlTransformerConfiguration(typeSystem,
typeSystem.TargetAssembly,
@@ -80,7 +94,8 @@ namespace Avalonia.Build.Tasks
asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors()
.First(c => c.Parameters.Count == 1));
- void CompileGroup(Dictionary resources, string name, Func uriTransform)
+ bool CompileGroup(Dictionary resources, string name, Func uriTransform,
+ Func pathTransform)
{
var typeDef = new TypeDefinition("CompiledAvaloniaXaml", name,
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
@@ -94,23 +109,63 @@ namespace Avalonia.Build.Tasks
var builder = typeSystem.CreateTypeBuilder(typeDef);
foreach (var res in resources)
{
- var xaml = Encoding.UTF8.GetString(res.Value);
- var parsed = XDocumentXamlIlParser.Parse(xaml);
- compiler.Transform(parsed);
- compiler.Compile(parsed, builder, contextClass,
- "Populate:" + res.Key, "Build:" + res.Key,
- "NamespaceInfo:" + res.Key, uriTransform(res.Key));
+ try
+ {
+ // StreamReader is needed here to handle BOM
+ var xaml = new StreamReader(new MemoryStream(res.Value)).ReadToEnd();
+ var parsed = XDocumentXamlIlParser.Parse(xaml);
+
+ var initialRoot = (XamlIlAstObjectNode)parsed.Root;
+ var classDirective = initialRoot.Children.OfType()
+ .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
+
+ if (classDirective != null)
+ {
+ if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlIlAstTextNode tn))
+ throw new XamlIlParseException("x:Class should have a string value", classDirective);
+ var classType = typeSystem.TargetAssembly.FindType(tn.Text);
+ if (classType == null)
+ throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective);
+ initialRoot.Type = new XamlIlAstClrTypeReference(classDirective, classType);
+ }
+
+
+ compiler.Transform(parsed);
+ compiler.Compile(parsed, builder, contextClass,
+ "Populate:" + res.Key, "Build:" + res.Key,
+ "NamespaceInfo:" + res.Key, uriTransform(res.Key));
+ }
+ catch (Exception e)
+ {
+ int lineNumber = 0, linePosition = 0;
+ if (e is XamlIlParseException xe)
+ {
+ lineNumber = xe.Line;
+ linePosition = xe.Position;
+ }
+ engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", pathTransform(res.Key),
+ lineNumber, linePosition, lineNumber, linePosition,
+ e.Message, "", "Avalonia"));
+ return false;
+ }
}
+
+ return true;
}
if (emres.Count != 0)
- CompileGroup(emres, "EmbeddedResource", name => $"resm:{name}?assembly={asm.Name}");
+ if (!CompileGroup(emres, "EmbeddedResource",
+ name => $"resm:{name}?assembly={asm.Name}", name => name))
+ return new CompileResult(false);
if (avares.Count != 0)
- CompileGroup(avares, "AvaloniaResource", name => $"avares://{asm.Name}/{name}");
+ if (!CompileGroup(avares, "AvaloniaResource",
+ name => $"avares://{asm.Name}/{name}",
+ name => Path.Combine(projectDirectory, name.TrimStart('/'))))
+ return new CompileResult(false);
var ms = new MemoryStream();
asm.Write(ms);
- return ms.ToArray();
+ return new CompileResult(true, ms.ToArray());
}
}
diff --git a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
index 045cc49142..ea53f308ab 100644
--- a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
+++ b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
@@ -1,7 +1,6 @@
netstandard2.0
- true
diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
index ddc2490b8f..570fa4d67e 160000
--- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
+++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
@@ -1 +1 @@
-Subproject commit ddc2490b8f0437c42c9bc4662b25c2f693255278
+Subproject commit 570fa4d67ed0da7fc5b6e36c3100f0ccbba5aa5a