diff --git a/build-tools/xaprepare/xaprepare/Application/Utilities.cs b/build-tools/xaprepare/xaprepare/Application/Utilities.cs index eb2a9393525..e594209db44 100644 --- a/build-tools/xaprepare/xaprepare/Application/Utilities.cs +++ b/build-tools/xaprepare/xaprepare/Application/Utilities.cs @@ -867,154 +867,7 @@ void LogError (string message) public static string GetRelativePath (string relativeTo, string path) { - return GetRelativePath (relativeTo, path, Context.Instance.OS.DefaultStringComparison); + return Xamarin.Android.Tools.PathUtil.GetRelativePath (relativeTo, path, Context.Instance.OS.DefaultStringComparison); } - - // Adapted from CoreFX sources - public static string GetRelativePath (string relativeTo, string path, StringComparison comparisonType) - { - if (String.IsNullOrEmpty (relativeTo)) - throw new ArgumentException ("must not be null or empty", nameof (relativeTo)); - - if (String.IsNullOrEmpty (path)) - throw new ArgumentException ("must not be null or empty", nameof (path)); - - relativeTo = Path.GetFullPath (relativeTo); - path = Path.GetFullPath (path); - - // Need to check if the roots are different- if they are we need to return the "to" path. - if (!AreRootsEqual (relativeTo, path, comparisonType)) - return path; - - int commonLength = GetCommonPathLength (relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase); - - // If there is nothing in common they can't share the same root, return the "to" path as is. - if (commonLength == 0) - return path; - - // Trailing separators aren't significant for comparison - int relativeToLength = relativeTo.Length; - if (EndsInDirectorySeparator (relativeTo)) - relativeToLength--; - - bool pathEndsInSeparator = EndsInDirectorySeparator (path); - int pathLength = path.Length; - if (pathEndsInSeparator) - pathLength--; - - // If we have effectively the same path, return "." - if (relativeToLength == pathLength && commonLength >= relativeToLength) - return "."; - - // We have the same root, we need to calculate the difference now using the - // common Length and Segment count past the length. - // - // Some examples: - // - // C:\Foo C:\Bar L3, S1 -> ..\Bar - // C:\Foo C:\Foo\Bar L6, S0 -> Bar - // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar - // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar - - var sb = new StringBuilder (Math.Max (relativeTo.Length, path.Length)); - - // Add parent segments for segments past the common on the "from" path - if (commonLength < relativeToLength) { - sb.Append (".."); - - for (int i = commonLength + 1; i < relativeToLength; i++) { - if (IsDirectorySeparator (relativeTo[i])) { - sb.Append (Path.DirectorySeparatorChar); - sb.Append (".."); - } - } - } else if (IsDirectorySeparator (path[commonLength])) { - // No parent segments and we need to eat the initial separator - // (C:\Foo C:\Foo\Bar case) - commonLength++; - } - - // Now add the rest of the "to" path, adding back the trailing separator - int differenceLength = pathLength - commonLength; - if (pathEndsInSeparator) - differenceLength++; - - if (differenceLength > 0) { - if (sb.Length > 0) { - sb.Append (Path.DirectorySeparatorChar); - } - - sb.Append(path, commonLength, differenceLength); - } - - return sb.ToString (); - } - - // Adapted from CoreFX sources - static bool AreRootsEqual (string first, string second, StringComparison comparisonType) - { - int firstRootLength = GetRootLength (first); - int secondRootLength = GetRootLength (second); - - return firstRootLength == secondRootLength - && String.Compare ( - strA: first, - indexA: 0, - strB: second, - indexB: 0, - length: firstRootLength, - comparisonType: comparisonType) == 0; - } - - // Adapted from CoreFX sources - static int GetCommonPathLength (string first, string second, bool ignoreCase) - { - int commonChars = EqualStartingCharacterCount (first, second, ignoreCase: ignoreCase); - - // If nothing matches - if (commonChars == 0) - return commonChars; - - // Or we're a full string and equal length or match to a separator - if (commonChars == first.Length && (commonChars == second.Length || IsDirectorySeparator (second[commonChars]))) - return commonChars; - - if (commonChars == second.Length && IsDirectorySeparator (first[commonChars])) - return commonChars; - - // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar. - while (commonChars > 0 && !IsDirectorySeparator (first[commonChars - 1])) - commonChars--; - - return commonChars; - } - - // Adapted from CoreFX sources - static unsafe int EqualStartingCharacterCount (string first, string second, bool ignoreCase) - { - if (String.IsNullOrEmpty (first) || string.IsNullOrEmpty (second)) - return 0; - - int commonChars = 0; - fixed (char* f = first) { - fixed (char* s = second) { - char* l = f; - char* r = s; - char* leftEnd = l + first.Length; - char* rightEnd = r + second.Length; - - while (l != leftEnd && r != rightEnd && (*l == *r || (ignoreCase && char.ToUpperInvariant ((*l)) == char.ToUpperInvariant ((*r))))) { - commonChars++; - l++; - r++; - } - } - } - - return commonChars; - } - - // Adapted from CoreFX sources - static bool EndsInDirectorySeparator (string path) => path.Length > 0 && IsDirectorySeparator (path[path.Length - 1]); } } diff --git a/build-tools/xaprepare/xaprepare/xaprepare.csproj b/build-tools/xaprepare/xaprepare/xaprepare.csproj index 2d5dc260e70..6730c7adae9 100644 --- a/build-tools/xaprepare/xaprepare/xaprepare.csproj +++ b/build-tools/xaprepare/xaprepare/xaprepare.csproj @@ -44,6 +44,10 @@ + + + + diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets index fd0674e9946..7b6191bf61e 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets @@ -41,6 +41,19 @@ It is shared between "legacy" binding projects and .NET 5 projects. + + + <_GeneratedManagedBindingFiles Include="$(GeneratedOutputPath)**\*.cs" /> + + + + + + + @@ -107,14 +120,23 @@ It is shared between "legacy" binding projects and .NET 5 projects. + + + + + + Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' Or '@(_GeneratedManagedBindingFiles->Count())' != '0' " + DependsOnTargets="GenerateBindings;_CollectGeneratedManagedBindingFiles"> + + + true + - + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets index 24d8d93c9c4..346c89aa99b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets @@ -118,6 +118,7 @@ properties that determine build ordering. _BuildResourceDesigner; UpdateAndroidInterfaceProxies; _SetAndroidGenerateManagedBindings; + _ClearGeneratedManagedBindings; AddBindingsToCompile; _CheckForInvalidDesignerConfig; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs index fd9c73a4298..b404d91156e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.BindingGenerator.cs @@ -127,6 +127,8 @@ public State BeginPartialClassFile (StreamWriter writer, string bindingClassName return state; } + public abstract void SetCodeBehindDir (string path); + protected abstract void BeginPartialClassFile (State state, string classNamespace, string className); public abstract void EndPartialClassFile (State state); public abstract void WritePartialClassProperty (State state, LayoutWidget widget); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs index c5dc083427d..bc2b9ff6db4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.CSharpBindingGenerator.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.Linq; +using Xamarin.Android.Tasks.LLVMIR; +using Xamarin.Android.Tools; namespace Xamarin.Android.Tasks { @@ -10,6 +12,7 @@ sealed class CSharpBindingGenerator : BindingGenerator { const string BindingPartialClassBackingFieldName = "__layout_binding"; + string codebehindDir = string.Empty; protected override string LineCommentString => "//"; protected override string DocCommentString => "///"; public override string LanguageName => "C#"; @@ -28,6 +31,11 @@ protected override void BeginPartialClassFile (State state, string classNamespac state.WriteLine (); } + public override void SetCodeBehindDir(string path) + { + codebehindDir = Path.GetFullPath (path); + } + public override void EndPartialClassFile (State state) { EndBindingFile (state); // currently they're identical @@ -239,7 +247,8 @@ protected override void WriteLocationDirective (State state, LayoutWidget widget if (loc == null) return; - WriteLineIndent (state, $"#line {loc.Line} \"{loc.FilePath}\""); + var relativePath = PathUtil.GetRelativePath (codebehindDir, Path.GetFullPath (loc.FilePath)); + WriteLineIndent (state, $"#line {loc.Line} \"{relativePath}\""); state.WriteLine (); } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs index 161fc7e374c..1c721326b42 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs @@ -107,6 +107,8 @@ public async override System.Threading.Tasks.Task RunTaskAsync () return; } + generator.SetCodeBehindDir (MonoAndroidCodeBehindDir); + LogDebugMessage ($"Generating {generator.LanguageName} binding sources"); var layoutGroups = new Dictionary (StringComparer.Ordinal); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index c653639bfd0..99e9a963422 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -1247,9 +1247,9 @@ protected override void OnCreate (Bundle bundle) proj.SetProperty ("AndroidGenerateLayoutBindings", "True"); using (var builder = CreateApkBuilder (path)) { Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); - FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "generated", "Binding.Main.g.cs")); + FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "codebehind", "Binding.Main.g.cs")); Assert.IsTrue (builder.Build (proj), "Second build should have succeeded."); - FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "generated", "Binding.Main.g.cs")); + FileAssert.Exists (Path.Combine (Root, path, proj.IntermediateOutputPath, "codebehind", "Binding.Main.g.cs")); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs index 70e42e8c71f..7fb2f61bfd7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs @@ -534,6 +534,8 @@ public void AppWithSingleJar () var builder = CreateApkBuilder (); Assert.IsTrue (builder.Build (proj), "first build should succeed"); + Assert.IsTrue (builder.DesignTimeBuild (proj), "Design time build should succeed."); + Assert.IsFalse (builder.Output.IsTargetSkipped ("AddBindingsToCompile"), "AddBindingsToCompile should run."); var assemblyPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs index a64a11f7bce..6c87875bfa0 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs @@ -124,7 +124,7 @@ public TestProjectInfo (string projectName, string testName, string rootDirector ProjectName = projectName; ObjPath = Path.Combine (rootDirectory, "obj"); - GeneratedPath = Path.Combine (ObjPath, XABuildPaths.Configuration, "generated"); + GeneratedPath = Path.Combine (ObjPath, XABuildPaths.Configuration, "codebehind"); BinPath = Path.Combine (rootDirectory, "bin", XABuildPaths.Configuration); ProjectPath = Path.Combine (rootDirectory, $"{projectName}.csproj"); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs b/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs new file mode 100644 index 00000000000..5156ca8aa9a --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/PathUtil.cs @@ -0,0 +1,289 @@ +using System; +using System.IO; +using System.Text; +using System.Runtime.InteropServices; + +namespace Xamarin.Android.Tools +{ + public static class PathUtil + { + + const int DevicePrefixLength = 4; + const int UncPrefixLength = 2; + const int UncExtendedPrefixLength = 8; + + internal const char VolumeSeparatorChar = ':'; + + static bool IsWindows = Path.DirectorySeparatorChar == '\\'; + // Adapted from CoreFX sources + public static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase) + { + if (String.IsNullOrEmpty(relativeTo)) + throw new ArgumentException("must not be null or empty", nameof(relativeTo)); + + if (String.IsNullOrEmpty(path)) + throw new ArgumentException("must not be null or empty", nameof(path)); + + relativeTo = Path.GetFullPath(relativeTo); + path = Path.GetFullPath(path); + + // Need to check if the roots are different- if they are we need to return the "to" path. + if (!AreRootsEqual(relativeTo, path, comparisonType)) + return path; + + int commonLength = GetCommonPathLength(relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase); + + // If there is nothing in common they can't share the same root, return the "to" path as is. + if (commonLength == 0) + return path; + + // Trailing separators aren't significant for comparison + int relativeToLength = relativeTo.Length; + if (EndsInDirectorySeparator(relativeTo)) + relativeToLength--; + + bool pathEndsInSeparator = EndsInDirectorySeparator(path); + int pathLength = path.Length; + if (pathEndsInSeparator) + pathLength--; + + // If we have effectively the same path, return "." + if (relativeToLength == pathLength && commonLength >= relativeToLength) + return "."; + + // We have the same root, we need to calculate the difference now using the + // common Length and Segment count past the length. + // + // Some examples: + // + // C:\Foo C:\Bar L3, S1 -> ..\Bar + // C:\Foo C:\Foo\Bar L6, S0 -> Bar + // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar + // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar + + var sb = new StringBuilder(Math.Max(relativeTo.Length, path.Length)); + + // Add parent segments for segments past the common on the "from" path + if (commonLength < relativeToLength) + { + sb.Append(".."); + + for (int i = commonLength + 1; i < relativeToLength; i++) + { + if (IsDirectorySeparator(relativeTo[i])) + { + sb.Append(Path.DirectorySeparatorChar); + sb.Append(".."); + } + } + } + else if (IsDirectorySeparator(path[commonLength])) + { + // No parent segments and we need to eat the initial separator + // (C:\Foo C:\Foo\Bar case) + commonLength++; + } + + // Now add the rest of the "to" path, adding back the trailing separator + int differenceLength = pathLength - commonLength; + if (pathEndsInSeparator) + differenceLength++; + + if (differenceLength > 0) + { + if (sb.Length > 0) + { + sb.Append(Path.DirectorySeparatorChar); + } + + sb.Append(path, commonLength, differenceLength); + } + + return sb.ToString(); + } + + // Adapted from CoreFX sources + static bool AreRootsEqual(string first, string second, StringComparison comparisonType) + { + int firstRootLength = GetRootLength(first); + int secondRootLength = GetRootLength(second); + + return firstRootLength == secondRootLength + && String.Compare( + strA: first, + indexA: 0, + strB: second, + indexB: 0, + length: firstRootLength, + comparisonType: comparisonType) == 0; + } + + // Adapted from CoreFX sources + static int GetCommonPathLength(string first, string second, bool ignoreCase) + { + int commonChars = EqualStartingCharacterCount(first, second, ignoreCase: ignoreCase); + + // If nothing matches + if (commonChars == 0) + return commonChars; + + // Or we're a full string and equal length or match to a separator + if (commonChars == first.Length && (commonChars == second.Length || IsDirectorySeparator(second[commonChars]))) + return commonChars; + + if (commonChars == second.Length && IsDirectorySeparator(first[commonChars])) + return commonChars; + + // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar. + while (commonChars > 0 && !IsDirectorySeparator(first[commonChars - 1])) + commonChars--; + + return commonChars; + } + + // Adapted from CoreFX sources + static unsafe int EqualStartingCharacterCount(string first, string second, bool ignoreCase) + { + if (String.IsNullOrEmpty(first) || string.IsNullOrEmpty(second)) + return 0; + + int commonChars = 0; + fixed (char* f = first) + { + fixed (char* s = second) + { + char* l = f; + char* r = s; + char* leftEnd = l + first.Length; + char* rightEnd = r + second.Length; + + while (l != leftEnd && r != rightEnd && (*l == *r || (ignoreCase && char.ToUpperInvariant((*l)) == char.ToUpperInvariant((*r))))) + { + commonChars++; + l++; + r++; + } + } + } + + return commonChars; + } + + // Adapted from CoreFX sources + static bool EndsInDirectorySeparator(string path) => path.Length > 0 && IsDirectorySeparator(path[path.Length - 1]); + + static bool IsDirectorySeparator(char c) + { + if (!IsWindows) + return c == Path.DirectorySeparatorChar; + return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar; + } + + // Adapted from CoreFX sources + static int GetRootLength(string path) + { + if (!IsWindows) + return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0; + return GetRootLength_ForWindows(path); + } + + internal static bool IsValidDriveChar(char value) + { + return ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z')); + } + + // Adapted from CoreFX sources + static bool IsExtended(string path) + { + // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths. + // Skipping of normalization will *only* occur if back slashes ('\') are used. + return path.Length >= DevicePrefixLength + && path[0] == '\\' + && (path[1] == '\\' || path[1] == '?') + && path[2] == '?' + && path[3] == '\\'; + } + + // Adapted from CoreFX sources + static bool IsDevice(string path) + { + // If the path begins with any two separators is will be recognized and normalized and prepped with + // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not. + return IsExtended(path) || + ( + path.Length >= DevicePrefixLength + && IsDirectorySeparator(path[0]) + && IsDirectorySeparator(path[1]) + && (path[2] == '.' || path[2] == '?') + && IsDirectorySeparator(path[3]) + ); + } + + // Adapted from CoreFX sources + static bool IsDeviceUNC(string path) + { + return path.Length >= UncExtendedPrefixLength + && IsDevice(path) + && IsDirectorySeparator(path[7]) + && path[4] == 'U' + && path[5] == 'N' + && path[6] == 'C'; + } + + // Adapted from CoreFX sources + static int GetRootLength_ForWindows(string path) + { + int pathLength = path.Length; + int i = 0; + + bool deviceSyntax = IsDevice(path); + bool deviceUnc = deviceSyntax && IsDeviceUNC(path); + + if ((!deviceSyntax || deviceUnc) && pathLength > 0 && IsDirectorySeparator(path[0])) + { + // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo") + if (deviceUnc || (pathLength > 1 && IsDirectorySeparator(path[1]))) + { + // UNC (\\?\UNC\ or \\), scan past server\share + + // Start past the prefix ("\\" or "\\?\UNC\") + i = deviceUnc ? UncExtendedPrefixLength : UncPrefixLength; + + // Skip two separators at most + int n = 2; + while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) + i++; + } + else + { + // Current drive rooted (e.g. "\foo") + i = 1; + } + } + else if (deviceSyntax) + { + // Device path (e.g. "\\?\.", "\\.\") + // Skip any characters following the prefix that aren't a separator + i = DevicePrefixLength; + while (i < pathLength && !IsDirectorySeparator(path[i])) + i++; + + // If there is another separator take it, as long as we have had at least one + // non-separator after the prefix (e.g. don't take "\\?\\", but take "\\?\a\") + if (i < pathLength && i > DevicePrefixLength && IsDirectorySeparator(path[i])) + i++; + } + else if (pathLength >= 2 && path[1] == VolumeSeparatorChar && IsValidDriveChar(path[0])) + { + // Valid drive specified path ("C:", "D:", etc.) + i = 2; + + // If the colon is followed by a directory separator, move past it (e.g "C:\") + if (pathLength > 2 && IsDirectorySeparator(path[2])) + i++; + } + + return i; + } + } +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 71e64a76db7..b639a9dd4ba 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -917,7 +917,7 @@ because xbuild doesn't support framework reference assemblies. Resources $(IntermediateOutputPath) - $(IntermediateOutputPath)generated + $(IntermediateOutputPath)codebehind $(IntermediateOutputPath)resourcecache <_AndroidIntermediateJavaSourceDirectory>$(IntermediateOutputPath)android\src\ <_AndroidIntermediateDexOutputDirectory>$(IntermediateOutputPath)android\bin\ @@ -2550,6 +2550,8 @@ because xbuild doesn't support framework reference assemblies. + +