C
C#2y ago
sasik

✅ Creating a cross-platform csproj supporting any .NET and any platform -linux,osx,amd64,arm64

Hello, I have a project that I would like to be able to run on any machine, from linux/amd64 with mono installed to (dated) linux/amd64 with dotnet 5 to osx/amd64 and osx/arm64 with the latest dotnet 7. To be more specific, what I would like to achieve: - when I type dotnet build/test/run, I would like to run it using the current platform and any available framework (I can safely assume there is just one) - when I type dotnet publish it is published as a self-contained application My current csproj (excerpt)
<PropertyGroup>
<TargetFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">net5</TargetFramework>
<TargetFramework Condition="'$(MSBuildRuntimeType)' != 'Core'">net461</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<RollForward>Major</RollForward>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<IsPublishable>false</IsPublishable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">net5</TargetFramework>
<TargetFramework Condition="'$(MSBuildRuntimeType)' != 'Core'">net461</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<RollForward>Major</RollForward>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<IsPublishable>false</IsPublishable>
</PropertyGroup>
And if the csproj is publishable, then I add also this:
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseApp' ">
<IsPublishable>true</IsPublishable>
<SelfContained>true</SelfContained>
<!-- PublishSingleFile messes app.config and adds no real benefit -->
<PublishSingleFile>false</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseApp' ">
<IsPublishable>true</IsPublishable>
<SelfContained>true</SelfContained>
<!-- PublishSingleFile messes app.config and adds no real benefit -->
<PublishSingleFile>false</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
Issues: - this lets me only handle .NET 4.6.1 (which I use via mono), .NET 5 and .NET 6. It won't work on .NET 7 strange thing here: <RollForward> (I've played with Major, LatestMajor) works if .NET 6 is installed but it doesn't work when .NET 7 is the only available runtime . Does it mean, that RollForward is only able to bump the major version by 1? - it doesn't work on osx. I have to manually change the <RuntimeIdentifier> - differently for osx/arm64 and for osx/amd64 How to do this well?
4 Replies
Angius
Angius2y ago
Why not just create a self-contained build that bundles the framework with it? Or do you also want to be able to develop it wherever? Because that sounds like a major PITA with no upsides
sasik
sasik2y ago
short answer is yes, I want to be able to develop it wherever for production use, I do build a self-contained app, currently using net5 (I do want to update it but I also want to do it gradually and carefully due to possible performance drops which I already encountered multiple times in the past) and btw. I've found out a really simple solution:
<PropertyGroup>
<FrameworkDescription>$([System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription.ToLower())</FrameworkDescription>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 7'))">net7</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 6'))">net6</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 5'))">net5</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('mono'))">net461</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<FrameworkDescription>$([System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription.ToLower())</FrameworkDescription>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 7'))">net7</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 6'))">net6</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('net 5'))">net5</TargetFramework>
<TargetFramework Condition="$(FrameworkDescription.Contains('mono'))">net461</TargetFramework>
</PropertyGroup>
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
sasik
sasik2y ago
Closing the issue although if anyone, ever, even in 10 years, will come across a better solution, please, let me know