Skip to content

Commit

Permalink
Mono workloads: Fix building non-mono project when `RunAOTCompilation…
Browse files Browse the repository at this point in the history
…=true` (#77762)

This manifested in a case where a non-mono project was passed a mono specific property `RunAOTCompilation=true`, but instead of it getting ignored, the build failed with:

```
/usr/local/share/dotnet/sdk/7.0.200-preview.22521.7/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5):

error NETSDK1147: To build this project, the following workloads must be installed: macos [/private/tmp/c/c.csproj]
error NETSDK1147: To install these workloads, run the following command: dotnet workload restore [/private/tmp/c/c.csproj]
```

And this is because the `MonoAOTCompiler.Task` is imported with:

https://github.com/dotnet/runtime/blob/82aa87f9cdf9ac20f0f685016648c36247a76ff1/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L57-L57

- This happens for net6, and net8 projects.

Fixes #77707 .

cc @steveisok @lewing
  • Loading branch information
radical authored Nov 3, 2022
1 parent 1f61914 commit 8e45d5f
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

<!-- TFM specific -->

<Import Condition="'$(TargetsCurrent)' == 'true' and '$(RunAOTCompilation)' == 'true' and '$(_BrowserWorkloadNotSupportedForTFM)' != 'true'" Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task" />
<Import Condition="'$(TargetsCurrent)' == 'true' and '$(RunAOTCompilation)' == 'true' and ('$(UsingBrowserRuntimeWorkload)' == 'true' or '$(UsingMobileWorkload)' == 'true')" Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task" />

<ImportGroup Condition="'$(TargetsCurrent)' == 'true' and '$(TargetPlatformIdentifier)' == 'android'">
<Import Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoTargets.Sdk" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->
<Project TreatAsLocalProperty="WasmNativeWorkload">
<Import Condition="'$(TargetsNet6)' == 'true' and '$(RunAOTCompilation)' == 'true' and '$(_BrowserWorkloadDisabled)' != 'true'" Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task.net6" />
<Import Condition="'$(TargetsNet6)' == 'true' and '$(RunAOTCompilation)' == 'true' and ('$(UsingBrowserRuntimeWorkload)' == 'true' or '$(UsingMobileWorkload)' == 'true')" Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task.net6" />

<ImportGroup Condition="'$(TargetsNet6)' == 'true' and '$(TargetPlatformIdentifier)' == 'android'">
<Import Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoTargets.Sdk.net6" />
Expand Down
3 changes: 3 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/HelperExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public static class HelperExtensions
=> data.SelectMany(row =>
rowsWithColumnArrays.Select(new_cols => row.Concat(new_cols)));

public static IEnumerable<IEnumerable<object?>> MultiplyWithSingleArgs(this IEnumerable<IEnumerable<object?>> data, params object?[] arrayOfArgs)
=> data.SelectMany(row => arrayOfArgs.Select(argCol => row.Concat(new[] { argCol })));

public static object?[] Enumerate(this RunHost host)
{
if (host == RunHost.None)
Expand Down
132 changes: 132 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;

#nullable enable

namespace Wasm.Build.Tests;

public class NonWasmTemplateBuildTests : BuildTestBase
{
public NonWasmTemplateBuildTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

// For building non-wasm project with the sdk installed, we need to
// patch the framework references. But we want to maintain the versions.
// So, copy the reference for latest TFM, and add that back with the
// TFM=DefaultTargetFramework
//
// This is useful for the case when we are on tfm=net7.0, but sdk, and packages
// are really 8.0 .
private const string s_latestTargetFramework = "net8.0";
private const string s_previousTargetFramework = "net7.0";
private static string s_directoryBuildTargetsForPreviousTFM =
$$"""
<Project>
<Target Name="_FixupVersions" BeforeTargets="ProcessFrameworkReferences">
<ItemGroup>
<!-- Get net8.0 entry -->
<_KnownFrameworkReferenceToCopyFrom
Include="@(KnownFrameworkReference)"
Condition="'%(Identity)' == 'Microsoft.NETCore.App' and '%(TargetFramework)' == '{{s_latestTargetFramework}}'" />
<!-- patch it's TFM=net7.0 -->
<_KnownFrameworkReferenceToCopyFrom Update="@(_KnownFrameworkReferenceToCopyFrom)" TargetFramework="{{DefaultTargetFramework}}" />
<!-- remove the existing net7.0 entry -->
<KnownFrameworkReference
Remove="@(KnownFrameworkReference)"
Condition="'%(Identity)' == 'Microsoft.NETCore.App' and '%(TargetFramework)' == '{{DefaultTargetFramework}}'" />
<!-- add the new patched up net7.0 entry -->
<KnownFrameworkReference Include="@(_KnownFrameworkReferenceToCopyFrom)" />
</ItemGroup>
</Target>
</Project>
""";

private static string s_directoryBuildTargetsForCurrentTFM = "<Project />";

public static IEnumerable<object?[]> GetTestData() =>
new IEnumerable<object?>[]
{
new object?[] { "Debug" },
new object?[] { "Release" }
}
.AsEnumerable()
.MultiplyWithSingleArgs
(
"",
"/p:RunAOTCompilation=true",
"/p:WasmBuildNative=true"
)
.MultiplyWithSingleArgs
(
"net6.0",
s_previousTargetFramework,
s_latestTargetFramework
)
.UnwrapItemsAsArrays().ToList();

[Theory, TestCategory("no-workload")]
[MemberData(nameof(GetTestData))]
public void NonWasmConsoleBuild_WithoutWorkload(string config, string extraBuildArgs, string targetFramework)
=> NonWasmConsoleBuild(config,
extraBuildArgs,
targetFramework,
// net6 is sdk would be needed to run the app
shouldRun: targetFramework != "net6.0");


[Theory]
[MemberData(nameof(GetTestData))]
public void NonWasmConsoleBuild_WithWorkload(string config, string extraBuildArgs, string targetFramework)
=> NonWasmConsoleBuild(config,
extraBuildArgs,
targetFramework,
// net6 is sdk would be needed to run the app
shouldRun: targetFramework != "net6.0");

private void NonWasmConsoleBuild(string config,
string extraBuildArgs,
string targetFramework,
string? directoryBuildTargets = null,
bool shouldRun = true)
{
string id = $"nonwasm_{targetFramework}_{config}_{Path.GetRandomFileName()}";
InitPaths(id);
InitProjectDir(_projectDir);

directoryBuildTargets ??= targetFramework == s_previousTargetFramework
? s_directoryBuildTargetsForPreviousTFM
: s_directoryBuildTargetsForCurrentTFM;

File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.props"), "<Project />");
File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.targets"), directoryBuildTargets);

new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false)
.WithWorkingDirectory(_projectDir!)
.ExecuteWithCapturedOutput("new console --no-restore")
.EnsureSuccessful();

new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false)
.WithWorkingDirectory(_projectDir!)
.ExecuteWithCapturedOutput($"build -restore -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {extraBuildArgs} -f {targetFramework}")
.EnsureSuccessful();

if (shouldRun)
{
var result = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false)
.WithWorkingDirectory(_projectDir!)
.ExecuteWithCapturedOutput($"run -c {config} -f {targetFramework} --no-build")
.EnsureSuccessful();

Assert.Contains("Hello, World!", result.Output);
}
}
}

0 comments on commit 8e45d5f

Please sign in to comment.