Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build for .NET 4 and .NET 4.5 - what about referenced NuGet packages?

Tags:

nuget

msbuild

I've got a script that build a project, outputting .NET 4.0 assemblies.

The project includes NLog from NuGet. So the reference in the project file looks like this:

<Reference Include="NLog">
  <HintPath>..\packages\NLog.2.0.1.2\lib\NLog\net40\NLog.dll</HintPath>
</Reference>

And my packages.config looks like this:

<packages>
  <package id="NLog" version="2.0.1.2" targetFramework="net40" />
</packages>

This project is going to be published on NuGet, and now I want to update the build script so it also builds .NET 4.5 assemblies.

Now, I know I can pass /p:TargetFrameworkVersion="4.5" to msbuild and have it target .NET 4.5 - but that is still going to build againt the .NET 4.0 NLog assembly.

How can I have it build using the correct version of NuGet dependencies for the framework being targetted?

like image 640
Cocowalla Avatar asked Nov 12 '22 00:11

Cocowalla


1 Answers

Had the exact same requirement here a while ago and found no 'pure' NuGet solution. And I doubt there is. The only option seemed to be maintaining different project files (or parts of it) - definitely a no-go for massive code bases.

What I did instead was just target 4.5 in all projects, and have a rather simple msbuild script that creates copies of the projects and all their NuGet config for targetting other versions of .Net. Basically it just enumerates all .csproj files, does a find/replace from net45 -> net40 strings and saves them under a different name. Idem for the package config/targets/solution files.

Here's pretty much the complete MSBuild target:

<Target Name="MakeNet40Projects">
  <ItemGroup>
    <SourceProjs Include="$(MyProjectDir)*\*\*.csproj" Exclude="$(MyProjectDir)\*\*\*.Net40.csproj"/>
      ...
    <SourceConfigs Include="$(MyProjectDir)*\*\packages.config"/>
      ...
    <DestProjs Include="%(SourceProjs.RootDir)%(SourceProjs.Directory)%(SourceProjs.FileName).Net40.csproj"/>
    <DestConfigs Include="%(SourceConfigs.RootDir)%(SourceConfigs.Directory)%(SourceConfigs.FileName).Net40.config"/>
  </ItemGroup>
  <PropertyGroup>
    <OldPackages>packages.config</OldPackages>
    <NewPackages>packages.Net40.config</NewPackages>
    <OldTargets>NuGet.targets</OldTargets>
    <NewTargets>NuGet.Net40.targets</NewTargets>
    <OldProj>\.csproj</OldProj>
    <NewProj>.Net40.csproj</NewProj>
  </PropertyGroup>

  <Copy SourceFiles="@(SourceProjs)" DestinationFiles="@(DestProjs)"/>
  <FileUpdate Files="@(DestProjs)" Regex="[Nn][Ee][Tt]45" ReplacementText="net40" Encoding="utf-8"/>
  <FileUpdate Files="@(DestProjs)" Regex="$(OldPackages)" ReplacementText="$(NewPackages)" Encoding="utf-8"/>
  <FileUpdate Files="@(DestProjs)" Regex="$(OldTargets)" ReplacementText="$(NewTargets)" Encoding="utf-8"/>
  <FileUpdate Files="@(DestProjs)" Regex="$(OldProj)" ReplacementText="$(NewProj)" Encoding="utf-8"/>

  <Copy SourceFiles="@(SourceConfigs)" DestinationFiles="@(DestConfigs)"/>
  <FileUpdate Files="@(DestConfigs)" Regex="[Nn][Ee][Tt]45" ReplacementText="net40" Encoding="utf-8"/>

  <Copy SourceFiles="$(MsBuildThisFileDirectory)\.nuget\$(OldTargets)" DestinationFiles="$(MsBuildThisFileDirectory)\.nuget\$(NewTargets)"/>
  <FileUpdate Files="$(MsBuildThisFileDirectory)\.nuget\$(NewTargets)" Regex="$(OldPackages)" ReplacementText="$(NewPackages)" Encoding="utf-8"/>

  <Copy SourceFiles="$(MsBuildThisFileDirectory)\my.sln" DestinationFiles="$(MsBuildThisFileDirectory)\my.Net40.sln"/>
  <FileUpdate Files="$(MsBuildThisFileDirectory)\my.Net40.sln" Regex="$(OldProj)" ReplacementText="$(NewProj)" Encoding="utf-8"/>
  <FileUpdate Files="$(MsBuildThisFileDirectory)\my.Net40.sln" Regex="NuGet\.targets" ReplacementText="$(NewTargets)" Encoding="utf-8"/>
</Target>

After running this there's a .Net40.csproj for each project, a .Net40.sln, a Nuget.Net40.targets for the solution and packages.Net40.config files, all ready to be built. So far, so good.

Small problem though: packages.config is hardcoded as a string in Nuget.exe so it won't accept packages.net40.config on it's command line. It's part of it's 'algorithm' to decide whether or not the path passed to the -install algorithm is an actual package config, or a package Id. Lol. I raised a question on this but no answer. Anyway I wasn't planning to let this spoil the fun so I made a single-line adjustment in the source to have it accept anything that ends with .config, built it and use that Nuget.exe now.

like image 119
stijn Avatar answered Nov 14 '22 22:11

stijn