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).
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.