0

Is it possible to use a newer dotnet SDK building C++/CLI vcxproj than their target framework?

We have a large solution containing C#, C++ and a handful of C++/CLI projects. The target framework is set to .NET 6 (latest LTS and all that). At the same time I'd like to use C# 11 and which requires the use of a .NET 7 sdk when building.

For normal C# projects I can simply use a global.json to specify .NET 7 (when using a new enough VS) while keeping TargetFramework=6.0.

When doing the same with C++/CLI projects I get a NETSDK1145 error:

Error NETSDK1145 The Apphost pack is not installed and NuGet package restore is not supported. Upgrade Visual Studio, remove global.json if it specifies a certain SDK version, and uninstall the newer SDK. For more options visit https://aka.ms/targeting-apphost-pack-missing Pack Type:Apphost, Pack directory: C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64, targetframework: net6.0, Pack PackageId: Microsoft.NETCore.App.Host.win-x64, Pack Package Version: 6.0.16 C:\Program Files\dotnet\sdk\7.0.203\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets 135

The link says something about setting

<ItemGroup>
  <KnownAppHostPack Update="@(KnownAppHostPack)">
    <AppHostPackVersion Condition="'%(TargetFramework)' == 'TARGETFRAMEWORK'">EXISTINGVERSION</AppHostPackVersion>
  </KnownAppHostPack>
</ItemGroup>

but does not say anything about possible problems or the consequences of doing so. I'm also not sure how I'd do that if people might have different .NET 7 SDKs installed (I don't want to force a single SDK).

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Voo
  • 29,040
  • 11
  • 82
  • 156

2 Answers2

1

Im probably going to be the bearer of bad news here.

My understanding of it is that probably wont work for you. If you field it out correctly I think it would look like this

  <ItemGroup>
    <KnownAppHostPack Update="@(KnownAppHostPack)">
      <AppHostPackVersion Condition="'%(TargetFramework)' == 'net6.0'">EXISTINGVERSION</AppHostPackVersion>
    </KnownAppHostPack>
  </ItemGroup>

As your telling Apphost what specific version to use. If done correctly this would potentially solve the NETSDK1145 error; however, it would only solve that error, it wouldnt update it for the whole project which would likely be full of issues.

Your likely just going to be hopping from one bug to another even if that works

It will probably just be quicker to update your project. Visual studios supports Net7 targets now

https://developercommunity.visualstudio.com/t/Add-NET70-target-for-CCLI-Projects/10232939

Lucas Hendren
  • 2,786
  • 2
  • 18
  • 33
  • What do you mean with "wouldnt update it for the whole project"? As I understand it, the AppHost packs are just the libs required to link against the runtime. What problems would be expected to crop up, given that the ABI is stable? Using a non-lts runtime is really out of the question given the maintenance timelines we're dealing with, it's not a question of what would be quicker. – Voo Jul 21 '23 at 14:18
  • It was my understanding that apphost would just affect the individual libraries, leading you with potential other issues, but im having issues finding the resource I used(documenation hasnt been great, found a blog with a user explaining it but cant find it, still looking). You can try it, if the ABI is stable, maybe it will work then, that fix above should handle that error. Also sharing another link im looking at, shows how to specify specific library/package versions for specific version https://stackoverflow.com/questions/58192348/multi-targeting-net-core-2-2-with-net-4-6-1 – Lucas Hendren Jul 23 '23 at 08:46
  • 1
    Well the interesting part is the "EXISTINGVERSION" which wasn't replaced ;-) But I wrote some inline code factory to find the latest dotnet runtime that fits with the target framework. Now just need to wait and see if there's any unexpected problems. The link isn't really relevant here, since I don't even multi target the project. – Voo Jul 23 '23 at 17:43
  • I was thinking the way they use ItemGroups to set packages could be useful, sorry if this doesnt apply. Please update if this works, not alot of documentation on this, fingers crossed – Lucas Hendren Jul 24 '23 at 06:40
0

So far just setting the app host package to a .NET 6 variant while building using .NET 7 seems to be working just fine.

To make this streamlined to use, I wrote a simple inline roslyn code factory that finds the newest app host package for the required target framework (nb the hardcoded runtime identifier - you'll have to see what msbuild identifier exists for a general solution).

On the build system the used .NET SDK and its runtime version are hardcoded for reproducability

<UsingTask TaskName="GetAppHostVersionTask"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
        <NetCoreTargetingPackRoot ParameterType="System.String" Required="true" />
        <KnownAppHostPack ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
        <RuntimeIdentifiers ParameterType="System.String" Required="true" />
        <TargetFramework ParameterType="System.String" Required="true" />
        <HighestSupportedVersion ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
        <Code Type="Fragment" Language="cs">
<![CDATA[
#pragma warning disable CS0162 // False positive warning
var runtimeName = this.KnownAppHostPack[0].ItemSpec;
var packDirectory = Path.Combine(this.NetCoreTargetingPackRoot, $"{runtimeName}.Host.{this.RuntimeIdentifiers}");
var supportedVersion = this.TargetFramework.Substring("net".Length);
var versionToUse = Directory.EnumerateDirectories(packDirectory)
      .Select(Path.GetFileName)
      .Where(dirName => dirName.StartsWith(supportedVersion, StringComparison.OrdinalIgnoreCase))
      .OrderByDescending(Version.Parse)
      .FirstOrDefault();
if (versionToUse is null)
{
 this.Log.LogError($"'{packDirectory}' does not contain any pack runtime for target framework {this.TargetFramework}.");
 return false;
}
this.Log.LogMessage(MessageImportance.High, $"AppHostPackVersion set to {versionToUse}");
this.HighestSupportedVersion = versionToUse;
return true;
]]>
</Code>
    </Task>
</UsingTask>

<Target Name="SetAppHostPackVersion" BeforeTargets="ProcessFrameworkReferences">
    <GetAppHostVersionTask
        NetCoreTargetingPackRoot="$(NetCoreTargetingPackRoot)"
        KnownAppHostPack="@(KnownAppHostPack)"
        RuntimeIdentifiers="win-$(Platform)"
        TargetFramework="$(TargetFramework)"
        Condition=" '$(MyAppHostPackVersion)' == '' ">
        <Output TaskParameter="HighestSupportedVersion" PropertyName="MyAppHostPackVersion" />
    </GetAppHostVersionTask>
    <ItemGroup>
        <KnownAppHostPack Update="@(KnownAppHostPack)">
            <AppHostPackVersion>$(MyAppHostPackVersion)</AppHostPackVersion>
        </KnownAppHostPack>
        <KnownFrameworkReference Update="@(KnownFrameworkReference)">
            <TargetingPackVersion>$(MyAppHostPackVersion)</TargetingPackVersion>
        </KnownFrameworkReference>
    </ItemGroup>
</Target>

I'll report back if there's any bug reports that can be traced back to this, but so far it looks good. Seems like the ABI is stable across versions.

Voo
  • 29,040
  • 11
  • 82
  • 156