From f6958e47c0172111548aa76350db39487c6d598f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 30 Jun 2026 16:10:09 -0500 Subject: [PATCH 1/3] [xaprepare] Move XABuildConfig.cs generation from xaprepare to MSBuild Mirrors the cmake-config.csproj precedent (#11760): a new Microsoft.Build.NoTargets project at build-tools/scripts/xabuildconfig/xabuildconfig.csproj generates bin/Build$(Configuration)/XABuildConfig.cs from build-tools/scripts/XABuildConfig.cs.in using the existing ReplaceFileContents, GitCommitHash, and GitBranch prep tasks (all hosted via TaskFactory=TaskHostFactory Runtime=NET, per the internal-prep-task convention). All substitution values come from Configuration.props properties already in scope - no new C# task code required. The three consumers that XABuildConfig.cs now the new csproj with ReferenceOutputAssembly=False, ensuring single-execution and ordering for isolated builds: * src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj * src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj * src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj The generated file is byte-identical to the prior xaprepare output (verified via fc /b against a baseline captured before the change). xaprepare cleanup (the only consumers of these methods/properties were the deleted Get_XABuildConfig_cs and its helpers): * Step_GenerateFiles.cs: deleted Get_XABuildConfig_cs and its GetMajor/GetMinor helpers; the at-build-start list now contains only Get_Configuration_OperatingSystem_props. * BuildInfo.cs: deleted NDKRevision, NDKVersionMajor/Minor/Micro, NDKVersion, cachedNdkVersion, XACommitHash, XABranch, GatherGitInfo, and DetermineXACommitInfo. * Context.cs: removed the `if (SelectedScenario.NeedsGitBuildInfo)` GatherGitInfo block. * Scenario.cs / Scenario_Required.cs / Scenario_Standard.cs: removed the now-unused NeedsGitBuildInfo property and setters. * ConfigAndData/BuildAndroidPlatforms.cs: entire file deleted - AndroidNdkVersion, AndroidNdkPkgRevision, NdkMinimumAPI, and NdkMinimumAPILegacy32 were all sourced from Configuration.props by way of Get_XABuildConfig_cs. * Utilities.cs: deleted ParseAndroidPkgRevision (sole caller was BuildInfo.NDKVersion). * GitRunner.cs: deleted GetTopCommitHash and GetBranchName (sole caller was BuildInfo.DetermineXACommitInfo). The GitRunner class is retained - other consumers (Blame, SubmoduleUpdate, etc.) remain. * README.md: dropped the BuildAndroidPlatforms.cs bullet. Net diff: +6 / -195 (one new ~120-line csproj, ~175 lines of C# removed). Verification: * xaprepare.csproj: 0 warnings, 0 errors. * Xamarin.Android.Build.Tasks.csproj: builds; consumes the MSBuild-generated XABuildConfig.cs unchanged. * Incremental rebuild of xabuildconfig.csproj reports _GenerateXABuildConfig as up-to-date. * fc /b vs baseline: no differences encountered. Precedent PRs in this incremental xaprepare removal stream: #11568, #11580, #11608, #11613, #11631, #11731, #11732, #11733, #11737, #11740, #11760, #11803, #11821, #11825. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../xabuildconfig/xabuildconfig.csproj | 116 ++++++++++++++++++ build-tools/xaprepare/README.md | 3 - .../xaprepare/Application/BuildInfo.cs | 40 ------ .../xaprepare/Application/Context.cs | 3 - .../xaprepare/Application/Scenario.cs | 1 - .../xaprepare/Application/Utilities.cs | 23 ---- .../ConfigAndData/BuildAndroidPlatforms.cs | 13 -- .../xaprepare/Scenarios/Scenario_Required.cs | 1 - .../xaprepare/Scenarios/Scenario_Standard.cs | 1 - .../xaprepare/Steps/Step_GenerateFiles.cs | 55 --------- .../xaprepare/ToolRunners/GitRunner.cs | 55 --------- .../Xamarin.Android.Build.Tests.csproj | 2 + .../Xamarin.ProjectTools.csproj | 2 + .../Xamarin.Android.Build.Tasks.csproj | 2 + 14 files changed, 122 insertions(+), 195 deletions(-) create mode 100644 build-tools/scripts/xabuildconfig/xabuildconfig.csproj delete mode 100644 build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs diff --git a/build-tools/scripts/xabuildconfig/xabuildconfig.csproj b/build-tools/scripts/xabuildconfig/xabuildconfig.csproj new file mode 100644 index 00000000000..29ce336f74e --- /dev/null +++ b/build-tools/scripts/xabuildconfig/xabuildconfig.csproj @@ -0,0 +1,116 @@ + + + + + netstandard2.0 + Debug + AnyCPU + false + + + + + + + + + + <_XABuildConfigTemplate>$(MSBuildThisFileDirectory)..\XABuildConfig.cs.in + <_XABuildConfigOutput>$(XamarinAndroidSourcePath)bin\Build$(Configuration)\XABuildConfig.cs + + + + + + <_XASupportedAbis>$(AndroidSupportedTargetJitAbis.Replace(':', '%3B')) + + <_NdkVersionMajor>$(_XAAndroidNdkPkgRevision.Split('.')[0]) + <_NdkVersionMinor>$(_XAAndroidNdkPkgRevision.Split('.')[1]) + <_NdkVersionMicro>$(_XAAndroidNdkPkgRevision.Split('.')[2]) + + <_MinApiMajor>$(AndroidMinimumDotNetApiLevel.Split('.')[0]) + <_MinApiMinor>0 + <_MinApiMinor Condition=" $(AndroidMinimumDotNetApiLevel.Contains('.')) ">$(AndroidMinimumDotNetApiLevel.Split('.')[1]) + + <_TargetApiMajor>$(AndroidDefaultTargetDotnetApiLevel.Split('.')[0]) + <_TargetApiMinor>0 + <_TargetApiMinor Condition=" $(AndroidDefaultTargetDotnetApiLevel.Contains('.')) ">$(AndroidDefaultTargetDotnetApiLevel.Split('.')[1]) + + <_StableApiMajor>$(AndroidLatestStableApiLevel.Split('.')[0]) + <_StableApiMinor>0 + <_StableApiMinor Condition=" $(AndroidLatestStableApiLevel.Contains('.')) ">$(AndroidLatestStableApiLevel.Split('.')[1]) + + <_UnstableApiMajor>$(AndroidLatestUnstableApiLevel.Split('.')[0]) + <_UnstableApiMinor>0 + <_UnstableApiMinor Condition=" $(AndroidLatestUnstableApiLevel.Contains('.')) ">$(AndroidLatestUnstableApiLevel.Split('.')[1]) + + + + + + + + + + + + <_XABuildConfigReplacement Include="@NDK_REVISION@=$(_XAAndroidNdkPkgRevision)" /> + <_XABuildConfigReplacement Include="@NDK_RELEASE@=$(_XAAndroidNdkRelease)" /> + <_XABuildConfigReplacement Include="@NDK_VERSION_MAJOR@=$(_NdkVersionMajor)" /> + <_XABuildConfigReplacement Include="@NDK_VERSION_MINOR@=$(_NdkVersionMinor)" /> + <_XABuildConfigReplacement Include="@NDK_VERSION_MICRO@=$(_NdkVersionMicro)" /> + <_XABuildConfigReplacement Include="@NDK_ARMEABI_V7_API@=$(_MinApiMajor)" /> + <_XABuildConfigReplacement Include="@NDK_ARM64_V8A_API@=$(_MinApiMajor)" /> + <_XABuildConfigReplacement Include="@NDK_X86_API@=$(_MinApiMajor)" /> + <_XABuildConfigReplacement Include="@NDK_X86_64_API@=$(_MinApiMajor)" /> + <_XABuildConfigReplacement Include="@XA_SUPPORTED_ABIS@=$(_XASupportedAbis)" /> + <_XABuildConfigReplacement Include="@SDK_BUILD_TOOLS_VERSION@=$(XABuildToolsFolder)" /> + <_XABuildConfigReplacement Include="@ANDROID_DEFAULT_MINIMUM_DOTNET_API_LEVEL@=$(_MinApiMajor)" /> + <_XABuildConfigReplacement Include="@ANDROID_DEFAULT_MINIMUM_DOTNET_API_LEVEL_MINOR@=$(_MinApiMinor)" /> + <_XABuildConfigReplacement Include="@ANDROID_DEFAULT_TARGET_DOTNET_API_LEVEL@=$(_TargetApiMajor)" /> + <_XABuildConfigReplacement Include="@ANDROID_DEFAULT_TARGET_DOTNET_API_LEVEL_MINOR@=$(_TargetApiMinor)" /> + <_XABuildConfigReplacement Include="@ANDROID_LATEST_STABLE_API_LEVEL@=$(_StableApiMajor)" /> + <_XABuildConfigReplacement Include="@ANDROID_LATEST_STABLE_API_LEVEL_MINOR@=$(_StableApiMinor)" /> + <_XABuildConfigReplacement Include="@ANDROID_LATEST_UNSTABLE_API_LEVEL@=$(_UnstableApiMajor)" /> + <_XABuildConfigReplacement Include="@ANDROID_LATEST_UNSTABLE_API_LEVEL_MINOR@=$(_UnstableApiMinor)" /> + <_XABuildConfigReplacement Include="@XAMARIN_ANDROID_VERSION@=$(ProductVersion)" /> + <_XABuildConfigReplacement Include="@XAMARIN_ANDROID_COMMIT_HASH@=$(_XACommitHash)" /> + <_XABuildConfigReplacement Include="@XAMARIN_ANDROID_BRANCH@=$(_XABranch)" /> + + + + + + + diff --git a/build-tools/xaprepare/README.md b/build-tools/xaprepare/README.md index 53be76c2522..bda30f58006 100644 --- a/build-tools/xaprepare/README.md +++ b/build-tools/xaprepare/README.md @@ -100,9 +100,6 @@ The files mentioned above are found in the [ConfigAndData](xaprepare/ConfigAndDa Rarely modified, contains all the target ABI names as used throughout the .NET for Android source as well as a number of helper methods used throughout the preparation utility code. **Be very careful** when modifying the names there as it may break the build! - - [BuildAndroidPlatforms.cs](xaprepare/ConfigAndData/BuildAndroidPlatforms.cs) - Contains the NDK release/revision constants and the minimum NDK API levels used for all the Android device targets. - The Android API level list itself lives in [`/src/Mono.Android/Mono.Android.Apis.projitems`](../../src/Mono.Android/Mono.Android.Apis.projitems). - [CommonLicenses.cs](xaprepare/ConfigAndData/CommonLicenses.cs) A file with constants containing paths to licenses commonly used by software .NET for Android uses. The licenses are used when generating Third Party Notices. diff --git a/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs b/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs index 5674d987d41..1d882d0ac9d 100644 --- a/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs +++ b/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs @@ -11,47 +11,7 @@ partial class BuildInfo : AppObject { public string CommitOfLastVersionChange { get; private set; } = String.Empty; - // NDK version info is now derived directly from BuildAndroidPlatforms.AndroidNdkPkgRevision - // (single source of truth shared with src/androidsdk/androidsdk.targets via Configuration.props). - public string NDKRevision => BuildAndroidPlatforms.AndroidNdkPkgRevision; - public string NDKVersionMajor => NDKVersion.Major.ToString (); - public string NDKVersionMinor => NDKVersion.Minor.ToString (); - public string NDKVersionMicro => NDKVersion.Build.ToString (); - - Version? cachedNdkVersion; - Version NDKVersion { - get { - if (cachedNdkVersion != null) - return cachedNdkVersion; - if (!Utilities.ParseAndroidPkgRevision (BuildAndroidPlatforms.AndroidNdkPkgRevision, out Version? ver, out _) || ver == null) - throw new InvalidOperationException ($"Unable to parse NDK revision '{BuildAndroidPlatforms.AndroidNdkPkgRevision}' as a valid version string"); - cachedNdkVersion = ver; - return ver; - } - } - public string VersionHash { get; private set; } = String.Empty; - public string XACommitHash { get; private set; } = String.Empty; - public string XABranch { get; private set; } = String.Empty; - - public async Task GatherGitInfo (Context context) - { - if (context == null) - throw new ArgumentNullException (nameof (context)); - - Log.StatusLine (); - Log.StatusLine ("Determining basic build information", ConsoleColor.DarkGreen); - await DetermineLastVersionChangeCommit (context); - Log.StatusLine (); - DetermineXACommitInfo (context); - } - - void DetermineXACommitInfo (Context context) - { - GitRunner git = CreateGitRunner (context); - XACommitHash = git.GetTopCommitHash (shortHash: false); - XABranch = git.GetBranchName (); - } async Task DetermineLastVersionChangeCommit (Context context) { diff --git a/build-tools/xaprepare/xaprepare/Application/Context.cs b/build-tools/xaprepare/xaprepare/Application/Context.cs index c4ec9a63d52..b126ee4aa29 100644 --- a/build-tools/xaprepare/xaprepare/Application/Context.cs +++ b/build-tools/xaprepare/xaprepare/Application/Context.cs @@ -431,9 +431,6 @@ public async Task Init (string? scenarioName = null) } BuildInfo = new BuildInfo (); - if (SelectedScenario.NeedsGitBuildInfo) { - await BuildInfo.GatherGitInfo (this); - } if (MakeConcurrency == 0) MakeConcurrency = OS.CPUCount + 1; diff --git a/build-tools/xaprepare/xaprepare/Application/Scenario.cs b/build-tools/xaprepare/xaprepare/Application/Scenario.cs index 8fc45c50464..85387455bc1 100644 --- a/build-tools/xaprepare/xaprepare/Application/Scenario.cs +++ b/build-tools/xaprepare/xaprepare/Application/Scenario.cs @@ -11,7 +11,6 @@ abstract partial class Scenario : AppObject public string? LogFilePath { get; protected set; } public List Steps { get; } = new List (); public bool NeedsGitSubmodules { get; protected set; } - public bool NeedsGitBuildInfo { get; protected set; } public bool NeedsCompilers { get; protected set; } protected Scenario (string name, string description) diff --git a/build-tools/xaprepare/xaprepare/Application/Utilities.cs b/build-tools/xaprepare/xaprepare/Application/Utilities.cs index 6d3ced690ab..0a2067e63b9 100644 --- a/build-tools/xaprepare/xaprepare/Application/Utilities.cs +++ b/build-tools/xaprepare/xaprepare/Application/Utilities.cs @@ -31,29 +31,6 @@ static partial class Utilities public static readonly Encoding UTF8NoBOM = new UTF8Encoding (false); - public static bool ParseAndroidPkgRevision (string? v, out Version? version, out string? tag) - { - string? ver = v?.Trim (); - version = null; - tag = null; - if (String.IsNullOrEmpty (ver)) - return false; - - if (ver!.IndexOf ('.') < 0) - ver = $"{ver}.0"; - - int tagIdx = ver.IndexOf ('-'); - if (tagIdx >= 0) { - tag = ver.Substring (tagIdx + 1); - ver = ver.Substring (0, tagIdx - 1); - } - - if (Version.TryParse (ver, out version)) - return true; - - return false; - } - public static string ToXamarinAndroidPropertyValue (ICollection coll) { if (coll == null) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs deleted file mode 100644 index 7ead038f419..00000000000 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Xamarin.Android.Prepare -{ - class BuildAndroidPlatforms - { - public const string AndroidNdkVersion = "28c"; - public const string AndroidNdkPkgRevision = "28.2.13676358"; - - public static string NdkMinimumAPI => Context.Instance.Properties.GetRequiredValue (KnownProperties.AndroidMinimumDotNetApiLevel); - public static string NdkMinimumAPILegacy32 => NdkMinimumAPI; - } -} diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Required.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Required.cs index 3cf55e0dd2d..39e3582f99d 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Required.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Required.cs @@ -10,7 +10,6 @@ public Scenario_Required () : base ("Required", "Just the basic steps to quickly { NeedsGitSubmodules = true; NeedsCompilers = true; - NeedsGitBuildInfo = true; } protected override void AddSteps (Context context) diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs index 06cfc3086df..96c051baf72 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs @@ -10,7 +10,6 @@ public Scenario_Standard () { NeedsGitSubmodules = true; NeedsCompilers = true; - NeedsGitBuildInfo = true; } protected override void AddSteps (Context context) diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index 96105963689..5d555fdf24d 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -47,7 +47,6 @@ protected override Task Execute (Context context) } else { return new List { Get_Configuration_OperatingSystem_props (context), - Get_XABuildConfig_cs (context), }; } } @@ -89,59 +88,5 @@ GeneratedFile Get_Configuration_OperatingSystem_props (Context context) Path.Combine (BuildPaths.XamarinAndroidSourceRoot, OutputFileName) ); } - - GeneratedFile Get_XABuildConfig_cs (Context context) - { - const string OutputFileName = "XABuildConfig.cs"; - - var replacements = new Dictionary (StringComparer.Ordinal) { - { "@NDK_REVISION@", context.BuildInfo.NDKRevision }, - { "@NDK_RELEASE@", BuildAndroidPlatforms.AndroidNdkVersion }, - { "@NDK_VERSION_MAJOR@", context.BuildInfo.NDKVersionMajor }, - { "@NDK_VERSION_MINOR@", context.BuildInfo.NDKVersionMinor }, - { "@NDK_VERSION_MICRO@", context.BuildInfo.NDKVersionMicro }, - { "@NDK_ARMEABI_V7_API@", BuildAndroidPlatforms.NdkMinimumAPILegacy32.ToString () }, - { "@NDK_ARM64_V8A_API@", BuildAndroidPlatforms.NdkMinimumAPI.ToString () }, - { "@NDK_X86_API@", BuildAndroidPlatforms.NdkMinimumAPILegacy32.ToString ().ToString () }, - { "@NDK_X86_64_API@", BuildAndroidPlatforms.NdkMinimumAPI.ToString ().ToString () }, - { "@XA_SUPPORTED_ABIS@", context.Properties.GetRequiredValue (KnownProperties.AndroidSupportedTargetJitAbis).Replace (':', ';') }, - { "@SDK_BUILD_TOOLS_VERSION@", context.Properties.GetRequiredValue (KnownProperties.XABuildToolsFolder) }, - { "@ANDROID_DEFAULT_MINIMUM_DOTNET_API_LEVEL@", GetMajor (context.Properties.GetRequiredValue (KnownProperties.AndroidMinimumDotNetApiLevel)) }, - { "@ANDROID_DEFAULT_MINIMUM_DOTNET_API_LEVEL_MINOR@", GetMinor (context.Properties.GetRequiredValue (KnownProperties.AndroidMinimumDotNetApiLevel)) }, - { "@ANDROID_DEFAULT_TARGET_DOTNET_API_LEVEL@", GetMajor (context.Properties.GetRequiredValue (KnownProperties.AndroidDefaultTargetDotnetApiLevel)) }, - { "@ANDROID_DEFAULT_TARGET_DOTNET_API_LEVEL_MINOR@", GetMinor (context.Properties.GetRequiredValue (KnownProperties.AndroidDefaultTargetDotnetApiLevel)) }, - { "@ANDROID_LATEST_STABLE_API_LEVEL@", GetMajor (context.Properties.GetRequiredValue (KnownProperties.AndroidLatestStableApiLevel)) }, - { "@ANDROID_LATEST_STABLE_API_LEVEL_MINOR@", GetMinor (context.Properties.GetRequiredValue (KnownProperties.AndroidLatestStableApiLevel)) }, - { "@ANDROID_LATEST_UNSTABLE_API_LEVEL@", GetMajor (context.Properties.GetRequiredValue (KnownProperties.AndroidLatestUnstableApiLevel)) }, - { "@ANDROID_LATEST_UNSTABLE_API_LEVEL_MINOR@", GetMinor (context.Properties.GetRequiredValue (KnownProperties.AndroidLatestUnstableApiLevel)) }, - { "@XAMARIN_ANDROID_VERSION@", context.Properties.GetRequiredValue (KnownProperties.ProductVersion) }, - { "@XAMARIN_ANDROID_COMMIT_HASH@", context.BuildInfo.XACommitHash }, - { "@XAMARIN_ANDROID_BRANCH@", context.BuildInfo.XABranch }, - }; - - return new GeneratedPlaceholdersFile ( - replacements, - Path.Combine (Configurables.Paths.BuildToolsScriptsDir, $"{OutputFileName}.in"), - Path.Combine (Configurables.Paths.BuildBinDir, OutputFileName) - ); - - static string GetMajor (string value) - { - var dot = value.IndexOf ('.'); - if (dot < 0) { - return value; - } - return value.Substring (0, dot); - } - - static string GetMinor (string value) - { - var dot = value.IndexOf ('.'); - if (dot < 0) { - return "0"; - } - return value.Substring (dot + 1); - } - } } } diff --git a/build-tools/xaprepare/xaprepare/ToolRunners/GitRunner.cs b/build-tools/xaprepare/xaprepare/ToolRunners/GitRunner.cs index 1fe8f8cf149..bfda932cddc 100644 --- a/build-tools/xaprepare/xaprepare/ToolRunners/GitRunner.cs +++ b/build-tools/xaprepare/xaprepare/ToolRunners/GitRunner.cs @@ -135,61 +135,6 @@ public async Task SubmoduleUpdate (string? workingDirectory = null, bool i return await RunGit (runner, "submodule-update"); } - public string GetBranchName (string? workingDirectory = null) - { - string runnerWorkingDirectory = DetermineRunnerWorkingDirectory (workingDirectory); - var runner = CreateGitRunner (runnerWorkingDirectory); - runner - .AddArgument ("name-rev") - .AddArgument ("--name-only") - .AddArgument ("--exclude=tags/*") - .AddArgument ("HEAD"); - - string branchName = String.Empty; - using (var outputSink = (OutputSink)SetupOutputSink (runner)) { - outputSink.LineCallback = (string? line) => { - if (!String.IsNullOrEmpty (branchName)) { - return; - } - branchName = line?.Trim () ?? String.Empty; - }; - - if (!runner.Run ()) { - return String.Empty; - } - - return branchName; - } - } - - public string GetTopCommitHash (string? workingDirectory = null, bool shortHash = true) - { - string runnerWorkingDirectory = DetermineRunnerWorkingDirectory (workingDirectory); - - var runner = CreateGitRunner (runnerWorkingDirectory); - runner.AddArgument ("rev-parse"); - runner.AddArgument ("HEAD"); - - Log.StatusLine (GetLogMessage (runner), CommandMessageColor); - - string hash = String.Empty; - using (var outputSink = (OutputSink)SetupOutputSink (runner)) { - outputSink.LineCallback = (string? line) => { - if (!String.IsNullOrEmpty (hash)) - return; - hash = line?.Trim () ?? String.Empty; - }; - - if (!runner.Run ()) - return String.Empty; - - if (shortHash) - return Utilities.ShortenGitHash (hash); - - return hash; - } - } - public async Task?> Blame (string filePath) { return await Blame (filePath, gitArguments: null, blameArguments: null, workingDirectory: null); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index dd05e759f72..3ddc820c7e5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -27,6 +27,8 @@ + + diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj index a6000e757d7..43618fd9eec 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj @@ -37,5 +37,7 @@ {dbdc804f-8406-4f5e-83c6-720cb0cb6c6f} vswhere + + diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index edc14fe83cd..7f9d989b052 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -265,6 +265,8 @@ + + From ac9de0dbb3ac29e058768777c03a400aa367f457 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 30 Jun 2026 16:23:18 -0500 Subject: [PATCH 2/3] [xaprepare] Convert XABuildConfig generation to AndroidBuildConfig class library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to commit f6958e47c on this branch. The previous commit moved XABuildConfig.cs generation out of xaprepare into a NoTargets MSBuild project that produced bin/Build$(Configuration)/XABuildConfig.cs and was 'd into three csprojs (Xamarin.Android.Build.Tasks, Xamarin.ProjectTools, Xamarin.Android.Build.Tests). That preserved byte-equivalence with xaprepare's output but kept the long-standing problem that the same type (Xamarin.Android.Tools.XABuildConfig) ended up compiled into three different assemblies. Because Build.Tests references Build.Tasks (which exposes its internals via InternalsVisibleTo), every use of XABuildConfig in test sources produced CS0436 "type conflicts with imported type" warnings — about 22 of them. This commit collapses XABuildConfig to a single definition by making it a real class library: * New project src/AndroidBuildConfig/AndroidBuildConfig.csproj is a regular Microsoft.NET.Sdk netstandard2.0 strong-named assembly. It generates obj/$(Configuration)/$(TargetFramework)/XABuildConfig.cs from XABuildConfig.cs.in (now living alongside the csproj) using the same GitCommitHash / GitBranch / ReplaceFileContents tasks as before, with the BeforeCompile + Compile-inside-target pattern so the generated file lands under obj/ instead of the source tree. * The XABuildConfig class is now public, so consumers reference the assembly normally (the user explicitly OK'd making it public). * The three consumer csprojs lose their for XABuildConfig.cs and reference AndroidBuildConfig with a normal ProjectReference (no ReferenceOutputAssembly=False). * build-tools/installers/create-installers.targets ships AndroidBuildConfig.dll and .pdb alongside Xamarin.Android.Build.Tasks so the SDK installer carries the new dll. Verification: * AndroidBuildConfig.csproj: 0 warnings, 0 errors. * Xamarin.Android.Build.Tasks.csproj: 0 errors, 85 pre-existing unrelated warnings (none referencing XABuildConfig). * Xamarin.Android.Build.Tests.csproj: 0 errors, 7 warnings — down from ~22, the ~15 XABuildConfig CS0436 warnings are eliminated. * xaprepare.csproj: 0 warnings, 0 errors. * Generated XABuildConfig.cs matches the previous output exactly apart from "static class" -> "public static class" (the intentional change) and the expected commit-hash / branch drift. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../installers/create-installers.targets | 2 + .../AndroidBuildConfig.csproj | 77 ++++++++++--------- .../AndroidBuildConfig}/XABuildConfig.cs.in | 2 +- .../Xamarin.Android.Build.Tests.csproj | 4 +- .../Xamarin.ProjectTools.csproj | 4 +- .../Xamarin.Android.Build.Tasks.csproj | 4 +- 6 files changed, 47 insertions(+), 46 deletions(-) rename build-tools/scripts/xabuildconfig/xabuildconfig.csproj => src/AndroidBuildConfig/AndroidBuildConfig.csproj (70%) rename {build-tools/scripts => src/AndroidBuildConfig}/XABuildConfig.cs.in (98%) diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index 9c5e22940f6..71b59b45481 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -148,6 +148,8 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.JavaDependencyVerification.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.Maven.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Microsoft.Android.Sdk.Bindings.Gradle.targets" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)AndroidBuildConfig.dll" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)AndroidBuildConfig.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Tasks.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Tasks.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Microsoft.Android.Sdk.TrimmableTypeMap.dll" /> diff --git a/build-tools/scripts/xabuildconfig/xabuildconfig.csproj b/src/AndroidBuildConfig/AndroidBuildConfig.csproj similarity index 70% rename from build-tools/scripts/xabuildconfig/xabuildconfig.csproj rename to src/AndroidBuildConfig/AndroidBuildConfig.csproj index 29ce336f74e..8e703575098 100644 --- a/build-tools/scripts/xabuildconfig/xabuildconfig.csproj +++ b/src/AndroidBuildConfig/AndroidBuildConfig.csproj @@ -1,55 +1,55 @@ - - - + + + + - netstandard2.0 - Debug - AnyCPU - false + $(TargetFrameworkNETStandard) + Xamarin.Android.Tools + true + ..\..\product.snk - + + + - <_XABuildConfigTemplate>$(MSBuildThisFileDirectory)..\XABuildConfig.cs.in - <_XABuildConfigOutput>$(XamarinAndroidSourcePath)bin\Build$(Configuration)\XABuildConfig.cs + <_XABuildConfigTemplate>$(MSBuildThisFileDirectory)XABuildConfig.cs.in + Outputs="$(IntermediateOutputPath)XABuildConfig.cs"> + <_XABuildConfigOutput>$(IntermediateOutputPath)XABuildConfig.cs <_XASupportedAbis>$(AndroidSupportedTargetJitAbis.Replace(':', '%3B')) <_NdkVersionMajor>$(_XAAndroidNdkPkgRevision.Split('.')[0]) @@ -106,11 +106,16 @@ <_XABuildConfigReplacement Include="@XAMARIN_ANDROID_BRANCH@=$(_XABranch)" /> - + + + + + + diff --git a/build-tools/scripts/XABuildConfig.cs.in b/src/AndroidBuildConfig/XABuildConfig.cs.in similarity index 98% rename from build-tools/scripts/XABuildConfig.cs.in rename to src/AndroidBuildConfig/XABuildConfig.cs.in index 3c8ce65db0f..fbcf3d4e52b 100644 --- a/build-tools/scripts/XABuildConfig.cs.in +++ b/src/AndroidBuildConfig/XABuildConfig.cs.in @@ -5,7 +5,7 @@ using Xamarin.Android.Tools.AndroidSdk; namespace Xamarin.Android.Tools { - static class XABuildConfig + public static class XABuildConfig { public const string SupportedABIs = "@XA_SUPPORTED_ABIS@"; public const string NDKRevision = "@NDK_REVISION@"; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index 3ddc820c7e5..f99cb2ba1c1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -27,15 +27,13 @@ - - + - ..\Expected\GenerateDesignerFileExpected.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj index 43618fd9eec..9da63eb9a38 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj @@ -15,7 +15,6 @@ - @@ -37,7 +36,6 @@ {dbdc804f-8406-4f5e-83c6-720cb0cb6c6f} vswhere - - + diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index 7f9d989b052..5ef69c8d78d 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -42,7 +42,6 @@ - @@ -265,8 +264,7 @@ - - + From 46eea6c22c421bcfe753e974ed0023e6eab83e5a Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 1 Jul 2026 08:04:58 -0500 Subject: [PATCH 3/3] [xaprepare] Add AndroidBuildConfig.csproj to Xamarin.Android.sln Without this the CI build fails on Windows/Linux because the project reference from Xamarin.Android.Build.Tasks (built via the sln in Release) somehow triggers AndroidBuildConfig with Configuration=Debug, so it looks for bin\BuildDebug\net10.0\xa-prep-tasks.dll -- which doesn't exist yet. Adding the project to the sln with proper Debug/Release configuration mappings (mirroring cmake-config which has the same pattern) ensures the solution build passes Configuration correctly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- Xamarin.Android.sln | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index f93e6403d70..1feead5f7db 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native-nativeaot", "src\nat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmake-config", "src\native\cmake-config\cmake-config.csproj", "{5AA3C091-400C-40E4-A073-E093541A5B98}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AndroidBuildConfig", "src\AndroidBuildConfig\AndroidBuildConfig.csproj", "{4BD4C596-7AF4-416E-A4E6-B4739596DF08}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.ProjectTools", "src\Xamarin.Android.Build.Tasks\Tests\Xamarin.ProjectTools\Xamarin.ProjectTools.csproj", "{2DD1EE75-6D8D-4653-A800-0A24367F7F38}" @@ -411,6 +413,18 @@ Global {5AA3C091-400C-40E4-A073-E093541A5B98}.Release|x64.Build.0 = Release|Any CPU {5AA3C091-400C-40E4-A073-E093541A5B98}.Release|x86.ActiveCfg = Release|Any CPU {5AA3C091-400C-40E4-A073-E093541A5B98}.Release|x86.Build.0 = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|x64.ActiveCfg = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|x64.Build.0 = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|x86.ActiveCfg = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Debug|x86.Build.0 = Debug|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|Any CPU.Build.0 = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|x64.ActiveCfg = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|x64.Build.0 = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|x86.ActiveCfg = Release|Any CPU + {4BD4C596-7AF4-416E-A4E6-B4739596DF08}.Release|x86.Build.0 = Release|Any CPU {2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Debug|Any CPU.Build.0 = Debug|Any CPU {2DD1EE75-6D8D-4653-A800-0A24367F7F38}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1059,6 +1073,7 @@ Global {9B42A5BB-74CB-46E2-BCE0-AF763A792551} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {645E1718-C8C4-4C23-8A49-5A37E4ECF7ED} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {5AA3C091-400C-40E4-A073-E093541A5B98} = {04E3E11E-B47D-4599-8AFC-50515A95E715} + {4BD4C596-7AF4-416E-A4E6-B4739596DF08} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {2DD1EE75-6D8D-4653-A800-0A24367F7F38} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {53E4ABF0-1085-45F9-B964-DCAE4B819998} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {F9CD012E-67AC-4A4E-B2A7-252387F91256} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}