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

AnyCPU support #893

Open
dotMorten opened this issue May 31, 2021 · 16 comments
Open

AnyCPU support #893

dotMorten opened this issue May 31, 2021 · 16 comments
Assignees
Labels
area-Deployment Issues related to packaging, installation, runtime (e.g., SelfContained, Unpackaged) feature proposal servicing-consider
Milestone

Comments

@dotMorten
Copy link
Contributor

dotMorten commented May 31, 2021

Describe the bug
I'm trying to use MRTCore in a WPF application. I reference ProjectReunion package, and compile and I'm presented with this error:

1>C:\Users\mn.nuget\packages\microsoft.projectreunion.winui\0.8.0-preview\buildTransitive\Microsoft.WinUI.targets(15,5): error : This version of WinUI does not support AnyCPU. Either set Platform or PlatformTarget to one of the following: x86, x64, or arm64.

I'm in no way interested in using WinUI here, but the current nuget dependency forces me to get WinUI included, including all the types etc. IMHO this is backwards, and instead Microsoft.ProjectReunion.WinUI you be referencing Microsoft.ProjectReunion. The error above is extremely confusing as I am not interested in or explicitly referencing the WinUI extension.

Sure I can avoid using AnyCPU, but that's not so much the point (and I just followed the sample app config which has AnyCPU as well: https://github.com/microsoft/Project-Reunion-Samples/blob/main/MrtCore/winforms_unpackaged_app/winforms_unpackaged_app.csproj). Also why can't you do AnyCPU? Other .NET3+ apps can handle deploying multiple architecture runtimes in an AnyCPU app.

Steps to reproduce the bug
Create a WPF Application and add reunion:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>

    <TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
    <UseWPF>true</UseWPF>
    <Platforms>AnyCPU;x86;x64</Platforms>
    <RuntimeIdentifiers>win10-x86;win10-x64</RuntimeIdentifiers>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.ProjectReunion" Version="0.8.0-preview" />
  </ItemGroup>
</Project>

Compile for AnyCPU

I get the app packages the same runtime dependencies, but it creates confusing unrelated errors, and exposes a set of APIs that I never intended to reference. I'm only interested in MRTCore which is packaged with the "base" reunion package, yet I'm getting DWrite, InteractiveExperiences and WinUI throw in as well.

Expected behavior
WinUI, DWrite and InteractiveExperiences package is not included. Intellisense doesn't autocomplete those APIs either.

Version Info

NuGet package version: 0.8.0-preview

Windows 10 version Saw the problem?
Insider Build (xxxxx)
May 2020 Update (19041)
November 2019 Update (18363)
May 2019 Update (18362)
October 2018 Update (17763)

Additional context

@ghost ghost added the needs-triage label May 31, 2021
@riverar
Copy link
Contributor

riverar commented Jun 1, 2021

NuGet dependencies are including unrelated packages

You referenced the Project Reunion package which includes related packages:

<dependencies>
  <dependency id="Microsoft.ProjectReunion.Foundation" version="0.8.0-preview" />
  <dependency id="Microsoft.ProjectReunion.DWrite" version="0.8.0-preview" />
  <dependency id="Microsoft.ProjectReunion.WinUI" version="0.8.0-preview" />
  <dependency id="Microsoft.ProjectReunion.InteractiveExperiences" version="0.8.0-preview" />
</dependencies>

WinUI target throws error : This version of WinUI does not support AnyCPU. Either set Platform or PlatformTarget to one of the following: x86, x64, or arm64

Dynamic dependencies and other components do not support AnyCPU. Not sure why the sample ships with that though (bug?).

The error above is extremely confusing as I am not interested in or explicitly referencing the WinUI extension.

Well, you added that dependency (see above). But if you add the Foundation package by itself, the WinUI targets do still get evaluated, which I agree is very confusing.

@dotMorten
Copy link
Contributor Author

Dynamic dependencies and other components do not support AnyCPU. Not sure why the sample ships with that though (bug?).

.NET will deploy all the architecture runtimes when compiling for AnyCPU and dynamically load the correct one, so yes that should work just fine. That's why when you compile for AnyCPU you get a \runtimes\win10-[arch]\ for each supported architecture, but when compiling for a specific runtime identifier, that folder gets dropped and the dependencies gets placed in the root folder instead. Why should reunion work any different?

@riverar
Copy link
Contributor

