diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets index e0f1240f3d1..e311d457ce9 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets @@ -31,7 +31,9 @@ This file is only used by binding projects. OutputFile="$(ApiOutputFile).class-parse" SourceJars="@(EmbeddedJar);@(InputJar)" DocumentationPaths="@(_AndroidDocumentationPath)" + NetCoreRoot="$(NetCoreRoot)" ToolPath="$(MonoAndroidToolsDirectory)" + ToolExe="$(ClassParseToolExe)" /> $(IntermediateOutputPath)generated\ intellisense $(IntermediateOutputPath)api.xml + class-parse.dll + class-parse.exe + generator.dll + generator.exe + javadoc-to-mdoc.dll + javadoc-to-mdoc.exe <_GeneratorStampFile>$(_AndroidStampDirectory)generator.stamp @@ -73,6 +79,7 @@ It is shared between "legacy" binding projects and .NET 5 projects. ReferencedManagedLibraries="@(ReferencePath);@(ReferenceDependencyPaths)" MonoAndroidFrameworkDirectories="$(_XATargetFrameworkDirectories)" TypeMappingReportFile="$(GeneratedOutputPath)type-mapping.txt" + NetCoreRoot="$(NetCoreRoot)" ToolPath="$(MonoAndroidToolsDirectory)" ToolExe="$(BindingsGeneratorToolExe)" LangVersion="$(LangVersion)" diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Documentation.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Documentation.targets index d5a268134a7..785bb580b29 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Documentation.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Documentation.targets @@ -64,7 +64,9 @@ This file is only used by binding projects. .NET 5 can eventually use it, once ` /> public abstract class AndroidDotnetToolTask : AndroidToolTask { + /// + /// Path to the folder that contains dotnet / dotnet.exe. + /// + public string NetCoreRoot { get; set; } + /// /// If `true`, this task should run `dotnet foo.dll` and `foo.exe` otherwise. /// @@ -31,61 +36,65 @@ public abstract class AndroidDotnetToolTask : AndroidToolTask public override bool Execute () { - if (string.IsNullOrEmpty (ToolExe)) { - ToolExe = $"{BaseToolName}.exe"; - } - - var assemblyPath = Path.Combine (ToolPath, $"{BaseToolName}.dll"); - if (File.Exists (assemblyPath)) { + if (Path.GetExtension (ToolExe) == ".dll") { NeedsDotnet = true; - AssemblyPath = assemblyPath; + AssemblyPath = Path.Combine (ToolPath, ToolExe); ToolPath = null; + ToolExe = null; - Log.LogDebugMessage ($"Using: dotnet {AssemblyPath}"); + Log.LogDebugMessage ($"Using: {FindDotnet ()} {AssemblyPath}"); } else { if (!RuntimeInformation.IsOSPlatform (OSPlatform.Windows) && !RuntimeInformation.FrameworkDescription.StartsWith ("Mono", StringComparison.OrdinalIgnoreCase)) { // If not Windows and not running under Mono NeedsMono = true; - AssemblyPath = Path.Combine (ToolPath, $"{BaseToolName}.exe"); + AssemblyPath = Path.Combine (ToolPath, ToolExe); ToolPath = null; + ToolExe = null; - Log.LogDebugMessage ($"Using: mono {AssemblyPath}"); + Log.LogDebugMessage ($"Using: {FindMono ()} {AssemblyPath}"); } else { // Otherwise running the .exe directly should work - Log.LogDebugMessage ($"Using: {GenerateFullPathToTool ()}"); + Log.LogDebugMessage ($"Using: {Path.Combine (ToolPath, ToolExe)}"); } } return base.Execute (); } - /// - /// The base tool name, such as "generator" for `generator.exe` and `dotnet generator.dll` - /// - protected abstract string BaseToolName { - get; - } - protected override string ToolName { get { if (NeedsDotnet) return "dotnet"; if (NeedsMono) return "mono"; - return $"{BaseToolName}.exe"; + return ToolExe; } } protected override string GenerateFullPathToTool () { if (NeedsDotnet) - return "dotnet"; + return FindDotnet (); if (NeedsMono) return FindMono (); return Path.Combine (ToolPath, ToolExe); } + string FindDotnet () + { + if (Directory.Exists (NetCoreRoot)) { + var dotnetPath = Path.Combine (NetCoreRoot, (RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? "dotnet.exe" : "dotnet")); + if (File.Exists (dotnetPath)) + return dotnetPath; + } + + var dotnetHostPath = Environment.GetEnvironmentVariable ("DOTNET_HOST_PATH"); + if (File.Exists (dotnetHostPath)) + return dotnetHostPath; + + return "dotnet"; + } const RegisteredTaskObjectLifetime Lifetime = RegisteredTaskObjectLifetime.Build; const string MonoKey = nameof (AndroidDotnetToolTask) + "_Mono"; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs index 984bc8b4ab1..ce217d907fc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs @@ -10,8 +10,6 @@ public class ClassParse : AndroidDotnetToolTask { public override string TaskPrefix => "CLP"; - protected override string BaseToolName => "class-parse"; - [Required] public string OutputFile { get; set; } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs index f9b434e0e45..6d5848b96c6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs @@ -241,8 +241,6 @@ protected override string GenerateCommandLineCommands () return cmd.ToString (); } - protected override string BaseToolName => "generator"; - protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance) { base.LogEventsFromTextOutput (singleLine, messageImportance); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ImportJavaDoc.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ImportJavaDoc.cs index 4ae60e681c9..3b2c4e89ddb 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ImportJavaDoc.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ImportJavaDoc.cs @@ -24,8 +24,6 @@ public class ImportJavaDoc : AndroidDotnetToolTask [Required] public string OutputDocDirectory { get; set; } - protected override string BaseToolName => "javadoc-to-mdoc"; - protected override string GenerateCommandLineCommands () { if (!Directory.Exists (OutputDocDirectory)) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/AndroidDotnetToolTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/AndroidDotnetToolTests.cs new file mode 100644 index 00000000000..99d78ee4b4e --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/AndroidDotnetToolTests.cs @@ -0,0 +1,58 @@ +using System; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Xamarin.Android.Tasks; +using Xamarin.ProjectTools; + +namespace Xamarin.Android.Build.Tests +{ + [TestFixture] + [Category ("Node-5")] + public class AndroidDotnetToolTests : BaseTest + { + MockBuildEngine engine; + List errors; + List warnings; + List messages; + + [SetUp] + public void Setup () + { + engine = new MockBuildEngine (TestContext.Out, + errors: errors = new List (), + warnings: warnings = new List (), + messages: messages = new List ()); + } + + [Test] + public void ShouldUseFullToolPath () + { + var dotnetDir = AndroidSdkResolver.GetDotNetPreviewPath (); + var dotnetPath = Path.Combine (dotnetDir, (TestEnvironment.IsWindows ? "dotnet.exe" : "dotnet")); + var classParseTask = new ClassParseTestTask { + BuildEngine = engine, + NetCoreRoot = dotnetDir, + ToolPath = Builder.UseDotNet ? TestEnvironment.DotNetAndroidSdkToolsDirectory : AndroidMSBuildDirectory, + ToolExe = Builder.UseDotNet ? "class-parse.dll" : "class-parse.exe", + }; + + Assert.True (classParseTask.Execute (), "Task should have succeeded."); + var expectedTool = Builder.UseDotNet ? dotnetPath : Path.Combine (AndroidMSBuildDirectory, "class-parse.exe"); + Assert.IsTrue (messages.Any (m => m.Message.StartsWith (expectedTool)), "Task did not use expected tool path."); + } + } + + public class ClassParseTestTask : AndroidDotnetToolTask + { + public override string TaskPrefix => "TEST"; + protected override string GenerateCommandLineCommands () + { + return GetCommandLineBuilder ().ToString (); + } + } +}