From 7df3eb1520c22146da9addbcbd77119ec601685c Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 15 Jun 2023 07:21:09 +0200 Subject: [PATCH 1/8] [dotnet] Add targets to compute mlaunch arguments for installing and launching mobile apps. Fixes #18359. (#18446) Add public targets to compute the mlaunch command lines for installing and launching mobile apps. These new targets are: * ComputeMlaunchInstallArguments * ComputeMlaunchRunArguments As part of this change, also create a few new public properties: * MlaunchPath * MlaunchRunArguments * MlaunchInstallArguments * MlaunchRunScript * MlaunchInstallScript If the *Script variables are set, the corresponding target will create a script file with the path to mlaunch + the corresponding arguments. Otherwise, it's also possible to get the arguments directly from the build log. Fixes https://github.com/xamarin/xamarin-macios/issues/18359. --- .../targets/Microsoft.iOS.Windows.Sdk.props | 1 + dotnet/targets/Xamarin.Shared.Sdk.targets | 50 +++++++--- tests/common/BinLog.cs | 11 +++ tests/dotnet/UnitTests/MlaunchTest.cs | 97 +++++++++++++++++++ 4 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 tests/dotnet/UnitTests/MlaunchTest.cs diff --git a/dotnet/Microsoft.iOS.Windows.Sdk/targets/Microsoft.iOS.Windows.Sdk.props b/dotnet/Microsoft.iOS.Windows.Sdk/targets/Microsoft.iOS.Windows.Sdk.props index f834eba64dbd..57f86c3eed67 100644 --- a/dotnet/Microsoft.iOS.Windows.Sdk/targets/Microsoft.iOS.Windows.Sdk.props +++ b/dotnet/Microsoft.iOS.Windows.Sdk/targets/Microsoft.iOS.Windows.Sdk.props @@ -8,6 +8,7 @@ <_DotNetRootRemoteDirectory Condition="$(_DotNetRootRemoteDirectory) == ''">/usr/local/share/dotnet/ <_XamarinSdkRootDirectoryOnMac Condition="'$(_XamarinSdkRootDirectory)' != ''">$(_XamarinSdkRootDirectory.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)')) <_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch + $(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch $(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)..\targets\Microsoft.iOS.Windows.Sdk.targets <_XamarinSdkRootOnMac Condition="'$(_XamarinSdkRoot)' != ''">$(_XamarinSdkRoot.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)')) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 8515abdfba33..787f33f32870 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -1723,34 +1723,51 @@ - <_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectory)tools\bin\mlaunch + + $(_MlaunchPath) + $(_XamarinSdkRootDirectory)tools\bin\mlaunch + <_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(MlaunchPath) - + + + + - + - + + + + + - - + + + <_MlaunchCaptureOutput Condition="'$(_MlaunchCaptureOutput)' == ''">true @@ -1775,7 +1792,7 @@ DeviceName="$(_DeviceName)" EnvironmentVariables="@(MlaunchEnvironmentVariables)" LaunchApp="$(_AppBundlePath)" - MlaunchPath="$(_MlaunchPath)" + MlaunchPath="$(MlaunchPath)" SdkIsSimulator="$(_SdkIsSimulator)" SdkDevPath="$(_SdkDevPath)" SdkVersion="$(_SdkVersion)" @@ -1784,12 +1801,23 @@ TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" WaitForExit="$(_MlaunchWaitForExit)" > - + + + + + + - $(_MlaunchPath) - $(_MlaunchRunArguments) + $(MlaunchPath) + $(MlaunchRunArguments) diff --git a/tests/common/BinLog.cs b/tests/common/BinLog.cs index f49a29920fce..4ae578ca46c7 100644 --- a/tests/common/BinLog.cs +++ b/tests/common/BinLog.cs @@ -260,6 +260,17 @@ public static bool TryFindPropertyValue (string binlog, string property, [NotNul var dict = pefea.Properties as IDictionary; if (dict is not null && dict.TryGetValue (property, out var pvalue)) value = pvalue; + } else if (args is BuildMessageEventArgs bmea) { + if (bmea.Message.StartsWith ("Output Property: ", StringComparison.Ordinal)) { + var kvp = bmea.Message.Substring ("Output Property: ".Length); + var eq = kvp.IndexOf ('='); + if (eq > 0) { + var propname = kvp.Substring (0, eq); + var propvalue = kvp.Substring (eq + 1); + if (propname == property) + value = propvalue; + } + } } } diff --git a/tests/dotnet/UnitTests/MlaunchTest.cs b/tests/dotnet/UnitTests/MlaunchTest.cs new file mode 100644 index 000000000000..b48b4a232cb9 --- /dev/null +++ b/tests/dotnet/UnitTests/MlaunchTest.cs @@ -0,0 +1,97 @@ +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Text; + +using Mono.Cecil; + +using Xamarin.Tests; + +#nullable enable + +namespace Xamarin.Tests { + [TestFixture] + public class MlaunchTest : TestBaseClass { + [Test] + [TestCase (ApplePlatform.iOS, "ios-arm64")] + [TestCase (ApplePlatform.TVOS, "tvos-arm64")] + public void GetMlaunchInstallArguments (ApplePlatform platform, string runtimeIdentifiers) + { + var project = "MySimpleApp"; + Configuration.IgnoreIfIgnoredPlatform (platform); + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + + var outputPath = Path.Combine (Cache.CreateTemporaryDirectory (), "install.sh"); + var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath); + var properties = GetDefaultProperties (runtimeIdentifiers); + properties ["EnableCodeSigning"] = "false"; // Skip code signing, since that would require making sure we have code signing configured on bots. + + // Create the app manifest first, since it's required to compute the mlaunch install arguments + DotNet.Execute ("build", project_path, properties, target: "_DetectSdkLocations;_DetectAppManifest;_CompileAppManifest;_WriteAppManifest"); + + properties ["MlaunchInstallScript"] = outputPath; + var rv = DotNet.Execute ("build", project_path, properties, target: "ComputeMlaunchInstallArguments"); + + if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchInstallArguments", out var mlaunchInstallArguments)) + Assert.Fail ("Could not find the property 'MlaunchInstallArguments' in the binlog."); + + if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchPath", out var mlaunchPath)) + Assert.Fail ("Could not find the property 'MlaunchPath' in the binlog."); + Assert.That (mlaunchPath, Does.Exist, "mlaunch existence"); + + var expectedArguments = new StringBuilder (); + expectedArguments.Append ("--installdev "); + expectedArguments.Append (appPath.Substring (Path.GetDirectoryName (project_path)!.Length + 1)).Append ('/'); + expectedArguments.Append ($" --wait-for-exit:false"); + Assert.AreEqual (expectedArguments.ToString (), mlaunchInstallArguments); + + var scriptContents = File.ReadAllText (outputPath).Trim ('\n');; + var expectedScriptContents = mlaunchPath + " " + expectedArguments.ToString (); + Assert.AreEqual (expectedScriptContents, scriptContents, "Script contents"); + } + + [Test] + [TestCase (ApplePlatform.iOS, "iossimulator-x64;iossimulator-arm64", ":v2:runtime=com.apple.CoreSimulator.SimRuntime.iOS-16-4,devicetype=com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro")] + [TestCase (ApplePlatform.iOS, "ios-arm64", "")] + [TestCase (ApplePlatform.TVOS, "tvossimulator-arm64", ":v2:runtime=com.apple.CoreSimulator.SimRuntime.tvOS-16-4,devicetype=com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-3rd-generation-1080p")] + public void GetMlaunchRunArguments (ApplePlatform platform, string runtimeIdentifiers, string device) + { + var project = "MySimpleApp"; + Configuration.IgnoreIfIgnoredPlatform (platform); + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + + var outputPath = Path.Combine (Cache.CreateTemporaryDirectory (), "launch.sh"); + var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath); + var properties = GetDefaultProperties (runtimeIdentifiers); + properties ["EnableCodeSigning"] = "false"; // Skip code signing, since that would require making sure we have code signing configured on bots. + + // Create the app manifest first, since it's required to compute the mlaunch run arguments + DotNet.Execute ("build", project_path, properties, target: "_DetectSdkLocations;_DetectAppManifest;_CompileAppManifest;_WriteAppManifest"); + + properties ["MlaunchRunScript"] = outputPath; + var rv = DotNet.Execute ("build", project_path, properties, target: "ComputeMlaunchRunArguments"); + + if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchRunArguments", out var mlaunchRunArguments)) + Assert.Fail ("Could not find the property 'MlaunchRunArguments' in the binlog."); + + if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchPath", out var mlaunchPath)) + Assert.Fail ("Could not find the property 'MlaunchPath' in the binlog."); + Assert.That (mlaunchPath, Does.Exist, "mlaunch existence"); + + var expectedArguments = new StringBuilder (); + var isSim = runtimeIdentifiers.Contains ("simulator"); + expectedArguments.Append (isSim ? "--launchsim " : "--launchdev "); + expectedArguments.Append (appPath.Substring (Path.GetDirectoryName (project_path)!.Length + 1)).Append ('/'); + if (isSim) { + expectedArguments.Append (" --device \""); + expectedArguments.Append (device); + expectedArguments.Append ('"'); + } + expectedArguments.Append ($" --wait-for-exit:true"); + Assert.AreEqual (expectedArguments.ToString (), mlaunchRunArguments); + + var scriptContents = File.ReadAllText (outputPath).Trim ('\n');; + var expectedScriptContents = mlaunchPath + " " + expectedArguments.ToString (); + Assert.AreEqual (expectedScriptContents, scriptContents, "Script contents"); + } + } +} From 2761123a6bf6dd8eed5dd91ac85f969711f38114 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 15 Jun 2023 09:54:22 +0200 Subject: [PATCH 2/8] [dotnet] Add a property to opt-out of the _CopyLocalBindingResources logic easily. (#18443) It seems this target has more problems than at first I thought, so make it easier to opt-out of it by just setting a property in the csproj. More investigation is needed, but I'm keeping the target on by default for now, since it solves a real-world problem as well. Ref: https://github.com/xamarin/xamarin-macios/issues/18445 --- dotnet/targets/Xamarin.Shared.Sdk.targets | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 787f33f32870..b7440a1942b0 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -1898,7 +1898,11 @@ global using nfloat = global::System.Runtime.InteropServices.NFloat%3B - +