riverar commented Jun 1, 2021

.NET will deploy all the architecture runtimes when compiling for AnyCPU and dynamically load the correct one, so yes that should work just fine. That's why when you compile for AnyCPU you get a \runtimes\win10-[arch]\ for each supported architecture, but when compiling for a specific runtime identifier, that folder gets dropped and the dependencies gets placed in the root folder instead. Why should reunion work any different?

Not sure what behavior you're referring to but compiling the WPF app here as AnyCPU will result in a single ILONLY image.

@dotMorten
Copy link
Contributor Author

dotMorten commented Jun 1, 2021

When you build for any cpu in a .NET 3.1+ project, if a nuget dependency includes runtimes for several different architectures (and/or platforms) they are deployed to a subfolder for each, and .NET automatically knows where to find them based on current platform and architecture at runtime. For instance your output folder might have this:

image

Sure when you go to publish, you pick a specific architecture, but a standard new .NET Core project defaults to AnyCPU when you hit F5 after creating it - so this is just as much about simplifying the developer experience.

@andrewleader andrewleader changed the title NuGet dependencies are including unrelated packages. AnyCPU support Jun 2, 2021
@andrewleader
Copy link
Contributor

Thanks for pointing this out Morten, @AdamBraden is investigating the AnyCPU topic.

@andrewleader andrewleader added feature proposal area-Deployment Issues related to packaging, installation, runtime (e.g., SelfContained, Unpackaged) and removed needs-triage labels Jun 2, 2021
@AdamBraden
Copy link

Yes we need to fix the nuget packages to correctly place the native dependencies of our components.

Build/F5 of AnyCPU results in a lot of binaries being deployed, but apparently that's the way it is for .NET.

@asklar
Copy link
Member

asklar commented Jun 23, 2021

Duplicate of #922 ?

@mattleibow
Copy link

FYI: When using an Any CPU app head, then I still have to add this.

<Target Name="BinPlaceBootstrapDll" />

@DrusTheAxe
Copy link
Member

Dupe of #1217 ?

@dotMorten
Copy link
Contributor Author

dotMorten commented Aug 20, 2021

@DrusTheAxe No this is different. The other one is about being able to build architecture agnostic class libs and is a regression that holds up control libraries like ours and the toolkit. This one is about following the pattern of the other .net libs where when building for anycpu, all runtimes are deployed and at runtime the right native libs are loaded and will run. That creates a much better and simpler first run experience for .net developers (typically picking platform and architecture doesn't come into play until publish time).

@mattleibow
Copy link

Just adding some of the things that I found and am working around in maui. The Windows App SDK does already support AnyCPU since this is the default mode for .NET "Core", however there are targets that do not allow it and artificially restrict it.

There is a target WindowsAppSDKSelfContainedVerifyConfiguration that just throws an error. I work around this in my targets by replacing it with a dummy target:

<Target Name="WindowsAppSDKSelfContainedVerifyConfiguration">
</Target>

There is a GetExtractMicrosoftWindowsAppSDKMsixFilesInputs target that is supposed to extract things, but this fails if the Platform is not set. I work around this by injecting a target that runs right after it to replace the values of NativePlatform:

<Target Name="_MAUIAfter_GetExtractMicrosoftWindowsAppSDKMsixFilesInputs"
        AfterTargets="GetExtractMicrosoftWindowsAppSDKMsixFilesInputs"
        Condition="'$(NativePlatform)' == 'AnyCPU'">
  <PropertyGroup>
    <NativePlatform>Invalid</NativePlatform>
    <NativePlatform Condition="'$(Platform)' == 'x86'">x86</NativePlatform>
    <NativePlatform Condition="'$(Platform)' == 'Win32'">x86</NativePlatform>
    <NativePlatform Condition="'$(Platform)' == 'x64'">x64</NativePlatform>
    <NativePlatform Condition="'$(Platform)' == 'arm'">arm</NativePlatform>
    <NativePlatform Condition="'$(Platform)' == 'arm64'">arm64</NativePlatform>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Platform)' == 'AnyCPU' or '$(Platform)' == 'Any CPU'">
    <NativePlatform>neutral</NativePlatform>
    <NativePlatform Condition="'$(RuntimeIdentifier)' == 'win10-x86' or '$(RuntimeIdentifier)' == 'win-x86'">x86</NativePlatform>
    <NativePlatform Condition="'$(RuntimeIdentifier)' == 'win10-x64' or '$(RuntimeIdentifier)' == 'win-x64'">x64</NativePlatform>
    <NativePlatform Condition="'$(RuntimeIdentifier)' == 'win10-arm' or '$(RuntimeIdentifier)' == 'win-arm'">arm</NativePlatform>
    <NativePlatform Condition="'$(RuntimeIdentifier)' == 'win10-arm64' or '$(RuntimeIdentifier)' == 'win-arm64'">arm64</NativePlatform>
  </PropertyGroup>
  <ItemGroup>
    <MicrosoftWindowsAppSDKMsix Include="$([MSBuild]::NormalizeDirectory('$(MicrosoftWindowsAppSDKPackageDir)','tools\Msix\win10-$(NativePlatform)'))Microsoft.WindowsAppRuntime.?.?.Msix"/>
    <MicrosoftWindowsAppSDKMsix Include="$([MSBuild]::NormalizeDirectory('$(MicrosoftWindowsAppSDKPackageDir)','tools\Msix\win10-$(NativePlatform)'))Microsoft.WindowsAppRuntime.?.?-*.Msix"/>
  </ItemGroup>
