Search code examples
c#msbuild.net-4.0portable-class-library

Produce a .NET 4.0 library from a PCL Project where code is identical


It's quite frustrating, I have a Portable Class Library (PCL) library that had to drop .NET 4.0 in the profile to have access to the right API's "in PCL land". However, these API's do exist in .NET 4.0, such that if the exact same code is in a .NET 4.0 project it compiles just fine.

I want a minimal ongoing maintenance way to recompile the code in this PCL project to .net 4.0 so I can include it in a Nuget package.


Solution

  • With minimal conditional adjustments to the .csproj, an msbuild project can be created to compile a portable library solution to produce additional .net 4.0 profile binaries.

    Build.proj:

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <ItemGroup> 
            <ProjectToBuild Include="MyPortableSolution.sln">
                <Properties>Configuration=Release;</Properties>
            </ProjectToBuild>
            <ProjectToBuild Include="MyPortableSolution.sln">
                <Properties>Configuration=Release;OutputPath=bin\Release.net40\;IntermediateOutputPath=obj\Release.net40\;UseNet40=true;</Properties>
            </ProjectToBuild>
        </ItemGroup>
        <Target Name="Build">
            <MSBuild Projects="@(ProjectToBuild)"/>
        </Target>
    </Project>
    

    Make changes in two areas of MyPortableProj.csproj:

    First Replace:

    <TargetFrameworkProfile>Profile46</TargetFrameworkProfile>
    

    With:

    <UseNet40 Condition=" '$(UseNet40)' == '' ">false</UseNet40>
    <TargetFrameworkProfile Condition="$(UseNet40) == false">Profile46</TargetFrameworkProfile>
    

    Second Replace:

    <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
    

    With:

    <Import Condition="$(UseNet40) == true" Project="$(SolutionDir)\refs.targets" />
    <Import Condition="$(UseNet40) == true" Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    <Import Condition="$(UseNet40) == false" Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
    

    Include a refs.targets

    This is a file with the assembly references you need (edit from project to project):

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <ItemGroup>
        <Reference Include="mscorlib" />
        <Reference Include="Microsoft.CSharp" />
        <Reference Include="System" />
        <Reference Include="System.Core" />
      </ItemGroup>
    </Project>
    

    note: using a separate file because Visual studio parses and displays it otherwise.

    msbuild Build.proj

    This will create your portable lib in bin\Release and .net 40 specific lib in bin\Release.net40