Skip to content

Commit 8ea78a4

Browse files
authored
Add Microsoft.Android.Build.BaseTasks project (#101)
We are hoping to sever the xamarin-android dependency from monodroid. In order to do this we'll want to share some common MSBuild code across our two build task assemblies, `Xamarin.Android.Build.Tasks` and `Xamarin.Android.Build.Debugging.Tasks`. This common code has been moved from xamarin/xamarin-android into a new project in this repo named `Microsoft.Android.Build.BaseTasks`. More utilities can be migrated here in the future if we so desire. A new test project `Microsoft.Android.Build.BaseTasks-Tests.csproj` has also been added to bring over the relevant tests from xamarin-android.
1 parent b2d9fdf commit 8ea78a4

39 files changed

+3392
-4
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ prepare:
1616
run-all-tests:
1717
dotnet test -l "console;verbosity=detailed" -l trx \
1818
tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj
19+
dotnet test -l "console;verbosity=detailed" -l trx \
20+
tests/Microsoft.Android.Build.BaseTasks-Tests/Microsoft.Android.Build.BaseTasks-Tests.csproj

Xamarin.Android.Tools.sln

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
2-
# Visual Studio 2012
3-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.AndroidSdk", "src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}"
2+
# Visual Studio Version 16
3+
VisualStudioVersion = 16.0.30709.64
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AndroidSdk", "src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}"
46
EndProject
5-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.AndroidSdk-Tests", "tests\Xamarin.Android.Tools.AndroidSdk-Tests\Xamarin.Android.Tools.AndroidSdk-Tests.csproj", "{1E5501E8-49C1-4659-838D-CC9720C5208F}"
7+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AndroidSdk-Tests", "tests\Xamarin.Android.Tools.AndroidSdk-Tests\Xamarin.Android.Tools.AndroidSdk-Tests.csproj", "{1E5501E8-49C1-4659-838D-CC9720C5208F}"
8+
EndProject
9+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Android.Build.BaseTasks", "src\Microsoft.Android.Build.BaseTasks\Microsoft.Android.Build.BaseTasks.csproj", "{C8E51A26-F7A5-4B81-B0BC-F9A4BFB43D38}"
10+
EndProject
11+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Build.BaseTasks-Tests", "tests\Microsoft.Android.Build.BaseTasks-Tests\Microsoft.Android.Build.BaseTasks-Tests.csproj", "{4F5FD01C-B5A6-4F9F-91CE-3E78B3F942AC}"
612
EndProject
713
Global
814
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -18,8 +24,19 @@ Global
1824
{1E5501E8-49C1-4659-838D-CC9720C5208F}.Debug|Any CPU.Build.0 = Debug|Any CPU
1925
{1E5501E8-49C1-4659-838D-CC9720C5208F}.Release|Any CPU.ActiveCfg = Release|Any CPU
2026
{1E5501E8-49C1-4659-838D-CC9720C5208F}.Release|Any CPU.Build.0 = Release|Any CPU
27+
{C8E51A26-F7A5-4B81-B0BC-F9A4BFB43D38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28+
{C8E51A26-F7A5-4B81-B0BC-F9A4BFB43D38}.Debug|Any CPU.Build.0 = Debug|Any CPU
29+
{C8E51A26-F7A5-4B81-B0BC-F9A4BFB43D38}.Release|Any CPU.ActiveCfg = Release|Any CPU
30+
{C8E51A26-F7A5-4B81-B0BC-F9A4BFB43D38}.Release|Any CPU.Build.0 = Release|Any CPU
31+
{4F5FD01C-B5A6-4F9F-91CE-3E78B3F942AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32+
{4F5FD01C-B5A6-4F9F-91CE-3E78B3F942AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
33+
{4F5FD01C-B5A6-4F9F-91CE-3E78B3F942AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
34+
{4F5FD01C-B5A6-4F9F-91CE-3E78B3F942AC}.Release|Any CPU.Build.0 = Release|Any CPU
2135
EndGlobalSection
2236
GlobalSection(SolutionProperties) = preSolution
2337
HideSolutionNode = FALSE
2438
EndGlobalSection
39+
GlobalSection(ExtensibilityGlobals) = postSolution
40+
SolutionGuid = {BA1CD771-F00B-4DE8-93EE-7690D81F6A5A}
41+
EndGlobalSection
2542
EndGlobal

azure-pipelines.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ jobs:
6868
inputs:
6969
command: test
7070
projects: bin/TestDebug-net*/**/*-Tests.dll
71-
testRunTitle: Xamarin.Android.Tools Tests - $(vmImage)
7271

7372
- powershell: |
7473
$hashOfLastVersionChange = & "git" "log" "--follow" "-1" "--pretty=%H" "nuget.version"
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// https://github.com/xamarin/xamarin-android/blob/9fca138604c53989e1cff7fc0c2e939583b4da28/src/Xamarin.Android.Build.Tasks/Tasks/AndroidTask.cs#L27
2+
3+
using System;
4+
using Xamarin.Build;
5+
using static System.Threading.Tasks.TaskExtensions;
6+
7+
namespace Microsoft.Android.Build.Tasks
8+
{
9+
public abstract class AndroidAsyncTask : AsyncTask
10+
{
11+
public abstract string TaskPrefix { get; }
12+
13+
public override bool Execute ()
14+
{
15+
try {
16+
return RunTask ();
17+
} catch (Exception ex) {
18+
this.LogUnhandledException (TaskPrefix, ex);
19+
return false;
20+
}
21+
}
22+
23+
/// <summary>
24+
/// Typically `RunTaskAsync` will be the preferred method to override,
25+
/// however this method can be overridden instead for Tasks that will
26+
/// run quickly and do not need to be asynchronous.
27+
/// </summary>
28+
public virtual bool RunTask ()
29+
{
30+
Yield ();
31+
try {
32+
this.RunTask (() => RunTaskAsync ())
33+
.Unwrap ()
34+
.ContinueWith (Complete);
35+
36+
// This blocks on AsyncTask.Execute, until Complete is called
37+
return base.Execute ();
38+
} finally {
39+
Reacquire ();
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Override this method for simplicity of AsyncTask usage:
45+
/// * Yield / Reacquire is handled for you
46+
/// * RunTaskAsync is already on a background thread
47+
/// </summary>
48+
public virtual System.Threading.Tasks.Task RunTaskAsync () => System.Threading.Tasks.Task.CompletedTask;
49+
}
50+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// https://github.com/xamarin/xamarin-android/blob/34acbbae6795854cc4e9f8eb7167ab011e0266b4/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs#L251
2+
3+
using System;
4+
using System.IO;
5+
using System.Linq;
6+
using Microsoft.Build.Framework;
7+
8+
namespace Microsoft.Android.Build.Tasks
9+
{
10+
public static class AndroidRidAbiHelper
11+
{
12+
static readonly string[] ValidAbis = new[]{
13+
"arm64-v8a",
14+
"armeabi-v7a",
15+
"x86",
16+
"x86_64",
17+
};
18+
19+
public static string GetNativeLibraryAbi (string lib)
20+
{
21+
// The topmost directory the .so file is contained within
22+
var dir = Path.GetFileName (Path.GetDirectoryName (lib)).ToLowerInvariant ();
23+
if (dir.StartsWith ("interpreter-", StringComparison.Ordinal)) {
24+
dir = dir.Substring (12);
25+
}
26+
if (ValidAbis.Contains (dir)) {
27+
return dir;
28+
}
29+
return null;
30+
}
31+
32+
public static string GetNativeLibraryAbi (ITaskItem lib)
33+
{
34+
// If Abi is explicitly specified, simply return it.
35+
var lib_abi = lib.GetMetadata ("Abi");
36+
37+
if (!string.IsNullOrWhiteSpace (lib_abi))
38+
return lib_abi;
39+
40+
// Try to figure out what type of abi this is from the path
41+
// First, try nominal "Link" path.
42+
var link = lib.GetMetadata ("Link");
43+
if (!string.IsNullOrWhiteSpace (link)) {
44+
var linkdirs = link.ToLowerInvariant ().Split ('/', '\\');
45+
lib_abi = ValidAbis.Where (p => linkdirs.Contains (p)).FirstOrDefault ();
46+
}
47+
48+
// Check for a RuntimeIdentifier
49+
var rid = lib.GetMetadata ("RuntimeIdentifier");
50+
if (!string.IsNullOrWhiteSpace (rid)) {
51+
lib_abi = RuntimeIdentifierToAbi (rid);
52+
}
53+
54+
if (!string.IsNullOrWhiteSpace (lib_abi))
55+
return lib_abi;
56+
57+
// If not resolved, use ItemSpec
58+
return GetNativeLibraryAbi (lib.ItemSpec);
59+
}
60+
61+
/// <summary>
62+
/// Converts .NET 5 RIDs to Android ABIs or an empty string if no match.
63+
///
64+
/// Known RIDs:
65+
/// "android.21-arm64" -> "arm64-v8a"
66+
/// "android.21-arm" -> "armeabi-v7a"
67+
/// "android.21-x86" -> "x86"
68+
/// "android.21-x64" -> "x86_64"
69+
/// "android-arm64" -> "arm64-v8a"
70+
/// "android-arm" -> "armeabi-v7a"
71+
/// "android-x86" -> "x86"
72+
/// "android-x64" -> "x86_64"
73+
/// </summary>
74+
public static string RuntimeIdentifierToAbi (string runtimeIdentifier)
75+
{
76+
if (string.IsNullOrEmpty (runtimeIdentifier) || !runtimeIdentifier.StartsWith ("android", StringComparison.OrdinalIgnoreCase)) {
77+
return "";
78+
}
79+
if (runtimeIdentifier.EndsWith ("-arm64", StringComparison.OrdinalIgnoreCase)) {
80+
return "arm64-v8a";
81+
}
82+
if (runtimeIdentifier.EndsWith ("-arm", StringComparison.OrdinalIgnoreCase)) {
83+
return "armeabi-v7a";
84+
}
85+
if (runtimeIdentifier.EndsWith ("-x86", StringComparison.OrdinalIgnoreCase)) {
86+
return "x86";
87+
}
88+
if (runtimeIdentifier.EndsWith ("-x64", StringComparison.OrdinalIgnoreCase)) {
89+
return "x86_64";
90+
}
91+
return "";
92+
}
93+
}
94+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// https://github.com/xamarin/xamarin-android/blob/0134c2fb20f2f20127b24ef49177d9fe8226efdb/src/Xamarin.Android.Build.Tasks/Tasks/AndroidToolTask.cs#L9
2+
3+
using System.IO;
4+
using System.Text.RegularExpressions;
5+
using Microsoft.Build.Framework;
6+
7+
namespace Microsoft.Android.Build.Tasks
8+
{
9+
public abstract class AndroidRunToolTask : AndroidToolTask
10+
{
11+
protected static bool IsWindows = Path.DirectorySeparatorChar == '\\';
12+
13+
protected abstract string DefaultErrorCode { get; }
14+
15+
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
16+
{
17+
base.LogEventsFromTextOutput (singleLine, messageImportance);
18+
19+
if (messageImportance != StandardErrorLoggingImportance)
20+
return;
21+
22+
Log.LogFromStandardError (DefaultErrorCode, singleLine);
23+
}
24+
25+
protected virtual Regex ErrorRegex {
26+
get { return AndroidErrorRegex; }
27+
}
28+
29+
/* This gets pre-pended to any filenames that we get from error strings */
30+
protected string BaseDirectory { get; set; }
31+
32+
// Aapt errors looks like this:
33+
// res\layout\main.axml:7: error: No resource identifier found for attribute 'id2' in package 'android' (TaskId:22)
34+
// Resources/values/theme.xml(2): error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'.
35+
// Resources/values/theme.xml:2: error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'.
36+
// res/drawable/foo-bar.jpg: Invalid file name: must contain only [a-z0-9_.]
37+
// Warnings can be like this
38+
// aapt2 W 09-17 18:15:27 98796 12879433 ApkAssets.cpp:138] resources.arsc in APK 'android.jar' is compressed.
39+
// Look for them and convert them to MSBuild compatible errors.
40+
static Regex androidErrorRegex;
41+
public static Regex AndroidErrorRegex {
42+
get {
43+
if (androidErrorRegex == null)
44+
androidErrorRegex = new Regex (@"
45+
^
46+
( # start optional path followed by `:`
47+
(?<path>
48+
(?<file>.+[\\/][^:\(]+)
49+
(
50+
([:](?<line>[\d ]+))
51+
|
52+
(\((?<line>[\d ]+)\))
53+
)?
54+
)
55+
\s*
56+
:
57+
)?
58+
( # optional warning|error|aapt2\sW|aapt2.exe\sW:
59+
\s*
60+
(?<level>(warning|error|aapt2\sW|aapt2.exe\sW)[^:]*)\s*
61+
:
62+
)?
63+
\s*
64+
(?<message>.*)
65+
$
66+
", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
67+
return androidErrorRegex;
68+
}
69+
}
70+
71+
protected static string QuoteString (string value)
72+
{
73+
return string.Format ("\"{0}\"", value);
74+
}
75+
}
76+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// https://github.com/xamarin/xamarin-android/blob/9fca138604c53989e1cff7fc0c2e939583b4da28/src/Xamarin.Android.Build.Tasks/Tasks/AndroidTask.cs#L10
2+
3+
using System;
4+
using Microsoft.Build.Utilities;
5+
6+
namespace Microsoft.Android.Build.Tasks
7+
{
8+
// We use this task to ensure that no unhandled exceptions
9+
// escape our tasks which would cause an MSB4018
10+
public abstract class AndroidTask : Task
11+
{
12+
public abstract string TaskPrefix { get; }
13+
14+
public override bool Execute ()
15+
{
16+
try {
17+
return RunTask ();
18+
} catch (Exception ex) {
19+
Log.LogUnhandledException (TaskPrefix, ex);
20+
return false;
21+
}
22+
}
23+
24+
public abstract bool RunTask ();
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// https://github.com/xamarin/xamarin-android/blob/9fca138604c53989e1cff7fc0c2e939583b4da28/src/Xamarin.Android.Build.Tasks/Tasks/AndroidTask.cs#L75
2+
3+
using System;
4+
using Microsoft.Build.Utilities;
5+
6+
namespace Microsoft.Android.Build.Tasks
7+
{
8+
public abstract class AndroidToolTask : ToolTask
9+
{
10+
public abstract string TaskPrefix { get; }
11+
12+
public override bool Execute ()
13+
{
14+
try {
15+
return RunTask ();
16+
} catch (Exception ex) {
17+
Log.LogUnhandledException (TaskPrefix, ex);
18+
return false;
19+
}
20+
}
21+
22+
// Most ToolTask's do not override Execute and
23+
// just expect the base to be called
24+
public virtual bool RunTask () => base.Execute ();
25+
}
26+
}

0 commit comments

Comments
 (0)