</Target>

There is also a _GetProjectArchitecture that almost works with Any CPU, except that since .NET added/removed the support for the full RID graph, the conditions are no longer correct. I have also created a replacement target that will fix the values:

<Target Name="_GetProjectArchitecture" Returns="@(ProjectArchitecture)">
  <PropertyGroup>
    <_ProjectArchitectureOutput>Invalid</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(Platform)' == 'x86'">x86</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(Platform)' == 'Win32'">x86</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(Platform)' == 'x64'">x64</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(Platform)' == 'arm'">arm</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(Platform)' == 'arm64'">arm64</_ProjectArchitectureOutput>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Platform)' == 'AnyCPU' or '$(Platform)' == 'Any CPU'">
    <_ProjectArchitectureOutput>neutral</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(RuntimeIdentifier)' == 'win10-x86' or '$(RuntimeIdentifier)' == 'win-x86'">x86</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(RuntimeIdentifier)' == 'win10-x64' or '$(RuntimeIdentifier)' == 'win-x64'">x64</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(RuntimeIdentifier)' == 'win10-arm' or '$(RuntimeIdentifier)' == 'win-arm'">arm</_ProjectArchitectureOutput>
    <_ProjectArchitectureOutput Condition="'$(RuntimeIdentifier)' == 'win10-arm64' or '$(RuntimeIdentifier)' == 'win-arm64'">arm64</_ProjectArchitectureOutput>
  </PropertyGroup>
  <Error Condition="'$(UseAppHost)' == 'true' and '$(_ProjectArchitectureOutput)' == 'neutral' and '$(AllowNeutralPackageWithAppHost)' != 'true'"
    Text="Packaged .NET applications with an app host exe cannot be ProcessorArchitecture neutral. Please specify a RuntimeIdentifier or a Platform other than AnyCPU." />
  <ItemGroup>
    <ProjectArchitecture Include="$(_ProjectArchitectureOutput)" />
  </ItemGroup>
</Target>

@mattleibow
Copy link

This is maybe the same/similar issue to #2684

@mattleibow
Copy link

@Scottj1s FYI

@Scottj1s
Copy link
Member

@mattleibow thanks for reporting. The _GetProjectArchitecture target is fixed in WinAppSDK 1.6, available very soon. I'm really not sure why the WindowsAppSDKSelfContainedVerifyConfiguration target was added, given the more fine-grained check in _GetProjectArchitecture (which prevents packaging for Any CPU, not merely building it). I'll see if there's any resistance to just removing it. Your mods to GetExtractMicrosoftWindowsAppSDKMsixFilesInputs are appreciated - will include these.

@lhak
Copy link

lhak commented Jun 26, 2024

At least in the 1.6-experimental1 release, the _GetProjectArchitecture target still does not support the new runtime identifiers.

@Scottj1s
Copy link
Member

Scottj1s commented Jul 3, 2024

At least in the 1.6-experimental1 release, the _GetProjectArchitecture target still does not support the new runtime identifiers.

1.6 Experimental 2 includes the changes suggested by @mattleibow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Deployment Issues related to packaging, installation, runtime (e.g., SelfContained, Unpackaged) feature proposal servicing-consider
Projects
None yet
Development

No branches or pull requests