Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] Add targets to compute mlaunch arguments for installing and launching mobile apps. Fixes #18359. #18446

Merged
merged 1 commit into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<_DotNetRootRemoteDirectory Condition="$(_DotNetRootRemoteDirectory) == ''">/usr/local/share/dotnet/</_DotNetRootRemoteDirectory>
<_XamarinSdkRootDirectoryOnMac Condition="'$(_XamarinSdkRootDirectory)' != ''">$(_XamarinSdkRootDirectory.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootDirectoryOnMac>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch</_MlaunchPath>
<MlaunchPath Condition="'$(MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch</MlaunchPath>
<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)..\targets\Microsoft.iOS.Windows.Sdk.targets</AfterMicrosoftNETSdkTargets>

<_XamarinSdkRootOnMac Condition="'$(_XamarinSdkRoot)' != ''">$(_XamarinSdkRoot.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootOnMac>
Expand Down
50 changes: 39 additions & 11 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1723,34 +1723,51 @@
<!-- Install & Run -->

<PropertyGroup>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectory)tools\bin\mlaunch</_MlaunchPath>
<!-- We used to use '_MlaunchPath' as the property name, but we've made it public, so it's MlaunchPath now, but keep setting/supporting the underscored version for a while -->
<MlaunchPath Condition="'$(MlaunchPath)' == '' And '$(_MlaunchPath)' != ''">$(_MlaunchPath)</MlaunchPath>
<MlaunchPath Condition="'$(MlaunchPath)' == ''">$(_XamarinSdkRootDirectory)tools\bin\mlaunch</MlaunchPath>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(MlaunchPath)</_MlaunchPath>
</PropertyGroup>

<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName" Condition="'$(_SdkIsSimulator)' == 'false'">
<Target Name="ComputeMlaunchInstallArguments" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;_DetectAppManifest;_ComputeMlaunchInstallArguments" />
<Target Name="_ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
<!-- Launching from the command line on windows hasn't been implemented: https://github.com/xamarin/xamarin-macios/issues/16609 -->
<Error Condition="$([MSBuild]::IsOSPlatform('windows'))" Text="It's currently not supported to launch an app from the command line on Windows." />
<Error Condition="!Exists('$(_AppBundleManifestPath)')" Text="The app must be built before the arguments to launch the app using mlaunch can be computed." />

<GetMlaunchArguments
SessionId="$(BuildSessionId)"
AppBundlePath="$(_AppBundlePath)"
AppManifestPath="$(_AppBundleManifestPath)"
DeviceName="$(_DeviceName)"
InstallApp="$(_AppBundlePath)"
MlaunchPath="$(_MlaunchPath)"
MlaunchPath="$(MlaunchPath)"
SdkDevPath="$(_SdkDevPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkVersion="$(_SdkVersion)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
>
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchInstallArguments" />
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchInstallArguments" />
</GetMlaunchArguments>

<Exec SessionId="$(BuildSessionId)" Command="$(_MlaunchPath) $(_MlaunchInstallArguments)" />
<WriteLinesToFile
File="$(MlaunchInstallScript)"
Lines="$(MlaunchPath) $(MlaunchInstallArguments)"
Overwrite="true"
WriteOnlyWhenDifferent="true"
Condition="'$(MlaunchInstallScript)' != ''"
/>
</Target>

<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
<Exec SessionId="$(BuildSessionId)" Command="$(MlaunchPath) $(MlaunchInstallArguments)" />
</Target>

<!-- This is only needed for mobile platforms, RunCommand and RunArguments are defined for macOS in Microsoft.macOS.Sdk.targets. -->
<Target Name="_PrepareRunMobile" DependsOnTargets="_InstallMobile" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<Target Name="ComputeMlaunchRunArguments" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;_DetectAppManifest" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<!-- Launching from the command line on windows hasn't been implemented: https://github.com/xamarin/xamarin-macios/issues/16609 -->
<Error Condition="$([MSBuild]::IsOSPlatform('windows'))" Text="It's currently not supported to launch an app from the command line on Windows." />
<Error Condition="!Exists('$(_AppBundleManifestPath)')" Text="The app must be built before the arguments to launch the app using mlaunch can be computed." />

<PropertyGroup>
<!-- capture output by default -->
<_MlaunchCaptureOutput Condition="'$(_MlaunchCaptureOutput)' == ''">true</_MlaunchCaptureOutput>
Expand All @@ -1775,7 +1792,7 @@
DeviceName="$(_DeviceName)"
EnvironmentVariables="@(MlaunchEnvironmentVariables)"
LaunchApp="$(_AppBundlePath)"
MlaunchPath="$(_MlaunchPath)"
MlaunchPath="$(MlaunchPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkDevPath="$(_SdkDevPath)"
SdkVersion="$(_SdkVersion)"
Expand All @@ -1784,12 +1801,23 @@
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
WaitForExit="$(_MlaunchWaitForExit)"
>
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchRunArguments" />
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchRunArguments" />
</GetMlaunchArguments>

<WriteLinesToFile
File="$(MlaunchRunScript)"
Lines="$(MlaunchPath) $(MlaunchRunArguments)"
Overwrite="true"
WriteOnlyWhenDifferent="true"
Condition="'$(MlaunchRunScript)' != ''"
/>
</Target>

<!-- This is only needed for mobile platforms, RunCommand and RunArguments are defined for macOS in Microsoft.macOS.Sdk.targets. -->
<Target Name="_PrepareRunMobile" DependsOnTargets="_InstallMobile;ComputeMlaunchRunArguments" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<PropertyGroup>
<RunCommand>$(_MlaunchPath)</RunCommand>
<RunArguments>$(_MlaunchRunArguments)</RunArguments>
<RunCommand>$(MlaunchPath)</RunCommand>
<RunArguments>$(MlaunchRunArguments)</RunArguments>
</PropertyGroup>
</Target>

Expand Down
11 changes: 11 additions & 0 deletions tests/common/BinLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,17 @@ public static bool TryFindPropertyValue (string binlog, string property, [NotNul
var dict = pefea.Properties as IDictionary<string, string>;
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;
}
}
}
}

Expand Down
97 changes: 97 additions & 0 deletions tests/dotnet/UnitTests/MlaunchTest.cs
Original file line number Diff line number Diff line change
@@ -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");
}
}
}
Loading